@signe/room 2.9.0 → 2.9.3

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.js CHANGED
@@ -1,5 +1,13 @@
1
1
  var __defProp = Object.defineProperty;
2
- var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __decorateClass = (decorators, target, key, kind) => {
4
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
5
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
6
+ if (decorator = decorators[i])
7
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
8
+ if (kind && result) __defProp(target, key, result);
9
+ return result;
10
+ };
3
11
 
4
12
  // src/decorators.ts
5
13
  function Action(name, bodyValidation) {
@@ -13,7 +21,6 @@ function Action(name, bodyValidation) {
13
21
  });
14
22
  };
15
23
  }
16
- __name(Action, "Action");
17
24
  function UnhandledAction() {
18
25
  return function(target, propertyKey) {
19
26
  target.constructor._unhandledActionMetadata = {
@@ -21,7 +28,6 @@ function UnhandledAction() {
21
28
  };
22
29
  };
23
30
  }
24
- __name(UnhandledAction, "UnhandledAction");
25
31
  function Request2(options, bodyValidation) {
26
32
  return function(target, propertyKey) {
27
33
  if (!target.constructor._requestMetadata) {
@@ -38,7 +44,6 @@ function Request2(options, bodyValidation) {
38
44
  });
39
45
  };
40
46
  }
41
- __name(Request2, "Request");
42
47
  function Room(options) {
43
48
  return function(target) {
44
49
  target.path = options.path;
@@ -51,46 +56,40 @@ function Room(options) {
51
56
  }
52
57
  };
53
58
  }
54
- __name(Room, "Room");
55
59
  function RoomGuard(guards) {
56
60
  return function(target) {
57
61
  target["_roomGuards"] = guards;
58
62
  };
59
63
  }
60
- __name(RoomGuard, "RoomGuard");
61
64
  function Guard(guards) {
62
65
  return function(target, propertyKey, descriptor) {
63
66
  if (!target.constructor["_actionGuards"]) {
64
67
  target.constructor["_actionGuards"] = /* @__PURE__ */ new Map();
65
68
  }
66
69
  if (!Array.isArray(guards)) {
67
- guards = [
68
- guards
69
- ];
70
+ guards = [guards];
70
71
  }
71
72
  target.constructor["_actionGuards"].set(propertyKey, guards);
72
73
  };
73
74
  }
74
- __name(Guard, "Guard");
75
75
 
76
76
  // ../sync/src/utils.ts
77
77
  function generateShortUUID() {
78
78
  const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
79
+ const randomBytes = typeof globalThis.crypto?.getRandomValues === "function" ? globalThis.crypto.getRandomValues(new Uint8Array(8)) : null;
79
80
  let uuid = "";
80
81
  for (let i = 0; i < 8; i++) {
81
- const randomIndex = Math.floor(Math.random() * chars.length);
82
- uuid += chars[randomIndex];
82
+ const randomValue = randomBytes?.[i] ?? Math.floor(Math.random() * 256);
83
+ uuid += chars[randomValue % chars.length];
83
84
  }
84
85
  return uuid;
85
86
  }
86
- __name(generateShortUUID, "generateShortUUID");
87
87
 
88
88
  // src/storage.ts
89
89
  var Storage = class {
90
- static {
91
- __name(this, "Storage");
90
+ constructor() {
91
+ this.memory = /* @__PURE__ */ new Map();
92
92
  }
93
- memory = /* @__PURE__ */ new Map();
94
93
  async put(key, value) {
95
94
  this.memory.set(key, value);
96
95
  }
@@ -108,22 +107,27 @@ var Storage = class {
108
107
  // src/server.ts
109
108
  import { dset as dset2 } from "dset";
110
109
  import z from "zod";
111
- import { createStatesSnapshot, getByPath, load, syncClass, DELETE_TOKEN, generateShortUUID as generateShortUUID2, createStatesSnapshotDeep } from "@signe/sync";
110
+ import {
111
+ createStatesSnapshot,
112
+ getByPath,
113
+ load,
114
+ syncClass,
115
+ DELETE_TOKEN,
116
+ generateShortUUID as generateShortUUID2,
117
+ createStatesSnapshotDeep
118
+ } from "@signe/sync";
112
119
 
113
120
  // src/utils.ts
114
121
  import { dset } from "dset";
115
122
  function isPromise(value) {
116
123
  return value instanceof Promise;
117
124
  }
118
- __name(isPromise, "isPromise");
119
125
  async function awaitReturn(val) {
120
126
  return isPromise(val) ? await val : val;
121
127
  }
122
- __name(awaitReturn, "awaitReturn");
123
128
  function isClass(obj) {
124
129
  return typeof obj === "function" && obj.prototype && obj.prototype.constructor === obj;
125
130
  }
126
- __name(isClass, "isClass");
127
131
  function throttle(func, wait) {
128
132
  let timeout = null;
129
133
  let lastArgs = null;
@@ -142,7 +146,6 @@ function throttle(func, wait) {
142
146
  }
143
147
  };
144
148
  }
145
- __name(throttle, "throttle");
146
149
  function extractParams(pattern, str) {
147
150
  const regexPattern = pattern.replace(/{(\w+)}/g, "(?<$1>[\\w-]+)");
148
151
  const regex = new RegExp(`^${regexPattern}$`);
@@ -155,7 +158,6 @@ function extractParams(pattern, str) {
155
158
  return null;
156
159
  }
157
160
  }
158
- __name(extractParams, "extractParams");
159
161
  function dremove(obj, keys) {
160
162
  if (typeof keys === "string") {
161
163
  keys = keys.split(".");
@@ -175,7 +177,6 @@ function dremove(obj, keys) {
175
177
  delete t[k];
176
178
  }
177
179
  }
178
- __name(dremove, "dremove");
179
180
  function buildObject(valuesMap, allMemory) {
180
181
  let memoryObj = {};
181
182
  for (let path of valuesMap.keys()) {
@@ -189,33 +190,25 @@ function buildObject(valuesMap, allMemory) {
189
190
  }
190
191
  return memoryObj;
191
192
  }
192
- __name(buildObject, "buildObject");
193
193
  function response(status, body) {
194
194
  return new Response(JSON.stringify(body), {
195
195
  status,
196
- headers: {
197
- "Content-Type": "application/json"
198
- }
196
+ headers: { "Content-Type": "application/json" }
199
197
  });
200
198
  }
201
- __name(response, "response");
202
199
 
203
200
  // src/request/response.ts
204
201
  var ServerResponse = class {
205
- static {
206
- __name(this, "ServerResponse");
207
- }
208
- interceptors;
209
- statusCode = 200;
210
- responseBody = {};
211
- responseHeaders = {
212
- "Content-Type": "application/json"
213
- };
214
202
  /**
215
203
  * Creates a new ServerResponse instance
216
204
  * @param interceptors Array of interceptor functions that can modify the response
217
205
  */
218
206
  constructor(interceptors = []) {
207
+ this.statusCode = 200;
208
+ this.responseBody = {};
209
+ this.responseHeaders = {
210
+ "Content-Type": "application/json"
211
+ };
219
212
  this.interceptors = interceptors;
220
213
  }
221
214
  /**
@@ -253,10 +246,7 @@ var ServerResponse = class {
253
246
  * @returns this instance for chaining
254
247
  */
255
248
  setHeaders(headers) {
256
- this.responseHeaders = {
257
- ...this.responseHeaders,
258
- ...headers
259
- };
249
+ this.responseHeaders = { ...this.responseHeaders, ...headers };
260
250
  return this;
261
251
  }
262
252
  /**
@@ -381,9 +371,7 @@ var ServerResponse = class {
381
371
  * @returns Promise<Response> The final Response object
382
372
  */
383
373
  async notPermitted(message = "Not permitted") {
384
- return this.status(403).json({
385
- error: message
386
- });
374
+ return this.status(403).json({ error: message });
387
375
  }
388
376
  /**
389
377
  * Creates an error response with status 401
@@ -391,9 +379,7 @@ var ServerResponse = class {
391
379
  * @returns Promise<Response> The final Response object
392
380
  */
393
381
  async unauthorized(message = "Unauthorized") {
394
- return this.status(401).json({
395
- error: message
396
- });
382
+ return this.status(401).json({ error: message });
397
383
  }
398
384
  /**
399
385
  * Creates an error response with status 404
@@ -401,9 +387,7 @@ var ServerResponse = class {
401
387
  * @returns Promise<Response> The final Response object
402
388
  */
403
389
  async notFound(message = "Not found") {
404
- return this.status(404).json({
405
- error: message
406
- });
390
+ return this.status(404).json({ error: message });
407
391
  }
408
392
  /**
409
393
  * Creates an error response with status 500
@@ -411,9 +395,7 @@ var ServerResponse = class {
411
395
  * @returns Promise<Response> The final Response object
412
396
  */
413
397
  async serverError(message = "Internal Server Error") {
414
- return this.status(500).json({
415
- error: message
416
- });
398
+ return this.status(500).json({ error: message });
417
399
  }
418
400
  };
419
401
 
@@ -448,11 +430,9 @@ function cors(res, options = {}) {
448
430
  headers: newHeaders
449
431
  });
450
432
  }
451
- __name(cors, "cors");
452
433
  function createCorsInterceptor(options = {}) {
453
434
  return (res) => cors(res, options);
454
435
  }
455
- __name(createCorsInterceptor, "createCorsInterceptor");
456
436
 
457
437
  // src/server.ts
458
438
  var Message = z.object({
@@ -460,37 +440,31 @@ var Message = z.object({
460
440
  value: z.any()
461
441
  });
462
442
  var Server = class {
463
- static {
464
- __name(this, "Server");
465
- }
466
- room;
467
- subRoom;
468
- rooms;
469
443
  /**
470
- * @constructor
471
- * @param {Party.Room} room - The room object representing the current game or application instance.
472
- *
473
- * @example
474
- * ```typescript
475
- * const server = new MyServer(new ServerIo("game"));
476
- * ```
477
- */
444
+ * @constructor
445
+ * @param {Party.Room} room - The room object representing the current game or application instance.
446
+ *
447
+ * @example
448
+ * ```typescript
449
+ * const server = new MyServer(new ServerIo("game"));
450
+ * ```
451
+ */
478
452
  constructor(room) {
479
453
  this.room = room;
480
454
  this.subRoom = null;
481
455
  this.rooms = [];
482
456
  }
483
457
  /**
484
- * @readonly
485
- * @property {boolean} isHibernate - Indicates whether the server is in hibernate mode.
486
- *
487
- * @example
488
- * ```typescript
489
- * if (!server.isHibernate) {
490
- * console.log("Server is active");
491
- * }
492
- * ```
493
- */
458
+ * @readonly
459
+ * @property {boolean} isHibernate - Indicates whether the server is in hibernate mode.
460
+ *
461
+ * @example
462
+ * ```typescript
463
+ * if (!server.isHibernate) {
464
+ * console.log("Server is active");
465
+ * }
466
+ * ```
467
+ */
494
468
  get isHibernate() {
495
469
  return !!this["options"]?.hibernate;
496
470
  }
@@ -514,35 +488,31 @@ var Server = class {
514
488
  }
515
489
  }
516
490
  /**
517
- * @method onStart
518
- * @async
519
- * @description Initializes the server and creates the initial room if not in hibernate mode.
520
- * @returns {Promise<void>}
521
- *
522
- * @example
523
- * ```typescript
524
- * async function initServer() {
525
- * await server.onStart();
526
- * console.log("Server started");
527
- * }
528
- * ```
529
- */
491
+ * @method onStart
492
+ * @async
493
+ * @description Initializes the server and creates the initial room if not in hibernate mode.
494
+ * @returns {Promise<void>}
495
+ *
496
+ * @example
497
+ * ```typescript
498
+ * async function initServer() {
499
+ * await server.onStart();
500
+ * console.log("Server started");
501
+ * }
502
+ * ```
503
+ */
530
504
  async onStart() {
531
505
  if (!this.isHibernate) {
532
506
  this.subRoom = await this.createRoom();
533
507
  }
534
508
  }
535
509
  async runGarbageCollector() {
536
- await this.garbageCollector({
537
- sessionExpiryTime: -1
538
- });
510
+ await this.garbageCollector({ sessionExpiryTime: -1 });
539
511
  }
540
512
  async garbageCollector(options) {
541
513
  const subRoom = await this.getSubRoom();
542
514
  if (!subRoom) return;
543
- const activeConnections = [
544
- ...this.room.getConnections()
545
- ];
515
+ const activeConnections = [...this.room.getConnections()];
546
516
  const activePrivateIds = new Set(activeConnections.map((conn) => conn.id));
547
517
  try {
548
518
  const sessions = await this.room.storage.list();
@@ -577,21 +547,21 @@ var Server = class {
577
547
  }
578
548
  }
579
549
  /**
580
- * @method createRoom
581
- * @private
582
- * @async
583
- * @param {CreateRoomOptions} [options={}] - Options for creating the room.
584
- * @returns {Promise<Object>} The created room instance.
585
- *
586
- * @example
587
- * ```typescript
588
- * // This method is private and called internally
589
- * async function internalCreateRoom() {
590
- * const room = await this.createRoom({ getMemoryAll: true });
591
- * console.log("Room created:", room);
592
- * }
593
- * ```
594
- */
550
+ * @method createRoom
551
+ * @private
552
+ * @async
553
+ * @param {CreateRoomOptions} [options={}] - Options for creating the room.
554
+ * @returns {Promise<Object>} The created room instance.
555
+ *
556
+ * @example
557
+ * ```typescript
558
+ * // This method is private and called internally
559
+ * async function internalCreateRoom() {
560
+ * const room = await this.createRoom({ getMemoryAll: true });
561
+ * console.log("Room created:", room);
562
+ * }
563
+ * ```
564
+ */
595
565
  async createRoom(options = {}) {
596
566
  let instance;
597
567
  let init = true;
@@ -606,7 +576,7 @@ var Server = class {
606
576
  if (!instance) {
607
577
  return null;
608
578
  }
609
- const loadMemory = /* @__PURE__ */ __name(async () => {
579
+ const loadMemory = async () => {
610
580
  const root = await this.room.storage.get(".");
611
581
  const memory = await this.room.storage.list();
612
582
  const tmpObject = root || {};
@@ -620,7 +590,7 @@ var Server = class {
620
590
  dset2(tmpObject, key, value);
621
591
  }
622
592
  load(instance, tmpObject, true);
623
- }, "loadMemory");
593
+ };
624
594
  instance.$memoryAll = {};
625
595
  instance.$autoSync = instance["autoSync"] !== false;
626
596
  instance.$pendingSync = /* @__PURE__ */ new Map();
@@ -720,7 +690,7 @@ var Server = class {
720
690
  return null;
721
691
  }
722
692
  };
723
- const syncCb = /* @__PURE__ */ __name((values) => {
693
+ const syncCb = (values) => {
724
694
  if (options.getMemoryAll) {
725
695
  buildObject(values, instance.$memoryAll);
726
696
  }
@@ -736,13 +706,16 @@ var Server = class {
736
706
  return;
737
707
  }
738
708
  const packet = buildObject(values, instance.$memoryAll);
739
- this.broadcast({
740
- type: "sync",
741
- value: packet
742
- }, instance);
709
+ this.broadcast(
710
+ {
711
+ type: "sync",
712
+ value: packet
713
+ },
714
+ instance
715
+ );
743
716
  values.clear();
744
- }, "syncCb");
745
- const persistCb = /* @__PURE__ */ __name(async (values) => {
717
+ };
718
+ const persistCb = async (values) => {
746
719
  if (initPersist) {
747
720
  values.clear();
748
721
  return;
@@ -757,7 +730,7 @@ var Server = class {
757
730
  }
758
731
  }
759
732
  values.clear();
760
- }, "persistCb");
733
+ };
761
734
  syncClass(instance, {
762
735
  onSync: instance["throttleSync"] ? throttle(syncCb, instance["throttleSync"]) : syncCb,
763
736
  onPersist: instance["throttleStorage"] ? throttle(persistCb, instance["throttleStorage"]) : persistCb
@@ -768,21 +741,21 @@ var Server = class {
768
741
  return instance;
769
742
  }
770
743
  /**
771
- * @method getSubRoom
772
- * @private
773
- * @async
774
- * @param {Object} [options={}] - Options for getting the sub-room.
775
- * @returns {Promise<Object>} The sub-room instance.
776
- *
777
- * @example
778
- * ```typescript
779
- * // This method is private and called internally
780
- * async function internalGetSubRoom() {
781
- * const subRoom = await this.getSubRoom();
782
- * console.log("Sub-room retrieved:", subRoom);
783
- * }
784
- * ```
785
- */
744
+ * @method getSubRoom
745
+ * @private
746
+ * @async
747
+ * @param {Object} [options={}] - Options for getting the sub-room.
748
+ * @returns {Promise<Object>} The sub-room instance.
749
+ *
750
+ * @example
751
+ * ```typescript
752
+ * // This method is private and called internally
753
+ * async function internalGetSubRoom() {
754
+ * const subRoom = await this.getSubRoom();
755
+ * console.log("Sub-room retrieved:", subRoom);
756
+ * }
757
+ * ```
758
+ */
786
759
  async getSubRoom(options = {}) {
787
760
  let subRoom;
788
761
  if (this.isHibernate) {
@@ -793,20 +766,20 @@ var Server = class {
793
766
  return subRoom;
794
767
  }
795
768
  /**
796
- * @method getUsersProperty
797
- * @private
798
- * @param {Object} subRoom - The sub-room instance.
799
- * @returns {Object|null} The users property of the sub-room, or null if not found.
800
- *
801
- * @example
802
- * ```typescript
803
- * // This method is private and called internally
804
- * function internalGetUsers(subRoom) {
805
- * const users = this.getUsersProperty(subRoom);
806
- * console.log("Users:", users);
807
- * }
808
- * ```
809
- */
769
+ * @method getUsersProperty
770
+ * @private
771
+ * @param {Object} subRoom - The sub-room instance.
772
+ * @returns {Object|null} The users property of the sub-room, or null if not found.
773
+ *
774
+ * @example
775
+ * ```typescript
776
+ * // This method is private and called internally
777
+ * function internalGetUsers(subRoom) {
778
+ * const users = this.getUsersProperty(subRoom);
779
+ * console.log("Users:", users);
780
+ * }
781
+ * ```
782
+ */
810
783
  getUsersProperty(subRoom) {
811
784
  const meta = subRoom.constructor["_propertyMetadata"];
812
785
  const propId = meta?.get("users");
@@ -822,12 +795,12 @@ var Server = class {
822
795
  return metadata.get("users");
823
796
  }
824
797
  /**
825
- * Retrieves the connection status property from a user object.
826
- *
827
- * @param {any} user - The user object to get the connection property from.
828
- * @returns {Function|null} - The connection property signal function or null if not found.
829
- * @private
830
- */
798
+ * Retrieves the connection status property from a user object.
799
+ *
800
+ * @param {any} user - The user object to get the connection property from.
801
+ * @returns {Function|null} - The connection property signal function or null if not found.
802
+ * @private
803
+ */
831
804
  getUserConnectionProperty(user) {
832
805
  if (!user) return null;
833
806
  const metadata = user.constructor._propertyMetadata;
@@ -837,13 +810,13 @@ var Server = class {
837
810
  return user[connectedPropName];
838
811
  }
839
812
  /**
840
- * Updates a user's connection status in the signal.
841
- *
842
- * @param {any} user - The user object to update.
843
- * @param {boolean} isConnected - The new connection status.
844
- * @returns {boolean} - Whether the update was successful.
845
- * @private
846
- */
813
+ * Updates a user's connection status in the signal.
814
+ *
815
+ * @param {any} user - The user object to update.
816
+ * @param {boolean} isConnected - The new connection status.
817
+ * @returns {boolean} - Whether the update was successful.
818
+ * @private
819
+ */
847
820
  updateUserConnectionStatus(user, isConnected) {
848
821
  const connectionSignal = this.getUserConnectionProperty(user);
849
822
  if (connectionSignal) {
@@ -853,17 +826,17 @@ var Server = class {
853
826
  return false;
854
827
  }
855
828
  /**
856
- * @method getSession
857
- * @private
858
- * @param {string} privateId - The private ID of the session.
859
- * @returns {Promise<Object|null>} The session object, or null if not found.
860
- *
861
- * @example
862
- * ```typescript
863
- * const session = await server.getSession("privateId");
864
- * console.log(session);
865
- * ```
866
- */
829
+ * @method getSession
830
+ * @private
831
+ * @param {string} privateId - The private ID of the session.
832
+ * @returns {Promise<Object|null>} The session object, or null if not found.
833
+ *
834
+ * @example
835
+ * ```typescript
836
+ * const session = await server.getSession("privateId");
837
+ * console.log(session);
838
+ * ```
839
+ */
867
840
  async getSession(privateId) {
868
841
  if (!privateId) return null;
869
842
  try {
@@ -884,23 +857,20 @@ var Server = class {
884
857
  async updateSessionConnection(privateId, connected) {
885
858
  const session = await this.getSession(privateId);
886
859
  if (session) {
887
- await this.saveSession(privateId, {
888
- ...session,
889
- connected
890
- });
860
+ await this.saveSession(privateId, { ...session, connected });
891
861
  }
892
862
  }
893
863
  /**
894
- * @method deleteSession
895
- * @private
896
- * @param {string} privateId - The private ID of the session to delete.
897
- * @returns {Promise<void>}
898
- *
899
- * @example
900
- * ```typescript
901
- * await server.deleteSession("privateId");
902
- * ```
903
- */
864
+ * @method deleteSession
865
+ * @private
866
+ * @param {string} privateId - The private ID of the session to delete.
867
+ * @returns {Promise<void>}
868
+ *
869
+ * @example
870
+ * ```typescript
871
+ * await server.deleteSession("privateId");
872
+ * ```
873
+ */
904
874
  async deleteSession(privateId) {
905
875
  await this.room.storage.delete(`session:${privateId}`);
906
876
  }
@@ -912,10 +882,8 @@ var Server = class {
912
882
  conn.close();
913
883
  return;
914
884
  }
915
- const sessionExpiryTime = subRoom.constructor.sessionExpiryTime;
916
- await this.garbageCollector({
917
- sessionExpiryTime
918
- });
885
+ const sessionExpiryTime = subRoom.sessionExpiryTime ?? subRoom.constructor.sessionExpiryTime ?? 5 * 60 * 1e3;
886
+ await this.garbageCollector({ sessionExpiryTime });
919
887
  const roomGuards = subRoom.constructor["_roomGuards"] || [];
920
888
  for (const guard of roomGuards) {
921
889
  const isAuthorized = await guard(conn, ctx, this.room);
@@ -983,21 +951,21 @@ var Server = class {
983
951
  }
984
952
  }
985
953
  /**
986
- * @method onConnect
987
- * @async
988
- * @param {Party.Connection} conn - The connection object for the new user.
989
- * @param {Party.ConnectionContext} ctx - The context of the connection.
990
- * @description Handles a new user connection, creates a user object, and sends initial sync data.
991
- * @returns {Promise<void>}
992
- *
993
- * @example
994
- * ```typescript
995
- * server.onConnect = async (conn, ctx) => {
996
- * await server.onConnect(conn, ctx);
997
- * console.log("New user connected:", conn.id);
998
- * };
999
- * ```
1000
- */
954
+ * @method onConnect
955
+ * @async
956
+ * @param {Party.Connection} conn - The connection object for the new user.
957
+ * @param {Party.ConnectionContext} ctx - The context of the connection.
958
+ * @description Handles a new user connection, creates a user object, and sends initial sync data.
959
+ * @returns {Promise<void>}
960
+ *
961
+ * @example
962
+ * ```typescript
963
+ * server.onConnect = async (conn, ctx) => {
964
+ * await server.onConnect(conn, ctx);
965
+ * console.log("New user connected:", conn.id);
966
+ * };
967
+ * ```
968
+ */
1001
969
  async onConnect(conn, ctx) {
1002
970
  if (ctx.request?.headers.has("x-shard-id")) {
1003
971
  this.onConnectShard(conn, ctx);
@@ -1006,13 +974,13 @@ var Server = class {
1006
974
  }
1007
975
  }
1008
976
  /**
1009
- * @method onConnectShard
1010
- * @private
1011
- * @param {Party.Connection} conn - The connection object for the new shard.
1012
- * @param {Party.ConnectionContext} ctx - The context of the shard connection.
1013
- * @description Handles a new shard connection, setting up the necessary state.
1014
- * @returns {void}
1015
- */
977
+ * @method onConnectShard
978
+ * @private
979
+ * @param {Party.Connection} conn - The connection object for the new shard.
980
+ * @param {Party.ConnectionContext} ctx - The context of the shard connection.
981
+ * @description Handles a new shard connection, setting up the necessary state.
982
+ * @returns {void}
983
+ */
1016
984
  onConnectShard(conn, ctx) {
1017
985
  const shardId = ctx.request?.headers.get("x-shard-id") || "unknown-shard";
1018
986
  conn.setState({
@@ -1023,13 +991,13 @@ var Server = class {
1023
991
  });
1024
992
  }
1025
993
  /**
1026
- * @method onMessage
1027
- * @async
1028
- * @param {string} message - The message received from a user or shard.
1029
- * @param {Party.Connection} sender - The connection object of the sender.
1030
- * @description Processes incoming messages, handling differently based on if sender is shard or client.
1031
- * @returns {Promise<void>}
1032
- */
994
+ * @method onMessage
995
+ * @async
996
+ * @param {string} message - The message received from a user or shard.
997
+ * @param {Party.Connection} sender - The connection object of the sender.
998
+ * @description Processes incoming messages, handling differently based on if sender is shard or client.
999
+ * @returns {Promise<void>}
1000
+ */
1033
1001
  async onMessage(message, sender) {
1034
1002
  if (sender.state && sender.state.shard) {
1035
1003
  await this.handleShardMessage(message, sender);
@@ -1071,12 +1039,16 @@ var Server = class {
1071
1039
  }
1072
1040
  }
1073
1041
  if (actionName.bodyValidation) {
1074
- const bodyResult = actionName.bodyValidation.safeParse(result.data.value);
1042
+ const bodyResult = actionName.bodyValidation.safeParse(
1043
+ result.data.value
1044
+ );
1075
1045
  if (!bodyResult.success) {
1076
1046
  return;
1077
1047
  }
1078
1048
  }
1079
- await awaitReturn(subRoom[actionName.key](user, result.data.value, sender));
1049
+ await awaitReturn(
1050
+ subRoom[actionName.key](user, result.data.value, sender)
1051
+ );
1080
1052
  return;
1081
1053
  }
1082
1054
  const unhandledAction = subRoom.constructor["_unhandledActionMetadata"];
@@ -1088,18 +1060,20 @@ var Server = class {
1088
1060
  return;
1089
1061
  }
1090
1062
  }
1091
- await awaitReturn(subRoom[unhandledAction.key](user, result.data, sender));
1063
+ await awaitReturn(
1064
+ subRoom[unhandledAction.key](user, result.data, sender)
1065
+ );
1092
1066
  }
1093
1067
  }
1094
1068
  /**
1095
- * @method handleShardMessage
1096
- * @private
1097
- * @async
1098
- * @param {string} message - The message received from a shard.
1099
- * @param {Party.Connection} shardConnection - The connection object of the shard.
1100
- * @description Processes messages from shards, extracting client information.
1101
- * @returns {Promise<void>}
1102
- */
1069
+ * @method handleShardMessage
1070
+ * @private
1071
+ * @async
1072
+ * @param {string} message - The message received from a shard.
1073
+ * @param {Party.Connection} shardConnection - The connection object of the shard.
1074
+ * @description Processes messages from shards, extracting client information.
1075
+ * @returns {Promise<void>}
1076
+ */
1103
1077
  async handleShardMessage(message, shardConnection) {
1104
1078
  let parsedMessage;
1105
1079
  try {
@@ -1125,14 +1099,14 @@ var Server = class {
1125
1099
  }
1126
1100
  }
1127
1101
  /**
1128
- * @method handleShardClientConnect
1129
- * @private
1130
- * @async
1131
- * @param {Object} message - The client connection message from a shard.
1132
- * @param {Party.Connection} shardConnection - The connection object of the shard.
1133
- * @description Handles a new client connection via a shard.
1134
- * @returns {Promise<void>}
1135
- */
1102
+ * @method handleShardClientConnect
1103
+ * @private
1104
+ * @async
1105
+ * @param {Object} message - The client connection message from a shard.
1106
+ * @param {Party.Connection} shardConnection - The connection object of the shard.
1107
+ * @description Handles a new client connection via a shard.
1108
+ * @returns {Promise<void>}
1109
+ */
1136
1110
  async handleShardClientConnect(message, shardConnection) {
1137
1111
  const { privateId, requestInfo } = message;
1138
1112
  const shardState = shardConnection.state;
@@ -1145,22 +1119,22 @@ var Server = class {
1145
1119
  };
1146
1120
  const virtualConnection = {
1147
1121
  id: privateId,
1148
- send: /* @__PURE__ */ __name((data) => {
1122
+ send: (data) => {
1149
1123
  shardConnection.send(JSON.stringify({
1150
1124
  targetClientId: privateId,
1151
1125
  data
1152
1126
  }));
1153
- }, "send"),
1127
+ },
1154
1128
  state: {},
1155
- setState: /* @__PURE__ */ __name((state) => {
1129
+ setState: (state) => {
1156
1130
  const clients = shardState.clients;
1157
1131
  const currentState = clients.get(privateId) || {};
1158
1132
  const mergedState = Object.assign({}, currentState, state);
1159
1133
  clients.set(privateId, mergedState);
1160
1134
  virtualConnection.state = clients.get(privateId);
1161
1135
  return virtualConnection.state;
1162
- }, "setState"),
1163
- close: /* @__PURE__ */ __name(() => {
1136
+ },
1137
+ close: () => {
1164
1138
  shardConnection.send(JSON.stringify({
1165
1139
  type: "shard.closeClient",
1166
1140
  privateId
@@ -1168,7 +1142,7 @@ var Server = class {
1168
1142
  if (shardState.clients) {
1169
1143
  shardState.clients.delete(privateId);
1170
1144
  }
1171
- }, "close")
1145
+ }
1172
1146
  };
1173
1147
  if (!shardState.clients.has(privateId)) {
1174
1148
  shardState.clients.set(privateId, {});
@@ -1176,41 +1150,39 @@ var Server = class {
1176
1150
  await this.onConnectClient(virtualConnection, virtualContext);
1177
1151
  }
1178
1152
  /**
1179
- * @method handleShardClientMessage
1180
- * @private
1181
- * @async
1182
- * @param {Object} message - The client message from a shard.
1183
- * @param {Party.Connection} shardConnection - The connection object of the shard.
1184
- * @description Handles a message from a client via a shard.
1185
- * @returns {Promise<void>}
1186
- */
1153
+ * @method handleShardClientMessage
1154
+ * @private
1155
+ * @async
1156
+ * @param {Object} message - The client message from a shard.
1157
+ * @param {Party.Connection} shardConnection - The connection object of the shard.
1158
+ * @description Handles a message from a client via a shard.
1159
+ * @returns {Promise<void>}
1160
+ */
1187
1161
  async handleShardClientMessage(message, shardConnection) {
1188
1162
  const { privateId, publicId, payload } = message;
1189
1163
  const shardState = shardConnection.state;
1190
1164
  const clients = shardState.clients;
1191
1165
  if (!clients.has(privateId)) {
1192
1166
  console.warn(`Received message from unknown client ${privateId}, creating virtual connection`);
1193
- clients.set(privateId, {
1194
- publicId
1195
- });
1167
+ clients.set(privateId, { publicId });
1196
1168
  }
1197
1169
  const virtualConnection = {
1198
1170
  id: privateId,
1199
- send: /* @__PURE__ */ __name((data) => {
1171
+ send: (data) => {
1200
1172
  shardConnection.send(JSON.stringify({
1201
1173
  targetClientId: privateId,
1202
1174
  data
1203
1175
  }));
1204
- }, "send"),
1176
+ },
1205
1177
  state: clients.get(privateId),
1206
- setState: /* @__PURE__ */ __name((state) => {
1178
+ setState: (state) => {
1207
1179
  const currentState = clients.get(privateId) || {};
1208
1180
  const mergedState = Object.assign({}, currentState, state);
1209
1181
  clients.set(privateId, mergedState);
1210
1182
  virtualConnection.state = clients.get(privateId);
1211
1183
  return virtualConnection.state;
1212
- }, "setState"),
1213
- close: /* @__PURE__ */ __name(() => {
1184
+ },
1185
+ close: () => {
1214
1186
  shardConnection.send(JSON.stringify({
1215
1187
  type: "shard.closeClient",
1216
1188
  privateId
@@ -1218,20 +1190,20 @@ var Server = class {
1218
1190
  if (shardState.clients) {
1219
1191
  shardState.clients.delete(privateId);
1220
1192
  }
1221
- }, "close")
1193
+ }
1222
1194
  };
1223
1195
  const payloadString = typeof payload === "string" ? payload : JSON.stringify(payload);
1224
1196
  await this.onMessage(payloadString, virtualConnection);
1225
1197
  }
1226
1198
  /**
1227
- * @method handleShardClientDisconnect
1228
- * @private
1229
- * @async
1230
- * @param {Object} message - The client disconnection message from a shard.
1231
- * @param {Party.Connection} shardConnection - The connection object of the shard.
1232
- * @description Handles a client disconnection via a shard.
1233
- * @returns {Promise<void>}
1234
- */
1199
+ * @method handleShardClientDisconnect
1200
+ * @private
1201
+ * @async
1202
+ * @param {Object} message - The client disconnection message from a shard.
1203
+ * @param {Party.Connection} shardConnection - The connection object of the shard.
1204
+ * @description Handles a client disconnection via a shard.
1205
+ * @returns {Promise<void>}
1206
+ */
1235
1207
  async handleShardClientDisconnect(message, shardConnection) {
1236
1208
  const { privateId, publicId } = message;
1237
1209
  const shardState = shardConnection.state;
@@ -1243,33 +1215,34 @@ var Server = class {
1243
1215
  }
1244
1216
  const virtualConnection = {
1245
1217
  id: privateId,
1246
- send: /* @__PURE__ */ __name(() => {
1247
- }, "send"),
1218
+ send: () => {
1219
+ },
1220
+ // No-op since client is disconnecting
1248
1221
  state: clientState,
1249
- setState: /* @__PURE__ */ __name(() => {
1222
+ setState: () => {
1250
1223
  return {};
1251
- }, "setState"),
1252
- close: /* @__PURE__ */ __name(() => {
1253
- }, "close")
1224
+ },
1225
+ close: () => {
1226
+ }
1254
1227
  };
1255
1228
  await this.onClose(virtualConnection);
1256
1229
  clients.delete(privateId);
1257
1230
  }
1258
1231
  /**
1259
- * @method onClose
1260
- * @async
1261
- * @param {Party.Connection} conn - The connection object of the disconnecting user.
1262
- * @description Handles user disconnection, removing them from the room and triggering the onLeave event..
1263
- * @returns {Promise<void>}
1264
- *
1265
- * @example
1266
- * ```typescript
1267
- * server.onClose = async (conn) => {
1268
- * await server.onClose(conn);
1269
- * console.log("User disconnected:", conn.id);
1270
- * };
1271
- * ```
1272
- */
1232
+ * @method onClose
1233
+ * @async
1234
+ * @param {Party.Connection} conn - The connection object of the disconnecting user.
1235
+ * @description Handles user disconnection, removing them from the room and triggering the onLeave event..
1236
+ * @returns {Promise<void>}
1237
+ *
1238
+ * @example
1239
+ * ```typescript
1240
+ * server.onClose = async (conn) => {
1241
+ * await server.onClose(conn);
1242
+ * console.log("User disconnected:", conn.id);
1243
+ * };
1244
+ * ```
1245
+ */
1273
1246
  async onClose(conn) {
1274
1247
  const subRoom = await this.getSubRoom();
1275
1248
  if (!subRoom) {
@@ -1292,9 +1265,7 @@ var Server = class {
1292
1265
  if (!connectionUpdated) {
1293
1266
  this.broadcast({
1294
1267
  type: "user_disconnected",
1295
- value: {
1296
- publicId
1297
- }
1268
+ value: { publicId }
1298
1269
  }, subRoom);
1299
1270
  }
1300
1271
  }
@@ -1307,12 +1278,12 @@ var Server = class {
1307
1278
  await awaitReturn(subRoom["onError"]?.(connection, error));
1308
1279
  }
1309
1280
  /**
1310
- * @method onRequest
1311
- * @async
1312
- * @param {Party.Request} req - The HTTP request to handle
1313
- * @description Handles HTTP requests, either directly from clients or forwarded by shards
1314
- * @returns {Promise<Response>} The response to return to the client
1315
- */
1281
+ * @method onRequest
1282
+ * @async
1283
+ * @param {Party.Request} req - The HTTP request to handle
1284
+ * @description Handles HTTP requests, either directly from clients or forwarded by shards
1285
+ * @returns {Promise<Response>} The response to return to the client
1286
+ */
1316
1287
  async onRequest(req) {
1317
1288
  const isFromShard = req.headers.has("x-forwarded-by-shard");
1318
1289
  const shardId = req.headers.get("x-shard-id");
@@ -1328,14 +1299,14 @@ var Server = class {
1328
1299
  return this.handleDirectRequest(req, res);
1329
1300
  }
1330
1301
  /**
1331
- * @method handleSessionRestore
1332
- * @private
1333
- * @async
1334
- * @param {Party.Request} req - The HTTP request for session restore
1335
- * @param {ServerResponse} res - The response object
1336
- * @description Handles session restoration from transfer data, creates session from privateId
1337
- * @returns {Promise<Response>} The response to return to the client
1338
- */
1302
+ * @method handleSessionRestore
1303
+ * @private
1304
+ * @async
1305
+ * @param {Party.Request} req - The HTTP request for session restore
1306
+ * @param {ServerResponse} res - The response object
1307
+ * @description Handles session restoration from transfer data, creates session from privateId
1308
+ * @returns {Promise<Response>} The response to return to the client
1309
+ */
1339
1310
  async handleSessionRestore(req, res) {
1340
1311
  try {
1341
1312
  const transferData = await req.json();
@@ -1360,14 +1331,16 @@ var Server = class {
1360
1331
  if (signal2 && usersPropName) {
1361
1332
  const { classType } = signal2.options;
1362
1333
  const user = isClass(classType) ? new classType() : classType();
1363
- const hydratedSnapshot = await awaitReturn(subRoom["onSessionRestore"]?.({
1364
- userSnapshot,
1365
- user,
1366
- publicId,
1367
- privateId,
1368
- sessionState,
1369
- room: this.room
1370
- })) ?? userSnapshot;
1334
+ const hydratedSnapshot = await awaitReturn(
1335
+ subRoom["onSessionRestore"]?.({
1336
+ userSnapshot,
1337
+ user,
1338
+ publicId,
1339
+ privateId,
1340
+ sessionState,
1341
+ room: this.room
1342
+ })
1343
+ ) ?? userSnapshot;
1371
1344
  signal2()[publicId] = user;
1372
1345
  load(user, hydratedSnapshot, true);
1373
1346
  await this.room.storage.put(`${usersPropName}.${publicId}`, userSnapshot);
@@ -1379,22 +1352,20 @@ var Server = class {
1379
1352
  publicId,
1380
1353
  restored: true
1381
1354
  });
1382
- return res.success({
1383
- transferToken
1384
- });
1355
+ return res.success({ transferToken });
1385
1356
  } catch (error) {
1386
1357
  console.error("Error restoring session:", error);
1387
1358
  return res.serverError("Failed to restore session");
1388
1359
  }
1389
1360
  }
1390
1361
  /**
1391
- * @method handleDirectRequest
1392
- * @private
1393
- * @async
1394
- * @param {Party.Request} req - The HTTP request received directly from a client
1395
- * @description Processes requests received directly from clients
1396
- * @returns {Promise<Response>} The response to return to the client
1397
- */
1362
+ * @method handleDirectRequest
1363
+ * @private
1364
+ * @async
1365
+ * @param {Party.Request} req - The HTTP request received directly from a client
1366
+ * @description Processes requests received directly from clients
1367
+ * @returns {Promise<Response>} The response to return to the client
1368
+ */
1398
1369
  async handleDirectRequest(req, res) {
1399
1370
  const subRoom = await this.getSubRoom();
1400
1371
  if (!subRoom) {
@@ -1418,14 +1389,14 @@ var Server = class {
1418
1389
  return res.success(legacyResponse);
1419
1390
  }
1420
1391
  /**
1421
- * @method tryMatchRequestHandler
1422
- * @private
1423
- * @async
1424
- * @param {Party.Request} req - The HTTP request to handle
1425
- * @param {Object} subRoom - The room instance
1426
- * @description Attempts to match the request to a registered @Request handler
1427
- * @returns {Promise<Response | null>} The response or null if no handler matched
1428
- */
1392
+ * @method tryMatchRequestHandler
1393
+ * @private
1394
+ * @async
1395
+ * @param {Party.Request} req - The HTTP request to handle
1396
+ * @param {Object} subRoom - The room instance
1397
+ * @description Attempts to match the request to a registered @Request handler
1398
+ * @returns {Promise<Response | null>} The response or null if no handler matched
1399
+ */
1429
1400
  async tryMatchRequestHandler(req, res, subRoom) {
1430
1401
  const requestHandlers = subRoom.constructor["_requestMetadata"];
1431
1402
  if (!requestHandlers) {
@@ -1433,8 +1404,7 @@ var Server = class {
1433
1404
  }
1434
1405
  const url = new URL(req.url);
1435
1406
  const method = req.method;
1436
- let pathname = url.pathname;
1437
- pathname = "/" + pathname.split("/").slice(4).join("/");
1407
+ const pathname = this.normalizeRequestPath(url.pathname);
1438
1408
  for (const [routeKey, handler] of requestHandlers.entries()) {
1439
1409
  const firstColonIndex = routeKey.indexOf(":");
1440
1410
  const handlerMethod = routeKey.substring(0, firstColonIndex);
@@ -1455,23 +1425,20 @@ var Server = class {
1455
1425
  }
1456
1426
  }
1457
1427
  let bodyData = null;
1458
- if (handler.bodyValidation && [
1459
- "POST",
1460
- "PUT",
1461
- "PATCH"
1462
- ].includes(method)) {
1428
+ if (handler.bodyValidation && ["POST", "PUT", "PATCH"].includes(method)) {
1463
1429
  try {
1464
1430
  const contentType = req.headers.get("content-type") || "";
1465
- if (contentType.includes("application/json")) {
1466
- const body = await req.json();
1467
- const validation = handler.bodyValidation.safeParse(body);
1468
- if (!validation.success) {
1469
- return res.badRequest("Invalid request body", {
1470
- details: validation.error
1471
- });
1472
- }
1473
- bodyData = validation.data;
1431
+ if (!contentType.includes("application/json")) {
1432
+ return res.badRequest("Content-Type must be application/json");
1474
1433
  }
1434
+ const body = await req.json();
1435
+ const validation = handler.bodyValidation.safeParse(body);
1436
+ if (!validation.success) {
1437
+ return res.badRequest("Invalid request body", {
1438
+ details: validation.error
1439
+ });
1440
+ }
1441
+ bodyData = validation.data;
1475
1442
  } catch (error) {
1476
1443
  return res.badRequest("Failed to parse request body");
1477
1444
  }
@@ -1479,7 +1446,9 @@ var Server = class {
1479
1446
  try {
1480
1447
  req["data"] = bodyData;
1481
1448
  req["params"] = params;
1482
- const result = await awaitReturn(subRoom[handler.key](req, res));
1449
+ const result = await awaitReturn(
1450
+ subRoom[handler.key](req, res)
1451
+ );
1483
1452
  if (result instanceof Response) {
1484
1453
  return result;
1485
1454
  }
@@ -1493,26 +1462,24 @@ var Server = class {
1493
1462
  return null;
1494
1463
  }
1495
1464
  /**
1496
- * @method pathMatches
1497
- * @private
1498
- * @param {string} requestPath - The path from the request
1499
- * @param {string} handlerPath - The path pattern from the handler
1500
- * @description Checks if a request path matches a handler path pattern
1501
- * @returns {boolean} True if the paths match
1502
- */
1465
+ * @method pathMatches
1466
+ * @private
1467
+ * @param {string} requestPath - The path from the request
1468
+ * @param {string} handlerPath - The path pattern from the handler
1469
+ * @description Checks if a request path matches a handler path pattern
1470
+ * @returns {boolean} True if the paths match
1471
+ */
1503
1472
  pathMatches(requestPath, handlerPath) {
1504
- const pathRegexString = handlerPath.replace(/\//g, "\\/").replace(/:([^\/]+)/g, "([^/]+)");
1505
- const pathRegex = new RegExp(`^${pathRegexString}`);
1506
- return pathRegex.test(requestPath);
1473
+ return this.pathPatternToRegex(handlerPath).test(requestPath);
1507
1474
  }
1508
1475
  /**
1509
- * @method extractPathParams
1510
- * @private
1511
- * @param {string} requestPath - The path from the request
1512
- * @param {string} handlerPath - The path pattern from the handler
1513
- * @description Extracts path parameters from the request path based on the handler pattern
1514
- * @returns {Object} An object containing the path parameters
1515
- */
1476
+ * @method extractPathParams
1477
+ * @private
1478
+ * @param {string} requestPath - The path from the request
1479
+ * @param {string} handlerPath - The path pattern from the handler
1480
+ * @description Extracts path parameters from the request path based on the handler pattern
1481
+ * @returns {Object} An object containing the path parameters
1482
+ */
1516
1483
  extractPathParams(requestPath, handlerPath) {
1517
1484
  const params = {};
1518
1485
  const paramNames = [];
@@ -1521,8 +1488,7 @@ var Server = class {
1521
1488
  paramNames.push(segment.substring(1));
1522
1489
  }
1523
1490
  });
1524
- const pathRegexString = handlerPath.replace(/\//g, "\\/").replace(/:([^\/]+)/g, "([^/]+)");
1525
- const pathRegex = new RegExp(`^${pathRegexString}`);
1491
+ const pathRegex = this.pathPatternToRegex(handlerPath);
1526
1492
  const matches = requestPath.match(pathRegex);
1527
1493
  if (matches && matches.length > 1) {
1528
1494
  for (let i = 0; i < paramNames.length; i++) {
@@ -1531,15 +1497,32 @@ var Server = class {
1531
1497
  }
1532
1498
  return params;
1533
1499
  }
1500
+ normalizeRequestPath(pathname) {
1501
+ const parts = pathname.split("/").filter(Boolean);
1502
+ if (parts[0] === "parties" && parts.length >= 3) {
1503
+ const routePath = parts.slice(3).join("/");
1504
+ return routePath ? `/${routePath}` : "/";
1505
+ }
1506
+ return pathname || "/";
1507
+ }
1508
+ pathPatternToRegex(handlerPath) {
1509
+ const segments = handlerPath.split("/").map((segment) => {
1510
+ if (segment.startsWith(":")) {
1511
+ return "([^/]+)";
1512
+ }
1513
+ return segment.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1514
+ });
1515
+ return new RegExp(`^${segments.join("/")}$`);
1516
+ }
1534
1517
  /**
1535
- * @method handleShardRequest
1536
- * @private
1537
- * @async
1538
- * @param {Party.Request} req - The HTTP request forwarded by a shard
1539
- * @param {string | null} shardId - The ID of the shard that forwarded the request
1540
- * @description Processes requests forwarded by shards, preserving client context
1541
- * @returns {Promise<Response>} The response to return to the shard (which will forward it to the client)
1542
- */
1518
+ * @method handleShardRequest
1519
+ * @private
1520
+ * @async
1521
+ * @param {Party.Request} req - The HTTP request forwarded by a shard
1522
+ * @param {string | null} shardId - The ID of the shard that forwarded the request
1523
+ * @description Processes requests forwarded by shards, preserving client context
1524
+ * @returns {Promise<Response>} The response to return to the shard (which will forward it to the client)
1525
+ */
1543
1526
  async handleShardRequest(req, res, shardId) {
1544
1527
  const subRoom = await this.getSubRoom();
1545
1528
  if (!subRoom) {
@@ -1566,13 +1549,13 @@ var Server = class {
1566
1549
  }
1567
1550
  }
1568
1551
  /**
1569
- * @method createEnhancedRequest
1570
- * @private
1571
- * @param {Party.Request} originalReq - The original request received from the shard
1572
- * @param {string | null} originalClientIp - The original client IP, if available
1573
- * @description Creates an enhanced request object that preserves the original client context
1574
- * @returns {Party.Request} The enhanced request object
1575
- */
1552
+ * @method createEnhancedRequest
1553
+ * @private
1554
+ * @param {Party.Request} originalReq - The original request received from the shard
1555
+ * @param {string | null} originalClientIp - The original client IP, if available
1556
+ * @description Creates an enhanced request object that preserves the original client context
1557
+ * @returns {Party.Request} The enhanced request object
1558
+ */
1576
1559
  createEnhancedRequest(originalReq, originalClientIp) {
1577
1560
  const clonedReq = originalReq.clone();
1578
1561
  clonedReq.viaShard = true;
@@ -1585,18 +1568,6 @@ var Server = class {
1585
1568
 
1586
1569
  // src/shard.ts
1587
1570
  var Shard = class {
1588
- static {
1589
- __name(this, "Shard");
1590
- }
1591
- room;
1592
- ws;
1593
- connectionMap;
1594
- mainServerStub;
1595
- worldUrl;
1596
- worldId;
1597
- lastReportedConnections;
1598
- statsInterval;
1599
- statsIntervalId;
1600
1571
  constructor(room) {
1601
1572
  this.room = room;
1602
1573
  this.connectionMap = /* @__PURE__ */ new Map();
@@ -1719,9 +1690,7 @@ var Shard = class {
1719
1690
  })
1720
1691
  });
1721
1692
  if (!response2.ok) {
1722
- const errorData = await response2.json().catch(() => ({
1723
- error: "Unknown error"
1724
- }));
1693
+ const errorData = await response2.json().catch(() => ({ error: "Unknown error" }));
1725
1694
  console.error(`Failed to update World stats: ${response2.status} - ${errorData.error || "Unknown error"}`);
1726
1695
  return false;
1727
1696
  }
@@ -1733,17 +1702,15 @@ var Shard = class {
1733
1702
  }
1734
1703
  }
1735
1704
  /**
1736
- * @method onRequest
1737
- * @async
1738
- * @param {Party.Request} req - The HTTP request to handle
1739
- * @description Forwards HTTP requests to the main server, preserving client context
1740
- * @returns {Promise<Response>} The response from the main server
1741
- */
1705
+ * @method onRequest
1706
+ * @async
1707
+ * @param {Party.Request} req - The HTTP request to handle
1708
+ * @description Forwards HTTP requests to the main server, preserving client context
1709
+ * @returns {Promise<Response>} The response from the main server
1710
+ */
1742
1711
  async onRequest(req) {
1743
1712
  if (!this.mainServerStub) {
1744
- return response(503, {
1745
- error: "Shard not connected to main server"
1746
- });
1713
+ return response(503, { error: "Shard not connected to main server" });
1747
1714
  }
1748
1715
  try {
1749
1716
  const url = new URL(req.url);
@@ -1771,32 +1738,28 @@ var Shard = class {
1771
1738
  const response2 = await this.mainServerStub.fetch(path, requestInit);
1772
1739
  return response2;
1773
1740
  } catch (error) {
1774
- return response(500, {
1775
- error: "Error forwarding request"
1776
- });
1741
+ return response(500, { error: "Error forwarding request" });
1777
1742
  }
1778
1743
  }
1779
1744
  /**
1780
- * @method onAlarm
1781
- * @async
1782
- * @description Executed periodically, used to perform maintenance tasks
1783
- */
1745
+ * @method onAlarm
1746
+ * @async
1747
+ * @description Executed periodically, used to perform maintenance tasks
1748
+ */
1784
1749
  async onAlarm() {
1785
1750
  await this.updateWorldStats();
1786
1751
  }
1787
1752
  };
1788
1753
 
1789
1754
  // src/testing.ts
1790
- async function testRoom(Room3, options = {}) {
1791
- const createServer = /* @__PURE__ */ __name((io2) => {
1755
+ async function testRoom(Room2, options = {}) {
1756
+ const createServer = (io2) => {
1792
1757
  const server2 = new Server(io2);
1793
- server2.rooms = [
1794
- Room3
1795
- ];
1758
+ server2.rooms = [Room2];
1796
1759
  return server2;
1797
- }, "createServer");
1760
+ };
1798
1761
  const isShard = options.shard || false;
1799
- const io = new ServerIo(Room3.path, isShard ? {
1762
+ const io = new ServerIo(Room2.path, isShard ? {
1800
1763
  parties: {
1801
1764
  game: createServer,
1802
1765
  ...options.parties || {}
@@ -1808,9 +1771,9 @@ async function testRoom(Room3, options = {}) {
1808
1771
  partyFn: options.partyFn,
1809
1772
  env: options.env
1810
1773
  });
1811
- Room3.prototype.throttleSync = 0;
1812
- Room3.prototype.throttleStorage = 0;
1813
- Room3.prototype.options = options;
1774
+ Room2.prototype.throttleSync = 0;
1775
+ Room2.prototype.throttleStorage = 0;
1776
+ Room2.prototype.options = options;
1814
1777
  let server;
1815
1778
  if (options.shard) {
1816
1779
  const shardServer = new Shard(io);
@@ -1835,41 +1798,31 @@ async function testRoom(Room3, options = {}) {
1835
1798
  return {
1836
1799
  server,
1837
1800
  room: server.subRoom,
1838
- createClient: /* @__PURE__ */ __name(async (id2, opts) => {
1801
+ createClient: async (id2, opts) => {
1839
1802
  const client = await io.connection(server, id2, opts);
1840
1803
  return client;
1841
- }, "createClient"),
1842
- getServerUser: /* @__PURE__ */ __name(async (client, prop = "users") => {
1804
+ },
1805
+ getServerUser: async (client, prop = "users") => {
1843
1806
  const privateId = client.conn.id;
1844
1807
  const session = await server.getSession(privateId);
1845
1808
  return server.subRoom[prop]()[session?.publicId];
1846
- }, "getServerUser")
1809
+ }
1847
1810
  };
1848
1811
  }
1849
- __name(testRoom, "testRoom");
1850
1812
  async function request(room, path, options = {
1851
1813
  method: "GET"
1852
1814
  }) {
1853
1815
  const url = new URL("http://localhost" + path);
1854
- const request1 = new Request(url.toString(), options);
1855
- const response2 = await room.onRequest(request1);
1816
+ const request2 = new Request(url.toString(), options);
1817
+ const response2 = await room.onRequest(request2);
1856
1818
  return response2;
1857
1819
  }
1858
- __name(request, "request");
1859
1820
  function tick(ms = 0) {
1860
1821
  return new Promise((resolve) => setTimeout(resolve, ms));
1861
1822
  }
1862
- __name(tick, "tick");
1863
1823
 
1864
1824
  // src/mock.ts
1865
1825
  var MockPartyClient = class {
1866
- static {
1867
- __name(this, "MockPartyClient");
1868
- }
1869
- server;
1870
- events;
1871
- id;
1872
- conn;
1873
1826
  constructor(server, id2) {
1874
1827
  this.server = server;
1875
1828
  this.events = /* @__PURE__ */ new Map();
@@ -1905,12 +1858,7 @@ var MockPartyClient = class {
1905
1858
  return this.server.onMessage(JSON.stringify(data), this.conn);
1906
1859
  }
1907
1860
  };
1908
- var MockLobby = class MockLobby2 {
1909
- static {
1910
- __name(this, "MockLobby");
1911
- }
1912
- server;
1913
- lobbyId;
1861
+ var MockLobby = class {
1914
1862
  constructor(server, lobbyId) {
1915
1863
  this.server = server;
1916
1864
  this.lobbyId = lobbyId;
@@ -1928,12 +1876,7 @@ var MockLobby = class MockLobby2 {
1928
1876
  return request(this.server, baseUrl + url, options);
1929
1877
  }
1930
1878
  };
1931
- var MockContext = class MockContext2 {
1932
- static {
1933
- __name(this, "MockContext");
1934
- }
1935
- room;
1936
- parties;
1879
+ var MockContext = class {
1937
1880
  constructor(room, options = {}) {
1938
1881
  this.room = room;
1939
1882
  this.parties = {
@@ -1943,13 +1886,13 @@ var MockContext = class MockContext2 {
1943
1886
  if (options.partyFn) {
1944
1887
  const serverCache = /* @__PURE__ */ new Map();
1945
1888
  this.parties.main = {
1946
- get: /* @__PURE__ */ __name(async (lobbyId) => {
1889
+ get: async (lobbyId) => {
1947
1890
  if (!serverCache.has(lobbyId)) {
1948
1891
  const server = await options.partyFn(lobbyId);
1949
1892
  serverCache.set(lobbyId, new MockLobby(server, lobbyId));
1950
1893
  }
1951
1894
  return serverCache.get(lobbyId);
1952
- }, "get")
1895
+ }
1953
1896
  };
1954
1897
  } else {
1955
1898
  for (let lobbyId in parties) {
@@ -1959,15 +1902,7 @@ var MockContext = class MockContext2 {
1959
1902
  }
1960
1903
  }
1961
1904
  };
1962
- var MockPartyRoom = class MockPartyRoom2 {
1963
- static {
1964
- __name(this, "MockPartyRoom");
1965
- }
1966
- id;
1967
- clients;
1968
- storage;
1969
- context;
1970
- env;
1905
+ var MockPartyRoom = class {
1971
1906
  constructor(id2, options = {}) {
1972
1907
  this.id = id2;
1973
1908
  this.clients = /* @__PURE__ */ new Map();
@@ -1995,9 +1930,7 @@ var MockPartyRoom = class MockPartyRoom2 {
1995
1930
  ...opts?.headers || {}
1996
1931
  }
1997
1932
  });
1998
- await server.onConnect(socket.conn, {
1999
- request: request2
2000
- });
1933
+ await server.onConnect(socket.conn, { request: request2 });
2001
1934
  this.clients.set(socket.id, socket);
2002
1935
  return socket;
2003
1936
  }
@@ -2017,19 +1950,12 @@ var MockPartyRoom = class MockPartyRoom2 {
2017
1950
  }
2018
1951
  };
2019
1952
  var MockConnection = class {
2020
- static {
2021
- __name(this, "MockConnection");
2022
- }
2023
- client;
2024
- server;
2025
- id;
2026
1953
  constructor(client) {
2027
1954
  this.client = client;
2028
1955
  this.state = {};
2029
1956
  this.server = client.server;
2030
1957
  this.id = client.id;
2031
1958
  }
2032
- state;
2033
1959
  setState(value) {
2034
1960
  this.state = value;
2035
1961
  }
@@ -2048,17 +1974,8 @@ import { signal } from "@signe/reactive";
2048
1974
  import { sync, id, persist } from "@signe/sync";
2049
1975
  import { z as z2 } from "zod";
2050
1976
 
2051
- // src/types/party.ts
2052
- var party_exports = {};
2053
-
2054
1977
  // src/jwt.ts
2055
1978
  var JWTAuth = class {
2056
- static {
2057
- __name(this, "JWTAuth");
2058
- }
2059
- secret;
2060
- encoder;
2061
- decoder;
2062
1979
  /**
2063
1980
  * Constructor for the JWTAuth class
2064
1981
  * @param {string} secret - The secret key used for signing and verifying tokens
@@ -2079,18 +1996,16 @@ var JWTAuth = class {
2079
1996
  const keyData = this.encoder.encode(this.secret);
2080
1997
  return await crypto.subtle.importKey(
2081
1998
  "raw",
1999
+ // format
2082
2000
  keyData,
2001
+ // key data
2083
2002
  {
2084
2003
  name: "HMAC",
2085
- hash: {
2086
- name: "SHA-256"
2087
- }
2004
+ hash: { name: "SHA-256" }
2088
2005
  },
2089
2006
  false,
2090
- [
2091
- "sign",
2092
- "verify"
2093
- ]
2007
+ // extractable
2008
+ ["sign", "verify"]
2094
2009
  // key usages
2095
2010
  );
2096
2011
  }
@@ -2162,9 +2077,11 @@ var JWTAuth = class {
2162
2077
  const encodedPayload = this.base64UrlEncode(this.encoder.encode(JSON.stringify(fullPayload)));
2163
2078
  const signatureBase = `${encodedHeader}.${encodedPayload}`;
2164
2079
  const key = await this.getSecretKey();
2165
- const signature = await crypto.subtle.sign({
2166
- name: "HMAC"
2167
- }, key, this.encoder.encode(signatureBase));
2080
+ const signature = await crypto.subtle.sign(
2081
+ { name: "HMAC" },
2082
+ key,
2083
+ this.encoder.encode(signatureBase)
2084
+ );
2168
2085
  const encodedSignature = this.base64UrlEncode(signature);
2169
2086
  return `${signatureBase}.${encodedSignature}`;
2170
2087
  }
@@ -2196,9 +2113,12 @@ var JWTAuth = class {
2196
2113
  const key = await this.getSecretKey();
2197
2114
  const signatureBase = `${encodedHeader}.${encodedPayload}`;
2198
2115
  const signature = this.base64UrlDecode(encodedSignature);
2199
- const isValid = await crypto.subtle.verify({
2200
- name: "HMAC"
2201
- }, key, signature, this.encoder.encode(signatureBase));
2116
+ const isValid = await crypto.subtle.verify(
2117
+ { name: "HMAC" },
2118
+ key,
2119
+ signature,
2120
+ this.encoder.encode(signatureBase)
2121
+ );
2202
2122
  if (!isValid) {
2203
2123
  throw new Error("Invalid signature");
2204
2124
  }
@@ -2213,7 +2133,7 @@ var JWTAuth = class {
2213
2133
  };
2214
2134
 
2215
2135
  // src/world.guard.ts
2216
- var guardManageWorld = /* @__PURE__ */ __name(async (_, req, room) => {
2136
+ var guardManageWorld = async (_, req, room) => {
2217
2137
  const tokenShard = req.headers.get("x-access-shard");
2218
2138
  if (tokenShard) {
2219
2139
  if (tokenShard !== room.env.SHARD_SECRET) {
@@ -2236,46 +2156,22 @@ var guardManageWorld = /* @__PURE__ */ __name(async (_, req, room) => {
2236
2156
  return false;
2237
2157
  }
2238
2158
  return true;
2239
- }, "guardManageWorld");
2159
+ };
2240
2160
 
2241
2161
  // src/world.ts
2242
- function _ts_decorate(decorators, target, key, desc) {
2243
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2244
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
2245
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
2246
- return c > 3 && r && Object.defineProperty(target, key, r), r;
2247
- }
2248
- __name(_ts_decorate, "_ts_decorate");
2249
- function _ts_metadata(k, v) {
2250
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
2251
- }
2252
- __name(_ts_metadata, "_ts_metadata");
2253
2162
  var MAX_PLAYERS_PER_SHARD = 75;
2254
2163
  var RoomConfigSchema = z2.object({
2255
2164
  name: z2.string(),
2256
- balancingStrategy: z2.enum([
2257
- "round-robin",
2258
- "least-connections",
2259
- "random"
2260
- ]),
2165
+ balancingStrategy: z2.enum(["round-robin", "least-connections", "random"]),
2261
2166
  public: z2.boolean(),
2262
2167
  maxPlayersPerShard: z2.number().int().positive(),
2263
2168
  minShards: z2.number().int().min(0),
2264
2169
  maxShards: z2.number().int().positive().optional()
2265
2170
  });
2266
- var RegisterShardSchema = z2.object({
2267
- shardId: z2.string(),
2268
- roomId: z2.string(),
2269
- url: z2.string().url(),
2270
- maxConnections: z2.number().int().positive()
2271
- });
2272
2171
  var UpdateShardStatsSchema = z2.object({
2172
+ shardId: z2.string(),
2273
2173
  connections: z2.number().int().min(0),
2274
- status: z2.enum([
2275
- "active",
2276
- "maintenance",
2277
- "draining"
2278
- ]).optional()
2174
+ status: z2.enum(["active", "maintenance", "draining"]).optional()
2279
2175
  });
2280
2176
  var ScaleRoomSchema = z2.object({
2281
2177
  roomId: z2.string(),
@@ -2285,94 +2181,77 @@ var ScaleRoomSchema = z2.object({
2285
2181
  maxConnections: z2.number().int().positive()
2286
2182
  }).optional()
2287
2183
  });
2288
- var RoomConfig = class RoomConfig2 {
2289
- static {
2290
- __name(this, "RoomConfig");
2291
- }
2292
- id;
2293
- name = signal("");
2294
- balancingStrategy = signal("round-robin");
2295
- public = signal(true);
2296
- maxPlayersPerShard = signal(MAX_PLAYERS_PER_SHARD);
2297
- minShards = signal(1);
2298
- maxShards = signal(void 0);
2184
+ var RoomConfig = class {
2185
+ constructor() {
2186
+ this.name = signal("");
2187
+ this.balancingStrategy = signal("round-robin");
2188
+ this.public = signal(true);
2189
+ this.maxPlayersPerShard = signal(MAX_PLAYERS_PER_SHARD);
2190
+ this.minShards = signal(1);
2191
+ this.maxShards = signal(void 0);
2192
+ }
2299
2193
  };
2300
- _ts_decorate([
2301
- id(),
2302
- _ts_metadata("design:type", String)
2303
- ], RoomConfig.prototype, "id", void 0);
2304
- _ts_decorate([
2194
+ __decorateClass([
2195
+ id()
2196
+ ], RoomConfig.prototype, "id", 2);
2197
+ __decorateClass([
2305
2198
  sync()
2306
- ], RoomConfig.prototype, "name", void 0);
2307
- _ts_decorate([
2199
+ ], RoomConfig.prototype, "name", 2);
2200
+ __decorateClass([
2308
2201
  sync()
2309
- ], RoomConfig.prototype, "balancingStrategy", void 0);
2310
- _ts_decorate([
2202
+ ], RoomConfig.prototype, "balancingStrategy", 2);
2203
+ __decorateClass([
2311
2204
  sync()
2312
- ], RoomConfig.prototype, "public", void 0);
2313
- _ts_decorate([
2205
+ ], RoomConfig.prototype, "public", 2);
2206
+ __decorateClass([
2314
2207
  sync()
2315
- ], RoomConfig.prototype, "maxPlayersPerShard", void 0);
2316
- _ts_decorate([
2208
+ ], RoomConfig.prototype, "maxPlayersPerShard", 2);
2209
+ __decorateClass([
2317
2210
  sync()
2318
- ], RoomConfig.prototype, "minShards", void 0);
2319
- _ts_decorate([
2211
+ ], RoomConfig.prototype, "minShards", 2);
2212
+ __decorateClass([
2320
2213
  sync()
2321
- ], RoomConfig.prototype, "maxShards", void 0);
2322
- var ShardInfo = class ShardInfo2 {
2323
- static {
2324
- __name(this, "ShardInfo");
2325
- }
2326
- id;
2327
- roomId = signal("");
2328
- url = signal("");
2329
- currentConnections = signal(0);
2330
- maxConnections = signal(MAX_PLAYERS_PER_SHARD);
2331
- status = signal("active");
2332
- lastHeartbeat = signal(0);
2214
+ ], RoomConfig.prototype, "maxShards", 2);
2215
+ var ShardInfo = class {
2216
+ constructor() {
2217
+ this.roomId = signal("");
2218
+ this.url = signal("");
2219
+ this.currentConnections = signal(0);
2220
+ this.maxConnections = signal(MAX_PLAYERS_PER_SHARD);
2221
+ this.status = signal("active");
2222
+ this.lastHeartbeat = signal(0);
2223
+ }
2333
2224
  };
2334
- _ts_decorate([
2335
- id(),
2336
- _ts_metadata("design:type", String)
2337
- ], ShardInfo.prototype, "id", void 0);
2338
- _ts_decorate([
2225
+ __decorateClass([
2226
+ id()
2227
+ ], ShardInfo.prototype, "id", 2);
2228
+ __decorateClass([
2339
2229
  sync()
2340
- ], ShardInfo.prototype, "roomId", void 0);
2341
- _ts_decorate([
2230
+ ], ShardInfo.prototype, "roomId", 2);
2231
+ __decorateClass([
2342
2232
  sync()
2343
- ], ShardInfo.prototype, "url", void 0);
2344
- _ts_decorate([
2233
+ ], ShardInfo.prototype, "url", 2);
2234
+ __decorateClass([
2345
2235
  sync({
2346
2236
  persist: false
2347
2237
  })
2348
- ], ShardInfo.prototype, "currentConnections", void 0);
2349
- _ts_decorate([
2238
+ ], ShardInfo.prototype, "currentConnections", 2);
2239
+ __decorateClass([
2350
2240
  sync()
2351
- ], ShardInfo.prototype, "maxConnections", void 0);
2352
- _ts_decorate([
2241
+ ], ShardInfo.prototype, "maxConnections", 2);
2242
+ __decorateClass([
2353
2243
  sync()
2354
- ], ShardInfo.prototype, "status", void 0);
2355
- _ts_decorate([
2244
+ ], ShardInfo.prototype, "status", 2);
2245
+ __decorateClass([
2356
2246
  sync()
2357
- ], ShardInfo.prototype, "lastHeartbeat", void 0);
2247
+ ], ShardInfo.prototype, "lastHeartbeat", 2);
2358
2248
  var WorldRoom = class {
2359
- static {
2360
- __name(this, "WorldRoom");
2361
- }
2362
- room;
2363
- // Synchronized state
2364
- rooms;
2365
- shards;
2366
- // Only persisted state (not synced to clients)
2367
- rrCounters;
2368
- // Configuration
2369
- defaultShardUrlTemplate;
2370
- defaultMaxConnectionsPerShard;
2371
2249
  constructor(room) {
2372
2250
  this.room = room;
2373
2251
  this.rooms = signal({});
2374
2252
  this.shards = signal({});
2375
2253
  this.rrCounters = signal({});
2254
+ // Configuration
2376
2255
  this.defaultShardUrlTemplate = signal("{shardId}");
2377
2256
  this.defaultMaxConnectionsPerShard = signal(MAX_PLAYERS_PER_SHARD);
2378
2257
  const { AUTH_JWT_SECRET, SHARD_SECRET } = this.room.env;
@@ -2410,9 +2289,14 @@ var WorldRoom = class {
2410
2289
  });
2411
2290
  setTimeout(() => this.cleanupInactiveShards(), 6e4);
2412
2291
  }
2413
- // Actions
2414
- async registerRoom(req) {
2415
- const roomConfig = await req.json();
2292
+ async registerRoom(req, res) {
2293
+ const roomConfigResult = RoomConfigSchema.safeParse(await req.json());
2294
+ if (!roomConfigResult.success) {
2295
+ return res?.badRequest("Invalid room configuration", {
2296
+ details: roomConfigResult.error
2297
+ });
2298
+ }
2299
+ const roomConfig = roomConfigResult.data;
2416
2300
  const roomId = roomConfig.name;
2417
2301
  if (!this.rooms()[roomId]) {
2418
2302
  const newRoom = new RoomConfig();
@@ -2439,7 +2323,13 @@ var WorldRoom = class {
2439
2323
  }
2440
2324
  }
2441
2325
  async updateShardStats(req, res) {
2442
- const body = await req.json();
2326
+ const bodyResult = UpdateShardStatsSchema.safeParse(await req.json());
2327
+ if (!bodyResult.success) {
2328
+ return res.badRequest("Invalid shard statistics", {
2329
+ details: bodyResult.error
2330
+ });
2331
+ }
2332
+ const body = bodyResult.data;
2443
2333
  const { shardId, connections, status } = body;
2444
2334
  const shard = this.shards()[shardId];
2445
2335
  if (!shard) {
@@ -2452,7 +2342,13 @@ var WorldRoom = class {
2452
2342
  shard.lastHeartbeat.set(Date.now());
2453
2343
  }
2454
2344
  async scaleRoom(req, res) {
2455
- const data = await req.json();
2345
+ const dataResult = ScaleRoomSchema.safeParse(await req.json());
2346
+ if (!dataResult.success) {
2347
+ return res.badRequest("Invalid scale request", {
2348
+ details: dataResult.error
2349
+ });
2350
+ }
2351
+ const data = dataResult.data;
2456
2352
  const { targetShardCount, shardTemplate, roomId } = data;
2457
2353
  const room = this.rooms()[roomId];
2458
2354
  if (!room) {
@@ -2467,14 +2363,11 @@ var WorldRoom = class {
2467
2363
  });
2468
2364
  }
2469
2365
  if (targetShardCount < previousShardCount) {
2470
- const shardsToRemove = [
2471
- ...roomShards
2472
- ].sort((a, b) => {
2366
+ const shardsToRemove = [...roomShards].sort((a, b) => {
2473
2367
  if (a.status() === "draining" && b.status() !== "draining") return -1;
2474
2368
  if (a.status() !== "draining" && b.status() === "draining") return 1;
2475
2369
  return a.currentConnections() - b.currentConnections();
2476
2370
  }).slice(0, previousShardCount - targetShardCount);
2477
- const shardsToKeep = roomShards.filter((shard) => !shardsToRemove.some((s) => s.id === shard.id));
2478
2371
  for (const shard of shardsToRemove) {
2479
2372
  delete this.shards()[shard.id];
2480
2373
  }
@@ -2483,7 +2376,11 @@ var WorldRoom = class {
2483
2376
  if (targetShardCount > previousShardCount) {
2484
2377
  const newShards = [];
2485
2378
  for (let i = 0; i < targetShardCount - previousShardCount; i++) {
2486
- const newShard = await this.createShard(roomId, shardTemplate?.urlTemplate, shardTemplate?.maxConnections);
2379
+ const newShard = await this.createShard(
2380
+ roomId,
2381
+ shardTemplate?.urlTemplate,
2382
+ shardTemplate?.maxConnections
2383
+ );
2487
2384
  if (newShard) {
2488
2385
  newShards.push(newShard);
2489
2386
  }
@@ -2525,26 +2422,22 @@ var WorldRoom = class {
2525
2422
  if (!room) {
2526
2423
  if (autoCreate) {
2527
2424
  const mockRequest = {
2528
- json: /* @__PURE__ */ __name(async () => ({
2425
+ json: async () => ({
2529
2426
  name: roomId,
2530
2427
  balancingStrategy: "round-robin",
2531
2428
  public: true,
2532
2429
  maxPlayersPerShard: this.defaultMaxConnectionsPerShard(),
2533
2430
  minShards: 1,
2534
2431
  maxShards: void 0
2535
- }), "json")
2432
+ })
2536
2433
  };
2537
2434
  await this.registerRoom(mockRequest);
2538
2435
  room = this.rooms()[roomId];
2539
2436
  if (!room) {
2540
- return {
2541
- error: `Failed to create room ${roomId}`
2542
- };
2437
+ return { error: `Failed to create room ${roomId}` };
2543
2438
  }
2544
2439
  } else {
2545
- return {
2546
- error: `Room ${roomId} does not exist`
2547
- };
2440
+ return { error: `Room ${roomId} does not exist` };
2548
2441
  }
2549
2442
  }
2550
2443
  const roomShards = Object.values(this.shards()).filter((shard) => shard.roomId() === roomId);
@@ -2557,27 +2450,24 @@ var WorldRoom = class {
2557
2450
  url: newShard.url()
2558
2451
  };
2559
2452
  } else {
2560
- return {
2561
- error: `Failed to create shard for room ${roomId}`
2562
- };
2453
+ return { error: `Failed to create shard for room ${roomId}` };
2563
2454
  }
2564
2455
  } else {
2565
- return {
2566
- error: `No shards available for room ${roomId}`
2567
- };
2456
+ return { error: `No shards available for room ${roomId}` };
2568
2457
  }
2569
2458
  }
2570
2459
  const activeShards = roomShards.filter((shard) => shard && shard.status() === "active");
2571
2460
  if (activeShards.length === 0) {
2572
- return {
2573
- error: `No active shards available for room ${roomId}`
2574
- };
2461
+ return { error: `No active shards available for room ${roomId}` };
2575
2462
  }
2576
2463
  const balancingStrategy = room.balancingStrategy();
2577
2464
  let selectedShard;
2578
2465
  switch (balancingStrategy) {
2579
2466
  case "least-connections":
2580
- selectedShard = activeShards.reduce((min, shard) => shard.currentConnections() < min.currentConnections() ? shard : min, activeShards[0]);
2467
+ selectedShard = activeShards.reduce(
2468
+ (min, shard) => shard.currentConnections() < min.currentConnections() ? shard : min,
2469
+ activeShards[0]
2470
+ );
2581
2471
  break;
2582
2472
  case "random":
2583
2473
  selectedShard = activeShards[Math.floor(Math.random() * activeShards.length)];
@@ -2618,82 +2508,52 @@ var WorldRoom = class {
2618
2508
  return newShard;
2619
2509
  }
2620
2510
  };
2621
- _ts_decorate([
2511
+ __decorateClass([
2622
2512
  sync(RoomConfig)
2623
- ], WorldRoom.prototype, "rooms", void 0);
2624
- _ts_decorate([
2513
+ ], WorldRoom.prototype, "rooms", 2);
2514
+ __decorateClass([
2625
2515
  sync(ShardInfo)
2626
- ], WorldRoom.prototype, "shards", void 0);
2627
- _ts_decorate([
2516
+ ], WorldRoom.prototype, "shards", 2);
2517
+ __decorateClass([
2628
2518
  persist()
2629
- ], WorldRoom.prototype, "rrCounters", void 0);
2630
- _ts_decorate([
2519
+ ], WorldRoom.prototype, "rrCounters", 2);
2520
+ __decorateClass([
2631
2521
  Request2({
2632
2522
  path: "register-room",
2633
2523
  method: "POST"
2634
2524
  }),
2635
- Guard([
2636
- guardManageWorld
2637
- ]),
2638
- _ts_metadata("design:type", Function),
2639
- _ts_metadata("design:paramtypes", [
2640
- typeof party_exports === "undefined" || typeof void 0 === "undefined" ? Object : void 0
2641
- ]),
2642
- _ts_metadata("design:returntype", Promise)
2643
- ], WorldRoom.prototype, "registerRoom", null);
2644
- _ts_decorate([
2525
+ Guard([guardManageWorld])
2526
+ ], WorldRoom.prototype, "registerRoom", 1);
2527
+ __decorateClass([
2645
2528
  Request2({
2646
2529
  path: "update-shard",
2647
2530
  method: "POST"
2648
2531
  }),
2649
- Guard([
2650
- guardManageWorld
2651
- ]),
2652
- _ts_metadata("design:type", Function),
2653
- _ts_metadata("design:paramtypes", [
2654
- typeof party_exports === "undefined" || typeof void 0 === "undefined" ? Object : void 0,
2655
- typeof ServerResponse === "undefined" ? Object : ServerResponse
2656
- ]),
2657
- _ts_metadata("design:returntype", Promise)
2658
- ], WorldRoom.prototype, "updateShardStats", null);
2659
- _ts_decorate([
2532
+ Guard([guardManageWorld])
2533
+ ], WorldRoom.prototype, "updateShardStats", 1);
2534
+ __decorateClass([
2660
2535
  Request2({
2661
2536
  path: "scale-room",
2662
2537
  method: "POST"
2663
2538
  }),
2664
- Guard([
2665
- guardManageWorld
2666
- ]),
2667
- _ts_metadata("design:type", Function),
2668
- _ts_metadata("design:paramtypes", [
2669
- typeof party_exports === "undefined" || typeof void 0 === "undefined" ? Object : void 0,
2670
- typeof ServerResponse === "undefined" ? Object : ServerResponse
2671
- ]),
2672
- _ts_metadata("design:returntype", Promise)
2673
- ], WorldRoom.prototype, "scaleRoom", null);
2674
- _ts_decorate([
2539
+ Guard([guardManageWorld])
2540
+ ], WorldRoom.prototype, "scaleRoom", 1);
2541
+ __decorateClass([
2675
2542
  Request2({
2676
2543
  path: "connect",
2677
2544
  method: "POST"
2678
- }),
2679
- _ts_metadata("design:type", Function),
2680
- _ts_metadata("design:paramtypes", [
2681
- typeof party_exports === "undefined" || typeof void 0 === "undefined" ? Object : void 0,
2682
- typeof ServerResponse === "undefined" ? Object : ServerResponse
2683
- ]),
2684
- _ts_metadata("design:returntype", Promise)
2685
- ], WorldRoom.prototype, "connect", null);
2686
- WorldRoom = _ts_decorate([
2545
+ })
2546
+ ], WorldRoom.prototype, "connect", 1);
2547
+ WorldRoom = __decorateClass([
2687
2548
  Room({
2688
2549
  path: "world-{worldId}",
2689
2550
  maxUsers: 100,
2551
+ // Limit for admin connections
2690
2552
  throttleStorage: 2e3,
2553
+ // Throttle storage updates (ms)
2691
2554
  throttleSync: 500
2692
- }),
2693
- _ts_metadata("design:type", Function),
2694
- _ts_metadata("design:paramtypes", [
2695
- typeof party_exports === "undefined" || typeof void 0 === "undefined" ? Object : void 0
2696
- ])
2555
+ // Throttle sync updates (ms)
2556
+ })
2697
2557
  ], WorldRoom);
2698
2558
 
2699
2559
  // src/session.guard.ts
@@ -2718,8 +2578,7 @@ function createRequireSessionGuard(storage) {
2718
2578
  }
2719
2579
  };
2720
2580
  }
2721
- __name(createRequireSessionGuard, "createRequireSessionGuard");
2722
- var requireSession = /* @__PURE__ */ __name(async (sender, value, room) => {
2581
+ var requireSession = async (sender, value, room) => {
2723
2582
  if (!sender || !sender.id) {
2724
2583
  return false;
2725
2584
  }
@@ -2737,7 +2596,7 @@ var requireSession = /* @__PURE__ */ __name(async (sender, value, room) => {
2737
2596
  console.error("Error checking session in requireSession guard:", error);
2738
2597
  return false;
2739
2598
  }
2740
- }, "requireSession");
2599
+ };
2741
2600
  export {
2742
2601
  Action,
2743
2602
  ClientIo,