@signe/room 2.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +121 -14
- package/dist/index.js +308 -97
- package/dist/index.js.map +1 -1
- package/examples/game/app/components/Room.tsx +2 -2
- package/package.json +2 -2
- package/readme.md +21 -16
- package/src/index.ts +2 -1
- package/src/request/cors.ts +58 -0
- package/src/request/response.ts +228 -0
- package/src/server.ts +43 -45
- package/src/world.ts +15 -15
package/dist/index.js
CHANGED
|
@@ -326,6 +326,260 @@ function response(status, body) {
|
|
|
326
326
|
}
|
|
327
327
|
__name(response, "response");
|
|
328
328
|
|
|
329
|
+
// src/request/response.ts
|
|
330
|
+
var ServerResponse = class {
|
|
331
|
+
static {
|
|
332
|
+
__name(this, "ServerResponse");
|
|
333
|
+
}
|
|
334
|
+
interceptors;
|
|
335
|
+
statusCode = 200;
|
|
336
|
+
responseBody = {};
|
|
337
|
+
responseHeaders = {
|
|
338
|
+
"Content-Type": "application/json"
|
|
339
|
+
};
|
|
340
|
+
/**
|
|
341
|
+
* Creates a new ServerResponse instance
|
|
342
|
+
* @param interceptors Array of interceptor functions that can modify the response
|
|
343
|
+
*/
|
|
344
|
+
constructor(interceptors = []) {
|
|
345
|
+
this.interceptors = interceptors;
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* Sets the status code for the response
|
|
349
|
+
* @param code HTTP status code
|
|
350
|
+
* @returns this instance for chaining
|
|
351
|
+
*/
|
|
352
|
+
status(code) {
|
|
353
|
+
this.statusCode = code;
|
|
354
|
+
return this;
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* Sets the response body and returns this instance (chainable method)
|
|
358
|
+
*
|
|
359
|
+
* @param body Response body
|
|
360
|
+
* @returns this instance for chaining
|
|
361
|
+
*/
|
|
362
|
+
body(body) {
|
|
363
|
+
this.responseBody = body;
|
|
364
|
+
return this;
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Adds a header to the response
|
|
368
|
+
* @param name Header name
|
|
369
|
+
* @param value Header value
|
|
370
|
+
* @returns this instance for chaining
|
|
371
|
+
*/
|
|
372
|
+
header(name, value) {
|
|
373
|
+
this.responseHeaders[name] = value;
|
|
374
|
+
return this;
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* Adds multiple headers to the response
|
|
378
|
+
* @param headers Object containing headers
|
|
379
|
+
* @returns this instance for chaining
|
|
380
|
+
*/
|
|
381
|
+
setHeaders(headers) {
|
|
382
|
+
this.responseHeaders = {
|
|
383
|
+
...this.responseHeaders,
|
|
384
|
+
...headers
|
|
385
|
+
};
|
|
386
|
+
return this;
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* Add an interceptor to the chain
|
|
390
|
+
* @param interceptor Function that takes a Response and returns a modified Response
|
|
391
|
+
* @returns this instance for chaining
|
|
392
|
+
*/
|
|
393
|
+
use(interceptor) {
|
|
394
|
+
this.interceptors.push(interceptor);
|
|
395
|
+
return this;
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Builds and returns the Response object after applying all interceptors
|
|
399
|
+
* @returns Promise<Response> The final Response object
|
|
400
|
+
* @private Internal method used by terminal methods
|
|
401
|
+
*/
|
|
402
|
+
async buildResponse() {
|
|
403
|
+
let response2 = new Response(JSON.stringify(this.responseBody), {
|
|
404
|
+
status: this.statusCode,
|
|
405
|
+
headers: this.responseHeaders
|
|
406
|
+
});
|
|
407
|
+
for (const interceptor of this.interceptors) {
|
|
408
|
+
try {
|
|
409
|
+
const interceptedResponse = interceptor(response2);
|
|
410
|
+
if (interceptedResponse instanceof Promise) {
|
|
411
|
+
response2 = await interceptedResponse;
|
|
412
|
+
} else {
|
|
413
|
+
response2 = interceptedResponse;
|
|
414
|
+
}
|
|
415
|
+
} catch (error) {
|
|
416
|
+
console.error("Error in interceptor:", error);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
return response2;
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* Sets the response body to the JSON-stringified version of the provided value
|
|
423
|
+
* and sends the response (terminal method)
|
|
424
|
+
*
|
|
425
|
+
* @param body Response body to be JSON stringified
|
|
426
|
+
* @returns Promise<Response> The final Response object
|
|
427
|
+
*/
|
|
428
|
+
async json(body) {
|
|
429
|
+
this.responseBody = body;
|
|
430
|
+
this.responseHeaders["Content-Type"] = "application/json";
|
|
431
|
+
return this.buildResponse();
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* Sends the response with the current configuration (terminal method)
|
|
435
|
+
*
|
|
436
|
+
* @param body Optional body to set before sending
|
|
437
|
+
* @returns Promise<Response> The final Response object
|
|
438
|
+
*/
|
|
439
|
+
async send(body) {
|
|
440
|
+
if (body !== void 0) {
|
|
441
|
+
this.responseBody = body;
|
|
442
|
+
}
|
|
443
|
+
return this.buildResponse();
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* Sends a plain text response (terminal method)
|
|
447
|
+
*
|
|
448
|
+
* @param text Text to send
|
|
449
|
+
* @returns Promise<Response> The final Response object
|
|
450
|
+
*/
|
|
451
|
+
async text(text) {
|
|
452
|
+
this.responseBody = text;
|
|
453
|
+
this.responseHeaders["Content-Type"] = "text/plain";
|
|
454
|
+
let response2 = new Response(text, {
|
|
455
|
+
status: this.statusCode,
|
|
456
|
+
headers: this.responseHeaders
|
|
457
|
+
});
|
|
458
|
+
for (const interceptor of this.interceptors) {
|
|
459
|
+
try {
|
|
460
|
+
const interceptedResponse = interceptor(response2);
|
|
461
|
+
if (interceptedResponse instanceof Promise) {
|
|
462
|
+
response2 = await interceptedResponse;
|
|
463
|
+
} else {
|
|
464
|
+
response2 = interceptedResponse;
|
|
465
|
+
}
|
|
466
|
+
} catch (error) {
|
|
467
|
+
console.error("Error in interceptor:", error);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
return response2;
|
|
471
|
+
}
|
|
472
|
+
/**
|
|
473
|
+
* Redirects to the specified URL (terminal method)
|
|
474
|
+
*
|
|
475
|
+
* @param url URL to redirect to
|
|
476
|
+
* @param statusCode HTTP status code (default: 302)
|
|
477
|
+
* @returns Promise<Response> The final Response object
|
|
478
|
+
*/
|
|
479
|
+
async redirect(url, statusCode = 302) {
|
|
480
|
+
this.statusCode = statusCode;
|
|
481
|
+
this.responseHeaders["Location"] = url;
|
|
482
|
+
return this.buildResponse();
|
|
483
|
+
}
|
|
484
|
+
/**
|
|
485
|
+
* Creates a success response with status 200
|
|
486
|
+
* @param body Response body
|
|
487
|
+
* @returns Promise<Response> The final Response object
|
|
488
|
+
*/
|
|
489
|
+
async success(body = {}) {
|
|
490
|
+
return this.status(200).json(body);
|
|
491
|
+
}
|
|
492
|
+
/**
|
|
493
|
+
* Creates an error response with status 400
|
|
494
|
+
* @param message Error message
|
|
495
|
+
* @param details Additional error details
|
|
496
|
+
* @returns Promise<Response> The final Response object
|
|
497
|
+
*/
|
|
498
|
+
async badRequest(message, details = {}) {
|
|
499
|
+
return this.status(400).json({
|
|
500
|
+
error: message,
|
|
501
|
+
...details
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
/**
|
|
505
|
+
* Creates an error response with status 403
|
|
506
|
+
* @param message Error message
|
|
507
|
+
* @returns Promise<Response> The final Response object
|
|
508
|
+
*/
|
|
509
|
+
async notPermitted(message = "Not permitted") {
|
|
510
|
+
return this.status(403).json({
|
|
511
|
+
error: message
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* Creates an error response with status 401
|
|
516
|
+
* @param message Error message
|
|
517
|
+
* @returns Promise<Response> The final Response object
|
|
518
|
+
*/
|
|
519
|
+
async unauthorized(message = "Unauthorized") {
|
|
520
|
+
return this.status(401).json({
|
|
521
|
+
error: message
|
|
522
|
+
});
|
|
523
|
+
}
|
|
524
|
+
/**
|
|
525
|
+
* Creates an error response with status 404
|
|
526
|
+
* @param message Error message
|
|
527
|
+
* @returns Promise<Response> The final Response object
|
|
528
|
+
*/
|
|
529
|
+
async notFound(message = "Not found") {
|
|
530
|
+
return this.status(404).json({
|
|
531
|
+
error: message
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
/**
|
|
535
|
+
* Creates an error response with status 500
|
|
536
|
+
* @param message Error message
|
|
537
|
+
* @returns Promise<Response> The final Response object
|
|
538
|
+
*/
|
|
539
|
+
async serverError(message = "Internal Server Error") {
|
|
540
|
+
return this.status(500).json({
|
|
541
|
+
error: message
|
|
542
|
+
});
|
|
543
|
+
}
|
|
544
|
+
};
|
|
545
|
+
|
|
546
|
+
// src/request/cors.ts
|
|
547
|
+
function cors(res, options = {}) {
|
|
548
|
+
const newHeaders = new Headers(res.headers);
|
|
549
|
+
const requestOrigin = options.origin || "*";
|
|
550
|
+
newHeaders.set("Access-Control-Allow-Origin", requestOrigin);
|
|
551
|
+
if (options.credentials) {
|
|
552
|
+
newHeaders.set("Access-Control-Allow-Credentials", "true");
|
|
553
|
+
}
|
|
554
|
+
if (options.exposedHeaders && options.exposedHeaders.length) {
|
|
555
|
+
newHeaders.set("Access-Control-Expose-Headers", options.exposedHeaders.join(", "));
|
|
556
|
+
}
|
|
557
|
+
if (options.methods && options.methods.length) {
|
|
558
|
+
newHeaders.set("Access-Control-Allow-Methods", options.methods.join(", "));
|
|
559
|
+
} else {
|
|
560
|
+
newHeaders.set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS");
|
|
561
|
+
}
|
|
562
|
+
if (options.allowedHeaders && options.allowedHeaders.length) {
|
|
563
|
+
newHeaders.set("Access-Control-Allow-Headers", options.allowedHeaders.join(", "));
|
|
564
|
+
} else {
|
|
565
|
+
newHeaders.set("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Requested-With");
|
|
566
|
+
}
|
|
567
|
+
if (options.maxAge) {
|
|
568
|
+
newHeaders.set("Access-Control-Max-Age", options.maxAge.toString());
|
|
569
|
+
} else {
|
|
570
|
+
newHeaders.set("Access-Control-Max-Age", "86400");
|
|
571
|
+
}
|
|
572
|
+
return new Response(res.body, {
|
|
573
|
+
status: res.status,
|
|
574
|
+
headers: newHeaders
|
|
575
|
+
});
|
|
576
|
+
}
|
|
577
|
+
__name(cors, "cors");
|
|
578
|
+
function createCorsInterceptor(options = {}) {
|
|
579
|
+
return (res) => cors(res, options);
|
|
580
|
+
}
|
|
581
|
+
__name(createCorsInterceptor, "createCorsInterceptor");
|
|
582
|
+
|
|
329
583
|
// src/server.ts
|
|
330
584
|
var Message = z.object({
|
|
331
585
|
action: z.string(),
|
|
@@ -727,6 +981,10 @@ var Server = class {
|
|
|
727
981
|
return;
|
|
728
982
|
}
|
|
729
983
|
const subRoom = await this.getSubRoom();
|
|
984
|
+
if (!subRoom) {
|
|
985
|
+
console.warn("Room not found");
|
|
986
|
+
return;
|
|
987
|
+
}
|
|
730
988
|
const roomGuards = subRoom.constructor["_roomGuards"] || [];
|
|
731
989
|
for (const guard of roomGuards) {
|
|
732
990
|
const isAuthorized = await guard(sender, result.data.value, this.room);
|
|
@@ -980,10 +1238,16 @@ var Server = class {
|
|
|
980
1238
|
async onRequest(req) {
|
|
981
1239
|
const isFromShard = req.headers.has("x-forwarded-by-shard");
|
|
982
1240
|
const shardId = req.headers.get("x-shard-id");
|
|
1241
|
+
const res = new ServerResponse([
|
|
1242
|
+
createCorsInterceptor()
|
|
1243
|
+
]);
|
|
1244
|
+
if (req.method === "OPTIONS") {
|
|
1245
|
+
return res.status(200).send({});
|
|
1246
|
+
}
|
|
983
1247
|
if (isFromShard) {
|
|
984
|
-
return this.handleShardRequest(req, shardId);
|
|
1248
|
+
return this.handleShardRequest(req, res, shardId);
|
|
985
1249
|
}
|
|
986
|
-
return this.handleDirectRequest(req);
|
|
1250
|
+
return this.handleDirectRequest(req, res);
|
|
987
1251
|
}
|
|
988
1252
|
/**
|
|
989
1253
|
* @method handleDirectRequest
|
|
@@ -993,32 +1257,23 @@ var Server = class {
|
|
|
993
1257
|
* @description Processes requests received directly from clients
|
|
994
1258
|
* @returns {Promise<Response>} The response to return to the client
|
|
995
1259
|
*/
|
|
996
|
-
async handleDirectRequest(req) {
|
|
1260
|
+
async handleDirectRequest(req, res) {
|
|
997
1261
|
const subRoom = await this.getSubRoom();
|
|
998
|
-
const res = /* @__PURE__ */ __name((body, status) => {
|
|
999
|
-
return new Response(JSON.stringify(body), {
|
|
1000
|
-
status
|
|
1001
|
-
});
|
|
1002
|
-
}, "res");
|
|
1003
1262
|
if (!subRoom) {
|
|
1004
|
-
return res(
|
|
1005
|
-
error: "Not found"
|
|
1006
|
-
}, 404);
|
|
1263
|
+
return res.notFound();
|
|
1007
1264
|
}
|
|
1008
|
-
const response2 = await this.tryMatchRequestHandler(req, subRoom);
|
|
1265
|
+
const response2 = await this.tryMatchRequestHandler(req, res, subRoom);
|
|
1009
1266
|
if (response2) {
|
|
1010
1267
|
return response2;
|
|
1011
1268
|
}
|
|
1012
|
-
const legacyResponse = await awaitReturn(subRoom["onRequest"]?.(req,
|
|
1269
|
+
const legacyResponse = await awaitReturn(subRoom["onRequest"]?.(req, res));
|
|
1013
1270
|
if (!legacyResponse) {
|
|
1014
|
-
return res(
|
|
1015
|
-
error: "Not found"
|
|
1016
|
-
}, 404);
|
|
1271
|
+
return res.notFound();
|
|
1017
1272
|
}
|
|
1018
1273
|
if (legacyResponse instanceof Response) {
|
|
1019
1274
|
return legacyResponse;
|
|
1020
1275
|
}
|
|
1021
|
-
return res(legacyResponse
|
|
1276
|
+
return res.success(legacyResponse);
|
|
1022
1277
|
}
|
|
1023
1278
|
/**
|
|
1024
1279
|
* @method tryMatchRequestHandler
|
|
@@ -1029,7 +1284,7 @@ var Server = class {
|
|
|
1029
1284
|
* @description Attempts to match the request to a registered @Request handler
|
|
1030
1285
|
* @returns {Promise<Response | null>} The response or null if no handler matched
|
|
1031
1286
|
*/
|
|
1032
|
-
async tryMatchRequestHandler(req, subRoom) {
|
|
1287
|
+
async tryMatchRequestHandler(req, res, subRoom) {
|
|
1033
1288
|
const requestHandlers = subRoom.constructor["_requestMetadata"];
|
|
1034
1289
|
if (!requestHandlers) {
|
|
1035
1290
|
return null;
|
|
@@ -1054,11 +1309,7 @@ var Server = class {
|
|
|
1054
1309
|
return isAuthorized;
|
|
1055
1310
|
}
|
|
1056
1311
|
if (!isAuthorized) {
|
|
1057
|
-
return
|
|
1058
|
-
error: "Unauthorized"
|
|
1059
|
-
}), {
|
|
1060
|
-
status: 403
|
|
1061
|
-
});
|
|
1312
|
+
return res.notPermitted();
|
|
1062
1313
|
}
|
|
1063
1314
|
}
|
|
1064
1315
|
let bodyData = null;
|
|
@@ -1073,41 +1324,27 @@ var Server = class {
|
|
|
1073
1324
|
const body = await req.json();
|
|
1074
1325
|
const validation = handler.bodyValidation.safeParse(body);
|
|
1075
1326
|
if (!validation.success) {
|
|
1076
|
-
return
|
|
1077
|
-
error: "Invalid request body",
|
|
1327
|
+
return res.badRequest("Invalid request body", {
|
|
1078
1328
|
details: validation.error
|
|
1079
|
-
}), {
|
|
1080
|
-
status: 400
|
|
1081
1329
|
});
|
|
1082
1330
|
}
|
|
1083
1331
|
bodyData = validation.data;
|
|
1084
1332
|
}
|
|
1085
1333
|
} catch (error) {
|
|
1086
|
-
return
|
|
1087
|
-
error: "Failed to parse request body"
|
|
1088
|
-
}), {
|
|
1089
|
-
status: 400
|
|
1090
|
-
});
|
|
1334
|
+
return res.badRequest("Failed to parse request body");
|
|
1091
1335
|
}
|
|
1092
1336
|
}
|
|
1093
1337
|
try {
|
|
1094
|
-
|
|
1338
|
+
req["data"] = bodyData;
|
|
1339
|
+
req["params"] = params;
|
|
1340
|
+
const result = await awaitReturn(subRoom[handler.key](req, res));
|
|
1095
1341
|
if (result instanceof Response) {
|
|
1096
1342
|
return result;
|
|
1097
1343
|
}
|
|
1098
|
-
return
|
|
1099
|
-
status: 200,
|
|
1100
|
-
headers: {
|
|
1101
|
-
"Content-Type": typeof result === "string" ? "text/plain" : "application/json"
|
|
1102
|
-
}
|
|
1103
|
-
});
|
|
1344
|
+
return res.success(result);
|
|
1104
1345
|
} catch (error) {
|
|
1105
1346
|
console.error("Error executing request handler:", error);
|
|
1106
|
-
return
|
|
1107
|
-
error: "Internal server error"
|
|
1108
|
-
}), {
|
|
1109
|
-
status: 500
|
|
1110
|
-
});
|
|
1347
|
+
return res.serverError();
|
|
1111
1348
|
}
|
|
1112
1349
|
}
|
|
1113
1350
|
}
|
|
@@ -1161,43 +1398,29 @@ var Server = class {
|
|
|
1161
1398
|
* @description Processes requests forwarded by shards, preserving client context
|
|
1162
1399
|
* @returns {Promise<Response>} The response to return to the shard (which will forward it to the client)
|
|
1163
1400
|
*/
|
|
1164
|
-
async handleShardRequest(req, shardId) {
|
|
1401
|
+
async handleShardRequest(req, res, shardId) {
|
|
1165
1402
|
const subRoom = await this.getSubRoom();
|
|
1166
1403
|
if (!subRoom) {
|
|
1167
|
-
return
|
|
1168
|
-
error: "Not found"
|
|
1169
|
-
}), {
|
|
1170
|
-
status: 404
|
|
1171
|
-
});
|
|
1404
|
+
return res.notFound();
|
|
1172
1405
|
}
|
|
1173
1406
|
const originalClientIp = req.headers.get("x-original-client-ip");
|
|
1174
1407
|
const enhancedReq = this.createEnhancedRequest(req, originalClientIp);
|
|
1175
1408
|
try {
|
|
1176
|
-
const response2 = await this.tryMatchRequestHandler(enhancedReq, subRoom);
|
|
1409
|
+
const response2 = await this.tryMatchRequestHandler(enhancedReq, res, subRoom);
|
|
1177
1410
|
if (response2) {
|
|
1178
1411
|
return response2;
|
|
1179
1412
|
}
|
|
1180
|
-
const legacyResponse = await awaitReturn(subRoom["onRequest"]?.(enhancedReq,
|
|
1413
|
+
const legacyResponse = await awaitReturn(subRoom["onRequest"]?.(enhancedReq, res));
|
|
1181
1414
|
if (!legacyResponse) {
|
|
1182
|
-
return
|
|
1183
|
-
error: "Not found"
|
|
1184
|
-
}), {
|
|
1185
|
-
status: 404
|
|
1186
|
-
});
|
|
1415
|
+
return res.notFound();
|
|
1187
1416
|
}
|
|
1188
1417
|
if (legacyResponse instanceof Response) {
|
|
1189
1418
|
return legacyResponse;
|
|
1190
1419
|
}
|
|
1191
|
-
return
|
|
1192
|
-
status: 200
|
|
1193
|
-
});
|
|
1420
|
+
return res.success(legacyResponse);
|
|
1194
1421
|
} catch (error) {
|
|
1195
1422
|
console.error(`Error processing request from shard ${shardId}:`, error);
|
|
1196
|
-
return
|
|
1197
|
-
error: "Internal server error"
|
|
1198
|
-
}), {
|
|
1199
|
-
status: 500
|
|
1200
|
-
});
|
|
1423
|
+
return res.serverError();
|
|
1201
1424
|
}
|
|
1202
1425
|
}
|
|
1203
1426
|
/**
|
|
@@ -1858,14 +2081,12 @@ var WorldRoom = class {
|
|
|
1858
2081
|
room.maxShards.set(roomConfig.maxShards);
|
|
1859
2082
|
}
|
|
1860
2083
|
}
|
|
1861
|
-
async updateShardStats(req) {
|
|
2084
|
+
async updateShardStats(req, res) {
|
|
1862
2085
|
const body = await req.json();
|
|
1863
2086
|
const { shardId, connections, status } = body;
|
|
1864
2087
|
const shard = this.shards()[shardId];
|
|
1865
2088
|
if (!shard) {
|
|
1866
|
-
return {
|
|
1867
|
-
error: `Shard ${shardId} not found`
|
|
1868
|
-
};
|
|
2089
|
+
return res.notFound(`Shard ${shardId} not found`);
|
|
1869
2090
|
}
|
|
1870
2091
|
shard.currentConnections.set(connections);
|
|
1871
2092
|
if (status) {
|
|
@@ -1873,23 +2094,20 @@ var WorldRoom = class {
|
|
|
1873
2094
|
}
|
|
1874
2095
|
shard.lastHeartbeat.set(Date.now());
|
|
1875
2096
|
}
|
|
1876
|
-
async scaleRoom(req) {
|
|
2097
|
+
async scaleRoom(req, res) {
|
|
1877
2098
|
const data = await req.json();
|
|
1878
2099
|
const { targetShardCount, shardTemplate, roomId } = data;
|
|
1879
2100
|
const room = this.rooms()[roomId];
|
|
1880
2101
|
if (!room) {
|
|
1881
|
-
return {
|
|
1882
|
-
error: `Room ${roomId} does not exist`
|
|
1883
|
-
};
|
|
2102
|
+
return res.notFound(`Room ${roomId} does not exist`);
|
|
1884
2103
|
}
|
|
1885
2104
|
const roomShards = Object.values(this.shards()).filter((shard) => shard.roomId() === roomId);
|
|
1886
2105
|
const previousShardCount = roomShards.length;
|
|
1887
2106
|
if (room.maxShards() !== void 0 && targetShardCount > room.maxShards()) {
|
|
1888
|
-
return {
|
|
1889
|
-
error: `Cannot scale beyond maximum allowed shards (${room.maxShards()})`,
|
|
2107
|
+
return res.badRequest(`Cannot scale beyond maximum allowed shards (${room.maxShards()})`, {
|
|
1890
2108
|
roomId,
|
|
1891
2109
|
currentShardCount: previousShardCount
|
|
1892
|
-
};
|
|
2110
|
+
});
|
|
1893
2111
|
}
|
|
1894
2112
|
if (targetShardCount < previousShardCount) {
|
|
1895
2113
|
const shardsToRemove = [
|
|
@@ -1915,45 +2133,34 @@ var WorldRoom = class {
|
|
|
1915
2133
|
}
|
|
1916
2134
|
}
|
|
1917
2135
|
}
|
|
1918
|
-
async connect(req) {
|
|
2136
|
+
async connect(req, res) {
|
|
1919
2137
|
try {
|
|
1920
2138
|
let data;
|
|
1921
2139
|
try {
|
|
1922
2140
|
const body = await req.text();
|
|
1923
2141
|
if (!body || body.trim() === "") {
|
|
1924
|
-
return
|
|
1925
|
-
error: "Request body is empty"
|
|
1926
|
-
});
|
|
2142
|
+
return res.badRequest("Request body is empty");
|
|
1927
2143
|
}
|
|
1928
2144
|
data = JSON.parse(body);
|
|
1929
2145
|
} catch (parseError) {
|
|
1930
|
-
return
|
|
1931
|
-
error: "Invalid JSON in request body"
|
|
1932
|
-
});
|
|
2146
|
+
return res.badRequest("Invalid JSON in request body");
|
|
1933
2147
|
}
|
|
1934
2148
|
if (!data.roomId) {
|
|
1935
|
-
return
|
|
1936
|
-
error: "roomId parameter is required"
|
|
1937
|
-
});
|
|
2149
|
+
return res.badRequest("roomId parameter is required");
|
|
1938
2150
|
}
|
|
1939
2151
|
const autoCreate = data.autoCreate !== void 0 ? data.autoCreate : true;
|
|
1940
2152
|
const result = await this.findOptimalShard(data.roomId, autoCreate);
|
|
1941
2153
|
if ("error" in result) {
|
|
1942
|
-
return
|
|
1943
|
-
error: result.error
|
|
1944
|
-
});
|
|
2154
|
+
return res.notFound(result.error);
|
|
1945
2155
|
}
|
|
1946
|
-
return
|
|
2156
|
+
return res.success({
|
|
1947
2157
|
success: true,
|
|
1948
2158
|
shardId: result.shardId,
|
|
1949
2159
|
url: result.url
|
|
1950
2160
|
});
|
|
1951
2161
|
} catch (error) {
|
|
1952
2162
|
console.error("Error connecting to shard:", error);
|
|
1953
|
-
return
|
|
1954
|
-
error: "Internal server error",
|
|
1955
|
-
details: error instanceof Error ? error.message : String(error)
|
|
1956
|
-
});
|
|
2163
|
+
return res.serverError();
|
|
1957
2164
|
}
|
|
1958
2165
|
}
|
|
1959
2166
|
async findOptimalShard(roomId, autoCreate = true) {
|
|
@@ -2087,7 +2294,8 @@ _ts_decorate([
|
|
|
2087
2294
|
]),
|
|
2088
2295
|
_ts_metadata("design:type", Function),
|
|
2089
2296
|
_ts_metadata("design:paramtypes", [
|
|
2090
|
-
typeof party_exports === "undefined" || typeof void 0 === "undefined" ? Object : void 0
|
|
2297
|
+
typeof party_exports === "undefined" || typeof void 0 === "undefined" ? Object : void 0,
|
|
2298
|
+
typeof ServerResponse === "undefined" ? Object : ServerResponse
|
|
2091
2299
|
]),
|
|
2092
2300
|
_ts_metadata("design:returntype", Promise)
|
|
2093
2301
|
], WorldRoom.prototype, "updateShardStats", null);
|
|
@@ -2101,7 +2309,8 @@ _ts_decorate([
|
|
|
2101
2309
|
]),
|
|
2102
2310
|
_ts_metadata("design:type", Function),
|
|
2103
2311
|
_ts_metadata("design:paramtypes", [
|
|
2104
|
-
typeof party_exports === "undefined" || typeof void 0 === "undefined" ? Object : void 0
|
|
2312
|
+
typeof party_exports === "undefined" || typeof void 0 === "undefined" ? Object : void 0,
|
|
2313
|
+
typeof ServerResponse === "undefined" ? Object : ServerResponse
|
|
2105
2314
|
]),
|
|
2106
2315
|
_ts_metadata("design:returntype", Promise)
|
|
2107
2316
|
], WorldRoom.prototype, "scaleRoom", null);
|
|
@@ -2112,7 +2321,8 @@ _ts_decorate([
|
|
|
2112
2321
|
}),
|
|
2113
2322
|
_ts_metadata("design:type", Function),
|
|
2114
2323
|
_ts_metadata("design:paramtypes", [
|
|
2115
|
-
typeof party_exports === "undefined" || typeof void 0 === "undefined" ? Object : void 0
|
|
2324
|
+
typeof party_exports === "undefined" || typeof void 0 === "undefined" ? Object : void 0,
|
|
2325
|
+
typeof ServerResponse === "undefined" ? Object : ServerResponse
|
|
2116
2326
|
]),
|
|
2117
2327
|
_ts_metadata("design:returntype", Promise)
|
|
2118
2328
|
], WorldRoom.prototype, "connect", null);
|
|
@@ -2138,6 +2348,7 @@ export {
|
|
|
2138
2348
|
RoomGuard,
|
|
2139
2349
|
Server,
|
|
2140
2350
|
ServerIo,
|
|
2351
|
+
ServerResponse,
|
|
2141
2352
|
Shard,
|
|
2142
2353
|
WorldRoom,
|
|
2143
2354
|
request,
|