@colyseus/core 0.17.19 → 0.17.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/router/index.ts"],
4
- "sourcesContent": ["import type express from \"express\";\nimport type { IncomingMessage, ServerResponse } from \"http\";\nimport { type Endpoint, type Router, type RouterConfig, createRouter as createBetterCallRouter, createEndpoint } from \"@colyseus/better-call\";\nimport { toNodeHandler } from \"@colyseus/better-call/node\";\nimport { Transport } from \"../Transport.ts\";\nimport { controller } from \"../matchmaker/controller.ts\";\nimport pkg from \"../../package.json\" with { type: \"json\" };\n\nexport {\n createEndpoint,\n createMiddleware,\n createInternalContext,\n\n // Re-export types needed for declaration emit\n type Router,\n type RouterConfig,\n type Endpoint,\n type EndpointHandler,\n type EndpointOptions,\n type EndpointContext,\n type StrictEndpoint,\n} from \"@colyseus/better-call\";\n\nexport { toNodeHandler };\n\nexport function bindRouterToTransport(transport: Transport, router: Router) {\n // add default \"/__healthcheck\" endpoint\n router.addEndpoint(createEndpoint(\"/__healthcheck\", { method: \"GET\" }, async (ctx) => {\n return new Response(\"OK\", { status: 200 });\n }));\n\n // check if the server is bound to an express app\n const expressApp = transport.getExpressApp() as express.Application;\n\n // add default \"/\" route, if not provided.\n const hasRootRoute = (\n // check if express app has a root route\n expressRootRoute(expressApp) !== undefined ||\n\n // check if router has a root route\n Object.values(router.endpoints).some(endpoint => endpoint.path === \"/\")\n );\n\n if (!hasRootRoute) {\n router.addEndpoint(createEndpoint(\"/\", { method: \"GET\" }, async (ctx) => {\n return new Response(`Colyseus ${pkg.version}`, { status: 200 });\n }));\n }\n\n const server = transport.server;\n\n // use custom bindRouter method if provided\n if (!server && transport.bindRouter) {\n transport.bindRouter(router);\n return;\n }\n\n // main router handler\n let next: any = toNodeHandler(router.handler);\n\n if (expressApp) {\n server.removeListener('request', expressApp);\n\n // bind the router to the express app\n expressApp.use(next);\n\n // use the express app as the next function\n next = expressApp;\n }\n\n // handle cors headers for all requests by default\n server.prependListener('request', (req: IncomingMessage, res: ServerResponse) => {\n const corsHeaders = {\n ...controller.DEFAULT_CORS_HEADERS,\n ...controller.getCorsHeaders(new Headers(req.headers as any)),\n };\n\n if (req.method === \"OPTIONS\") {\n res.writeHead(204, corsHeaders);\n res.end();\n return;\n }\n\n Object.entries(corsHeaders).forEach(([key, value]) => {\n res.setHeader(key, value);\n });\n\n next(req, res);\n });\n}\n\nfunction expressRootRoute(expressApp: express.Application) {\n // express v5 uses `app.router`, express v4 uses `app._router`\n const stack = (expressApp as any)?.router?.stack ?? (expressApp as any)?._router?.stack;\n\n if (!stack) {\n throw new Error(\"Express app is not initialized\");\n }\n\n return stack.find((layer: any) => layer.match('/') && !['query', 'expressInit'].includes(layer.name));\n}\n\n/**\n * Do not use this directly. This is used internally by `@colyseus/playground`.\n * TODO: refactor. Avoid using globals.\n * @internal\n */\nexport let __globalEndpoints: Record<string, Endpoint> = {};\n\nexport function createRouter<\n E extends Record<string, Endpoint>,\n Config extends RouterConfig\n>(endpoints: E, config: Config = {} as Config) {\n // TODO: refactor. Avoid using globals.\n __globalEndpoints = endpoints;\n\n return createBetterCallRouter({ ...endpoints }, config);\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,yBAAsH;AACtH,kBAA8B;AAC9B,uBAA0B;AAC1B,wBAA2B;AAC3B,qBAAgB;AAEhB,IAAAA,sBAaO;AAIA,SAAS,sBAAsB,WAAsB,QAAgB;AAE1E,SAAO,gBAAY,mCAAe,kBAAkB,EAAE,QAAQ,MAAM,GAAG,OAAO,QAAQ;AACpF,WAAO,IAAI,SAAS,MAAM,EAAE,QAAQ,IAAI,CAAC;AAAA,EAC3C,CAAC,CAAC;AAGF,QAAM,aAAa,UAAU,cAAc;AAG3C,QAAM;AAAA;AAAA,IAEJ,iBAAiB,UAAU,MAAM;AAAA,IAGjC,OAAO,OAAO,OAAO,SAAS,EAAE,KAAK,cAAY,SAAS,SAAS,GAAG;AAAA;AAGxE,MAAI,CAAC,cAAc;AACjB,WAAO,gBAAY,mCAAe,KAAK,EAAE,QAAQ,MAAM,GAAG,OAAO,QAAQ;AACvE,aAAO,IAAI,SAAS,YAAY,eAAAC,QAAI,OAAO,IAAI,EAAE,QAAQ,IAAI,CAAC;AAAA,IAChE,CAAC,CAAC;AAAA,EACJ;AAEA,QAAM,SAAS,UAAU;AAGzB,MAAI,CAAC,UAAU,UAAU,YAAY;AACnC,cAAU,WAAW,MAAM;AAC3B;AAAA,EACF;AAGA,MAAI,WAAY,2BAAc,OAAO,OAAO;AAE5C,MAAI,YAAY;AACd,WAAO,eAAe,WAAW,UAAU;AAG3C,eAAW,IAAI,IAAI;AAGnB,WAAO;AAAA,EACT;AAGA,SAAO,gBAAgB,WAAW,CAAC,KAAsB,QAAwB;AAC/E,UAAM,cAAc;AAAA,MAClB,GAAG,6BAAW;AAAA,MACd,GAAG,6BAAW,eAAe,IAAI,QAAQ,IAAI,OAAc,CAAC;AAAA,IAC9D;AAEA,QAAI,IAAI,WAAW,WAAW;AAC5B,UAAI,UAAU,KAAK,WAAW;AAC9B,UAAI,IAAI;AACR;AAAA,IACF;AAEA,WAAO,QAAQ,WAAW,EAAE,QAAQ,CAAC,CAAC,KAAK,KAAK,MAAM;AACpD,UAAI,UAAU,KAAK,KAAK;AAAA,IAC1B,CAAC;AAED,SAAK,KAAK,GAAG;AAAA,EACf,CAAC;AACH;AAEA,SAAS,iBAAiB,YAAiC;AAEzD,QAAM,QAAS,YAAoB,QAAQ,SAAU,YAAoB,SAAS;AAElF,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,gCAAgC;AAAA,EAClD;AAEA,SAAO,MAAM,KAAK,CAAC,UAAe,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,SAAS,aAAa,EAAE,SAAS,MAAM,IAAI,CAAC;AACtG;AAOO,IAAI,oBAA8C,CAAC;AAEnD,SAAS,aAGd,WAAc,SAAiB,CAAC,GAAa;AAE7C,sBAAoB;AAEpB,aAAO,mBAAAC,cAAuB,EAAE,GAAG,UAAU,GAAG,MAAM;AACxD;",
4
+ "sourcesContent": ["import type express from \"express\";\nimport type { IncomingMessage, ServerResponse } from \"http\";\nimport { type Endpoint, type Router, type RouterConfig, createRouter as createBetterCallRouter, createEndpoint } from \"@colyseus/better-call\";\nimport { toNodeHandler } from \"@colyseus/better-call/node\";\nimport { Transport } from \"../Transport.ts\";\nimport { controller } from \"../matchmaker/controller.ts\";\nimport pkg from \"../../package.json\" with { type: \"json\" };\n\nexport {\n createEndpoint,\n createMiddleware,\n createInternalContext,\n\n // Re-export types needed for declaration emit\n type Router,\n type RouterConfig,\n type Endpoint,\n type EndpointHandler,\n type EndpointOptions,\n type EndpointContext,\n type StrictEndpoint,\n} from \"@colyseus/better-call\";\n\nexport { toNodeHandler };\n\nexport function bindRouterToTransport(transport: Transport, router: Router) {\n // add default \"/__healthcheck\" endpoint\n router.addEndpoint(createEndpoint(\"/__healthcheck\", { method: \"GET\" }, async (ctx) => {\n return new Response(\"OK\", { status: 200 });\n }));\n\n // check if the server is bound to an express app\n const expressApp = transport.getExpressApp() as express.Application;\n\n // add default \"/\" route, if not provided.\n const hasRootRoute = (\n // check if express app has a root route\n expressRootRoute(expressApp) !== undefined ||\n\n // check if router has a root route\n Object.values(router.endpoints).some(endpoint => endpoint.path === \"/\")\n );\n\n if (!hasRootRoute) {\n router.addEndpoint(createEndpoint(\"/\", { method: \"GET\" }, async (ctx) => {\n return new Response(`Colyseus ${pkg.version}`, { status: 200 });\n }));\n }\n\n const server = transport.server;\n\n // use custom bindRouter method if provided\n if (!server && transport.bindRouter) {\n transport.bindRouter(router);\n return;\n }\n\n // main router handler\n let next: any = toNodeHandler(router.handler);\n\n if (expressApp) {\n server.removeListener('request', expressApp);\n\n // bind the router to the express app\n expressApp.use(next);\n\n // use the express app as the next function\n next = expressApp;\n }\n\n // handle cors headers for all requests by default\n server.prependListener('request', (req: IncomingMessage, res: ServerResponse) => {\n const corsHeaders = {\n ...controller.DEFAULT_CORS_HEADERS,\n ...controller.getCorsHeaders(new Headers(req.headers as any)),\n };\n\n if (req.method === \"OPTIONS\") {\n res.writeHead(204, corsHeaders);\n res.end();\n return;\n }\n\n Object.entries(corsHeaders).forEach(([key, value]) => {\n res.setHeader(key, value);\n });\n\n next(req, res);\n });\n}\n\nfunction expressRootRoute(expressApp: express.Application) {\n //\n // express v5 uses `app.router`, express v4 uses `app._router`\n // check for `app._router` first, then `app.router`\n //\n // (express v4 will show a warning if `app.router` is used)\n //\n const stack = (expressApp as any)?._router?.stack ?? (expressApp as any)?.router?.stack;\n\n if (!stack) {\n return false;\n }\n\n return stack.find((layer: any) => layer.match('/') && !['query', 'expressInit'].includes(layer.name));\n}\n\n/**\n * Do not use this directly. This is used internally by `@colyseus/playground`.\n * TODO: refactor. Avoid using globals.\n * @internal\n */\nexport let __globalEndpoints: Record<string, Endpoint> = {};\n\nexport function createRouter<\n E extends Record<string, Endpoint>,\n Config extends RouterConfig\n>(endpoints: E, config: Config = {} as Config) {\n // TODO: refactor. Avoid using globals.\n __globalEndpoints = endpoints;\n\n return createBetterCallRouter({ ...endpoints }, config);\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,yBAAsH;AACtH,kBAA8B;AAC9B,uBAA0B;AAC1B,wBAA2B;AAC3B,qBAAgB;AAEhB,IAAAA,sBAaO;AAIA,SAAS,sBAAsB,WAAsB,QAAgB;AAE1E,SAAO,gBAAY,mCAAe,kBAAkB,EAAE,QAAQ,MAAM,GAAG,OAAO,QAAQ;AACpF,WAAO,IAAI,SAAS,MAAM,EAAE,QAAQ,IAAI,CAAC;AAAA,EAC3C,CAAC,CAAC;AAGF,QAAM,aAAa,UAAU,cAAc;AAG3C,QAAM;AAAA;AAAA,IAEJ,iBAAiB,UAAU,MAAM;AAAA,IAGjC,OAAO,OAAO,OAAO,SAAS,EAAE,KAAK,cAAY,SAAS,SAAS,GAAG;AAAA;AAGxE,MAAI,CAAC,cAAc;AACjB,WAAO,gBAAY,mCAAe,KAAK,EAAE,QAAQ,MAAM,GAAG,OAAO,QAAQ;AACvE,aAAO,IAAI,SAAS,YAAY,eAAAC,QAAI,OAAO,IAAI,EAAE,QAAQ,IAAI,CAAC;AAAA,IAChE,CAAC,CAAC;AAAA,EACJ;AAEA,QAAM,SAAS,UAAU;AAGzB,MAAI,CAAC,UAAU,UAAU,YAAY;AACnC,cAAU,WAAW,MAAM;AAC3B;AAAA,EACF;AAGA,MAAI,WAAY,2BAAc,OAAO,OAAO;AAE5C,MAAI,YAAY;AACd,WAAO,eAAe,WAAW,UAAU;AAG3C,eAAW,IAAI,IAAI;AAGnB,WAAO;AAAA,EACT;AAGA,SAAO,gBAAgB,WAAW,CAAC,KAAsB,QAAwB;AAC/E,UAAM,cAAc;AAAA,MAClB,GAAG,6BAAW;AAAA,MACd,GAAG,6BAAW,eAAe,IAAI,QAAQ,IAAI,OAAc,CAAC;AAAA,IAC9D;AAEA,QAAI,IAAI,WAAW,WAAW;AAC5B,UAAI,UAAU,KAAK,WAAW;AAC9B,UAAI,IAAI;AACR;AAAA,IACF;AAEA,WAAO,QAAQ,WAAW,EAAE,QAAQ,CAAC,CAAC,KAAK,KAAK,MAAM;AACpD,UAAI,UAAU,KAAK,KAAK;AAAA,IAC1B,CAAC;AAED,SAAK,KAAK,GAAG;AAAA,EACf,CAAC;AACH;AAEA,SAAS,iBAAiB,YAAiC;AAOzD,QAAM,QAAS,YAAoB,SAAS,SAAU,YAAoB,QAAQ;AAElF,MAAI,CAAC,OAAO;AACV,WAAO;AAAA,EACT;AAEA,SAAO,MAAM,KAAK,CAAC,UAAe,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,SAAS,aAAa,EAAE,SAAS,MAAM,IAAI,CAAC;AACtG;AAOO,IAAI,oBAA8C,CAAC;AAEnD,SAAS,aAGd,WAAc,SAAiB,CAAC,GAAa;AAE7C,sBAAoB;AAEpB,aAAO,mBAAAC,cAAuB,EAAE,GAAG,UAAU,GAAG,MAAM;AACxD;",
6
6
  "names": ["import_better_call", "pkg", "createBetterCallRouter"]
7
7
  }
@@ -52,9 +52,9 @@ function bindRouterToTransport(transport, router) {
52
52
  });
53
53
  }
54
54
  function expressRootRoute(expressApp) {
55
- const stack = expressApp?.router?.stack ?? expressApp?._router?.stack;
55
+ const stack = expressApp?._router?.stack ?? expressApp?.router?.stack;
56
56
  if (!stack) {
57
- throw new Error("Express app is not initialized");
57
+ return false;
58
58
  }
59
59
  return stack.find((layer) => layer.match("/") && !["query", "expressInit"].includes(layer.name));
60
60
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/router/index.ts"],
4
- "sourcesContent": ["import type express from \"express\";\nimport type { IncomingMessage, ServerResponse } from \"http\";\nimport { type Endpoint, type Router, type RouterConfig, createRouter as createBetterCallRouter, createEndpoint } from \"@colyseus/better-call\";\nimport { toNodeHandler } from \"@colyseus/better-call/node\";\nimport { Transport } from \"../Transport.ts\";\nimport { controller } from \"../matchmaker/controller.ts\";\nimport pkg from \"../../package.json\" with { type: \"json\" };\n\nexport {\n createEndpoint,\n createMiddleware,\n createInternalContext,\n\n // Re-export types needed for declaration emit\n type Router,\n type RouterConfig,\n type Endpoint,\n type EndpointHandler,\n type EndpointOptions,\n type EndpointContext,\n type StrictEndpoint,\n} from \"@colyseus/better-call\";\n\nexport { toNodeHandler };\n\nexport function bindRouterToTransport(transport: Transport, router: Router) {\n // add default \"/__healthcheck\" endpoint\n router.addEndpoint(createEndpoint(\"/__healthcheck\", { method: \"GET\" }, async (ctx) => {\n return new Response(\"OK\", { status: 200 });\n }));\n\n // check if the server is bound to an express app\n const expressApp = transport.getExpressApp() as express.Application;\n\n // add default \"/\" route, if not provided.\n const hasRootRoute = (\n // check if express app has a root route\n expressRootRoute(expressApp) !== undefined ||\n\n // check if router has a root route\n Object.values(router.endpoints).some(endpoint => endpoint.path === \"/\")\n );\n\n if (!hasRootRoute) {\n router.addEndpoint(createEndpoint(\"/\", { method: \"GET\" }, async (ctx) => {\n return new Response(`Colyseus ${pkg.version}`, { status: 200 });\n }));\n }\n\n const server = transport.server;\n\n // use custom bindRouter method if provided\n if (!server && transport.bindRouter) {\n transport.bindRouter(router);\n return;\n }\n\n // main router handler\n let next: any = toNodeHandler(router.handler);\n\n if (expressApp) {\n server.removeListener('request', expressApp);\n\n // bind the router to the express app\n expressApp.use(next);\n\n // use the express app as the next function\n next = expressApp;\n }\n\n // handle cors headers for all requests by default\n server.prependListener('request', (req: IncomingMessage, res: ServerResponse) => {\n const corsHeaders = {\n ...controller.DEFAULT_CORS_HEADERS,\n ...controller.getCorsHeaders(new Headers(req.headers as any)),\n };\n\n if (req.method === \"OPTIONS\") {\n res.writeHead(204, corsHeaders);\n res.end();\n return;\n }\n\n Object.entries(corsHeaders).forEach(([key, value]) => {\n res.setHeader(key, value);\n });\n\n next(req, res);\n });\n}\n\nfunction expressRootRoute(expressApp: express.Application) {\n // express v5 uses `app.router`, express v4 uses `app._router`\n const stack = (expressApp as any)?.router?.stack ?? (expressApp as any)?._router?.stack;\n\n if (!stack) {\n throw new Error(\"Express app is not initialized\");\n }\n\n return stack.find((layer: any) => layer.match('/') && !['query', 'expressInit'].includes(layer.name));\n}\n\n/**\n * Do not use this directly. This is used internally by `@colyseus/playground`.\n * TODO: refactor. Avoid using globals.\n * @internal\n */\nexport let __globalEndpoints: Record<string, Endpoint> = {};\n\nexport function createRouter<\n E extends Record<string, Endpoint>,\n Config extends RouterConfig\n>(endpoints: E, config: Config = {} as Config) {\n // TODO: refactor. Avoid using globals.\n __globalEndpoints = endpoints;\n\n return createBetterCallRouter({ ...endpoints }, config);\n}\n"],
5
- "mappings": ";AAEA,SAAwD,gBAAgB,wBAAwB,sBAAsB;AACtH,SAAS,qBAAqB;AAC9B,OAA0B;AAC1B,SAAS,kBAAkB;AAC3B,OAAO,SAAS,qBAAqB,KAAK,EAAE,MAAM,OAAO;AAEzD;AAAA,EACE,kBAAAA;AAAA,EACA;AAAA,EACA;AAAA,OAUK;AAIA,SAAS,sBAAsB,WAAsB,QAAgB;AAE1E,SAAO,YAAY,eAAe,kBAAkB,EAAE,QAAQ,MAAM,GAAG,OAAO,QAAQ;AACpF,WAAO,IAAI,SAAS,MAAM,EAAE,QAAQ,IAAI,CAAC;AAAA,EAC3C,CAAC,CAAC;AAGF,QAAM,aAAa,UAAU,cAAc;AAG3C,QAAM;AAAA;AAAA,IAEJ,iBAAiB,UAAU,MAAM;AAAA,IAGjC,OAAO,OAAO,OAAO,SAAS,EAAE,KAAK,cAAY,SAAS,SAAS,GAAG;AAAA;AAGxE,MAAI,CAAC,cAAc;AACjB,WAAO,YAAY,eAAe,KAAK,EAAE,QAAQ,MAAM,GAAG,OAAO,QAAQ;AACvE,aAAO,IAAI,SAAS,YAAY,IAAI,OAAO,IAAI,EAAE,QAAQ,IAAI,CAAC;AAAA,IAChE,CAAC,CAAC;AAAA,EACJ;AAEA,QAAM,SAAS,UAAU;AAGzB,MAAI,CAAC,UAAU,UAAU,YAAY;AACnC,cAAU,WAAW,MAAM;AAC3B;AAAA,EACF;AAGA,MAAI,OAAY,cAAc,OAAO,OAAO;AAE5C,MAAI,YAAY;AACd,WAAO,eAAe,WAAW,UAAU;AAG3C,eAAW,IAAI,IAAI;AAGnB,WAAO;AAAA,EACT;AAGA,SAAO,gBAAgB,WAAW,CAAC,KAAsB,QAAwB;AAC/E,UAAM,cAAc;AAAA,MAClB,GAAG,WAAW;AAAA,MACd,GAAG,WAAW,eAAe,IAAI,QAAQ,IAAI,OAAc,CAAC;AAAA,IAC9D;AAEA,QAAI,IAAI,WAAW,WAAW;AAC5B,UAAI,UAAU,KAAK,WAAW;AAC9B,UAAI,IAAI;AACR;AAAA,IACF;AAEA,WAAO,QAAQ,WAAW,EAAE,QAAQ,CAAC,CAAC,KAAK,KAAK,MAAM;AACpD,UAAI,UAAU,KAAK,KAAK;AAAA,IAC1B,CAAC;AAED,SAAK,KAAK,GAAG;AAAA,EACf,CAAC;AACH;AAEA,SAAS,iBAAiB,YAAiC;AAEzD,QAAM,QAAS,YAAoB,QAAQ,SAAU,YAAoB,SAAS;AAElF,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,gCAAgC;AAAA,EAClD;AAEA,SAAO,MAAM,KAAK,CAAC,UAAe,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,SAAS,aAAa,EAAE,SAAS,MAAM,IAAI,CAAC;AACtG;AAOO,IAAI,oBAA8C,CAAC;AAEnD,SAAS,aAGd,WAAc,SAAiB,CAAC,GAAa;AAE7C,sBAAoB;AAEpB,SAAO,uBAAuB,EAAE,GAAG,UAAU,GAAG,MAAM;AACxD;",
4
+ "sourcesContent": ["import type express from \"express\";\nimport type { IncomingMessage, ServerResponse } from \"http\";\nimport { type Endpoint, type Router, type RouterConfig, createRouter as createBetterCallRouter, createEndpoint } from \"@colyseus/better-call\";\nimport { toNodeHandler } from \"@colyseus/better-call/node\";\nimport { Transport } from \"../Transport.ts\";\nimport { controller } from \"../matchmaker/controller.ts\";\nimport pkg from \"../../package.json\" with { type: \"json\" };\n\nexport {\n createEndpoint,\n createMiddleware,\n createInternalContext,\n\n // Re-export types needed for declaration emit\n type Router,\n type RouterConfig,\n type Endpoint,\n type EndpointHandler,\n type EndpointOptions,\n type EndpointContext,\n type StrictEndpoint,\n} from \"@colyseus/better-call\";\n\nexport { toNodeHandler };\n\nexport function bindRouterToTransport(transport: Transport, router: Router) {\n // add default \"/__healthcheck\" endpoint\n router.addEndpoint(createEndpoint(\"/__healthcheck\", { method: \"GET\" }, async (ctx) => {\n return new Response(\"OK\", { status: 200 });\n }));\n\n // check if the server is bound to an express app\n const expressApp = transport.getExpressApp() as express.Application;\n\n // add default \"/\" route, if not provided.\n const hasRootRoute = (\n // check if express app has a root route\n expressRootRoute(expressApp) !== undefined ||\n\n // check if router has a root route\n Object.values(router.endpoints).some(endpoint => endpoint.path === \"/\")\n );\n\n if (!hasRootRoute) {\n router.addEndpoint(createEndpoint(\"/\", { method: \"GET\" }, async (ctx) => {\n return new Response(`Colyseus ${pkg.version}`, { status: 200 });\n }));\n }\n\n const server = transport.server;\n\n // use custom bindRouter method if provided\n if (!server && transport.bindRouter) {\n transport.bindRouter(router);\n return;\n }\n\n // main router handler\n let next: any = toNodeHandler(router.handler);\n\n if (expressApp) {\n server.removeListener('request', expressApp);\n\n // bind the router to the express app\n expressApp.use(next);\n\n // use the express app as the next function\n next = expressApp;\n }\n\n // handle cors headers for all requests by default\n server.prependListener('request', (req: IncomingMessage, res: ServerResponse) => {\n const corsHeaders = {\n ...controller.DEFAULT_CORS_HEADERS,\n ...controller.getCorsHeaders(new Headers(req.headers as any)),\n };\n\n if (req.method === \"OPTIONS\") {\n res.writeHead(204, corsHeaders);\n res.end();\n return;\n }\n\n Object.entries(corsHeaders).forEach(([key, value]) => {\n res.setHeader(key, value);\n });\n\n next(req, res);\n });\n}\n\nfunction expressRootRoute(expressApp: express.Application) {\n //\n // express v5 uses `app.router`, express v4 uses `app._router`\n // check for `app._router` first, then `app.router`\n //\n // (express v4 will show a warning if `app.router` is used)\n //\n const stack = (expressApp as any)?._router?.stack ?? (expressApp as any)?.router?.stack;\n\n if (!stack) {\n return false;\n }\n\n return stack.find((layer: any) => layer.match('/') && !['query', 'expressInit'].includes(layer.name));\n}\n\n/**\n * Do not use this directly. This is used internally by `@colyseus/playground`.\n * TODO: refactor. Avoid using globals.\n * @internal\n */\nexport let __globalEndpoints: Record<string, Endpoint> = {};\n\nexport function createRouter<\n E extends Record<string, Endpoint>,\n Config extends RouterConfig\n>(endpoints: E, config: Config = {} as Config) {\n // TODO: refactor. Avoid using globals.\n __globalEndpoints = endpoints;\n\n return createBetterCallRouter({ ...endpoints }, config);\n}\n"],
5
+ "mappings": ";AAEA,SAAwD,gBAAgB,wBAAwB,sBAAsB;AACtH,SAAS,qBAAqB;AAC9B,OAA0B;AAC1B,SAAS,kBAAkB;AAC3B,OAAO,SAAS,qBAAqB,KAAK,EAAE,MAAM,OAAO;AAEzD;AAAA,EACE,kBAAAA;AAAA,EACA;AAAA,EACA;AAAA,OAUK;AAIA,SAAS,sBAAsB,WAAsB,QAAgB;AAE1E,SAAO,YAAY,eAAe,kBAAkB,EAAE,QAAQ,MAAM,GAAG,OAAO,QAAQ;AACpF,WAAO,IAAI,SAAS,MAAM,EAAE,QAAQ,IAAI,CAAC;AAAA,EAC3C,CAAC,CAAC;AAGF,QAAM,aAAa,UAAU,cAAc;AAG3C,QAAM;AAAA;AAAA,IAEJ,iBAAiB,UAAU,MAAM;AAAA,IAGjC,OAAO,OAAO,OAAO,SAAS,EAAE,KAAK,cAAY,SAAS,SAAS,GAAG;AAAA;AAGxE,MAAI,CAAC,cAAc;AACjB,WAAO,YAAY,eAAe,KAAK,EAAE,QAAQ,MAAM,GAAG,OAAO,QAAQ;AACvE,aAAO,IAAI,SAAS,YAAY,IAAI,OAAO,IAAI,EAAE,QAAQ,IAAI,CAAC;AAAA,IAChE,CAAC,CAAC;AAAA,EACJ;AAEA,QAAM,SAAS,UAAU;AAGzB,MAAI,CAAC,UAAU,UAAU,YAAY;AACnC,cAAU,WAAW,MAAM;AAC3B;AAAA,EACF;AAGA,MAAI,OAAY,cAAc,OAAO,OAAO;AAE5C,MAAI,YAAY;AACd,WAAO,eAAe,WAAW,UAAU;AAG3C,eAAW,IAAI,IAAI;AAGnB,WAAO;AAAA,EACT;AAGA,SAAO,gBAAgB,WAAW,CAAC,KAAsB,QAAwB;AAC/E,UAAM,cAAc;AAAA,MAClB,GAAG,WAAW;AAAA,MACd,GAAG,WAAW,eAAe,IAAI,QAAQ,IAAI,OAAc,CAAC;AAAA,IAC9D;AAEA,QAAI,IAAI,WAAW,WAAW;AAC5B,UAAI,UAAU,KAAK,WAAW;AAC9B,UAAI,IAAI;AACR;AAAA,IACF;AAEA,WAAO,QAAQ,WAAW,EAAE,QAAQ,CAAC,CAAC,KAAK,KAAK,MAAM;AACpD,UAAI,UAAU,KAAK,KAAK;AAAA,IAC1B,CAAC;AAED,SAAK,KAAK,GAAG;AAAA,EACf,CAAC;AACH;AAEA,SAAS,iBAAiB,YAAiC;AAOzD,QAAM,QAAS,YAAoB,SAAS,SAAU,YAAoB,QAAQ;AAElF,MAAI,CAAC,OAAO;AACV,WAAO;AAAA,EACT;AAEA,SAAO,MAAM,KAAK,CAAC,UAAe,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,SAAS,aAAa,EAAE,SAAS,MAAM,IAAI,CAAC;AACtG;AAOO,IAAI,oBAA8C,CAAC;AAEnD,SAAS,aAGd,WAAc,SAAiB,CAAC,GAAa;AAE7C,sBAAoB;AAEpB,SAAO,uBAAuB,EAAE,GAAG,UAAU,GAAG,MAAM;AACxD;",
6
6
  "names": ["createEndpoint"]
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@colyseus/core",
3
- "version": "0.17.19",
3
+ "version": "0.17.21",
4
4
  "description": "Multiplayer Framework for Node.js.",
5
5
  "type": "module",
6
6
  "input": "./src/index.ts",
@@ -51,7 +51,7 @@
51
51
  "@standard-schema/spec": "^1.0.0",
52
52
  "debug": "^4.3.4",
53
53
  "nanoid": "^3.3.11",
54
- "@colyseus/shared-types": "^0.17.2",
54
+ "@colyseus/shared-types": "^0.17.3",
55
55
  "@colyseus/better-call": "^1.2.0",
56
56
  "@colyseus/greeting-banner": "^3.0.7"
57
57
  },
@@ -59,8 +59,8 @@
59
59
  "@colyseus/schema": "^4.0.4",
60
60
  "express": "^5.0.0",
61
61
  "@colyseus/redis-driver": "^0.17.5",
62
- "@colyseus/tools": "^0.17.15",
63
- "@colyseus/redis-presence": "^0.17.5"
62
+ "@colyseus/redis-presence": "^0.17.5",
63
+ "@colyseus/tools": "^0.17.15"
64
64
  },
65
65
  "peerDependencies": {
66
66
  "@colyseus/schema": "^4.0.4",
package/src/MatchMaker.ts CHANGED
@@ -390,8 +390,8 @@ export function defineRoomType<T extends Type<Room>>(
390
390
  roomName: string,
391
391
  klass: T,
392
392
  defaultOptions?: OnCreateOptions<T>,
393
- ) {
394
- const registeredHandler = new RegisteredHandler(klass, defaultOptions);
393
+ ): RegisteredHandler<InstanceType<T>> {
394
+ const registeredHandler = new RegisteredHandler(klass, defaultOptions) as unknown as RegisteredHandler<InstanceType<T>>;
395
395
  registeredHandler.name = roomName;
396
396
 
397
397
  handlers[roomName] = registeredHandler;
package/src/Server.ts CHANGED
@@ -384,6 +384,6 @@ export function defineServer<
384
384
  export function defineRoom<T extends Type<Room>>(
385
385
  roomKlass: T,
386
386
  defaultOptions?: Parameters<NonNullable<InstanceType<T>['onCreate']>>[0],
387
- ): RegisteredHandler<T> {
388
- return new RegisteredHandler(roomKlass, defaultOptions);
387
+ ): RegisteredHandler<InstanceType<T>> {
388
+ return new RegisteredHandler(roomKlass, defaultOptions) as unknown as RegisteredHandler<InstanceType<T>>;
389
389
  }
package/src/Transport.ts CHANGED
@@ -30,7 +30,7 @@ export abstract class Transport {
30
30
  * For uWebSockets transport, this uses the uwebsockets-express module.
31
31
  * This method is called lazily only when an express callback is provided in server options.
32
32
  */
33
- public getExpressApp?(resolved?: boolean): Promise<import('express').Application> | import('express').Application | undefined;
33
+ public getExpressApp?(): Promise<import('express').Application> | import('express').Application | undefined;
34
34
 
35
35
  /**
36
36
  * Binds a router to the transport.
package/src/index.ts CHANGED
@@ -73,7 +73,7 @@ export {
73
73
  // Default rooms
74
74
  export { LobbyRoom } from './rooms/LobbyRoom.ts';
75
75
  export { RelayRoom } from './rooms/RelayRoom.ts';
76
- export { RankedQueueRoom, type RankedQueueOptions, type MatchGroup, type MatchTeam, type ClientQueueData } from './rooms/RankedQueueRoom.ts';
76
+ export { QueueRoom, type QueueOptions, type QueueMatchGroup, type QueueMatchTeam, type QueueClientData } from './rooms/QueueRoom.ts';
77
77
 
78
78
  // Router / Endpoints
79
79
  export {
@@ -36,32 +36,32 @@ type SortByKeys<RoomType extends Room> =
36
36
  ? keyof ExtractRoomCacheMetadata<RoomType> & string
37
37
  : never);
38
38
 
39
- export interface RegisteredHandlerEvents<RoomType extends Type<Room> = any> {
40
- create: [room: InstanceType<RoomType>];
41
- lock: [room: InstanceType<RoomType>];
42
- unlock: [room: InstanceType<RoomType>];
43
- join: [room: InstanceType<RoomType>, client: Client];
44
- leave: [room: InstanceType<RoomType>, client: Client, willDispose: boolean];
45
- dispose: [room: InstanceType<RoomType>];
46
- 'visibility-change': [room: InstanceType<RoomType>, isVisible: boolean];
47
- 'metadata-change': [room: InstanceType<RoomType>];
39
+ export interface RegisteredHandlerEvents<RoomType extends Room = any> {
40
+ create: [room: RoomType];
41
+ lock: [room: RoomType];
42
+ unlock: [room: RoomType];
43
+ join: [room: RoomType, client: Client];
44
+ leave: [room: RoomType, client: Client, willDispose: boolean];
45
+ dispose: [room: RoomType];
46
+ 'visibility-change': [room: RoomType, isVisible: boolean];
47
+ 'metadata-change': [room: RoomType];
48
48
  }
49
49
 
50
50
  export class RegisteredHandler<
51
- RoomType extends Type<Room> = any
51
+ RoomType extends Room = any
52
52
  > extends EventEmitter<RegisteredHandlerEvents<RoomType>> {
53
53
  '~room': RoomType;
54
54
 
55
- public klass: RoomType;
55
+ public klass: Type<RoomType>;
56
56
  public options: any;
57
57
 
58
58
  public name: string;
59
- public filterOptions: Array<FilterByKeys<InstanceType<RoomType>>> = [];
59
+ public filterOptions: Array<FilterByKeys<RoomType>> = [];
60
60
  public sortOptions?: SortOptions;
61
61
 
62
62
  public realtimeListingEnabled: boolean = false;
63
63
 
64
- constructor(klass: RoomType, options?: any) {
64
+ constructor(klass: Type<RoomType>, options?: any) {
65
65
  super();
66
66
 
67
67
  this.klass = klass;
@@ -106,7 +106,7 @@ export class RegisteredHandler<
106
106
  * // Mix both
107
107
  * .filterBy(['mode', 'difficulty', 'maxClients'])
108
108
  */
109
- public filterBy<T extends FilterByKeys<InstanceType<RoomType>>>(
109
+ public filterBy<T extends FilterByKeys<RoomType>>(
110
110
  options: T[]
111
111
  ) {
112
112
  this.filterOptions = options;
@@ -129,7 +129,7 @@ export class RegisteredHandler<
129
129
  * // Multiple sort criteria
130
130
  * .sortBy({ 'metadata.skillLevel': 1, clients: -1 })
131
131
  */
132
- public sortBy<T extends SortByKeys<InstanceType<RoomType>>>(
132
+ public sortBy<T extends SortByKeys<RoomType>>(
133
133
  options: { [K in T]: SortOptions[string] }
134
134
  ): this {
135
135
  this.sortOptions = options as unknown as SortOptions;
@@ -6,7 +6,7 @@ import { debugMatchMaking } from '../Debug.ts';
6
6
  import { ServerError } from '../errors/ServerError.ts';
7
7
  import { ErrorCode } from '@colyseus/shared-types';
8
8
 
9
- export interface RankedQueueOptions {
9
+ export interface QueueOptions {
10
10
  /**
11
11
  * number of players on each match
12
12
  */
@@ -44,29 +44,29 @@ export interface RankedQueueOptions {
44
44
  * Comparison function for matching clients to groups
45
45
  * Returns true if the client is compatible with the group
46
46
  */
47
- compare?: (client: ClientQueueData, matchGroup: MatchGroup) => boolean;
47
+ compare?: (client: QueueClientData, matchGroup: QueueMatchGroup) => boolean;
48
48
 
49
49
  /**
50
50
  *
51
51
  * When onGroupReady is set, the "roomNameToCreate" option is ignored.
52
52
  */
53
- onGroupReady?: (this: RankedQueueRoom, group: MatchGroup) => Promise<IRoomCache>;
53
+ onGroupReady?: (this: QueueRoom, group: QueueMatchGroup) => Promise<IRoomCache>;
54
54
  }
55
55
 
56
- export interface MatchGroup {
56
+ export interface QueueMatchGroup {
57
57
  averageRank: number;
58
- clients: Array<Client<{ userData: ClientQueueData }>>,
58
+ clients: Array<Client<{ userData: QueueClientData }>>,
59
59
  ready?: boolean;
60
60
  confirmed?: number;
61
61
  }
62
62
 
63
- export interface MatchTeam {
63
+ export interface QueueMatchTeam {
64
64
  averageRank: number;
65
- clients: Array<Client<{ userData: ClientQueueData }>>,
65
+ clients: Array<Client<{ userData: QueueClientData }>>,
66
66
  teamId: string | symbol;
67
67
  }
68
68
 
69
- export interface ClientQueueData {
69
+ export interface QueueClientData {
70
70
  /**
71
71
  * Rank of the client
72
72
  */
@@ -90,7 +90,7 @@ export interface ClientQueueData {
90
90
  /**
91
91
  * Match group the client is currently in
92
92
  */
93
- group?: MatchGroup;
93
+ group?: QueueMatchGroup;
94
94
 
95
95
  /**
96
96
  * Whether the client has confirmed the connection to the room
@@ -110,14 +110,14 @@ export interface ClientQueueData {
110
110
  }
111
111
 
112
112
  const DEFAULT_TEAM = Symbol("$default_team");
113
- const DEFAULT_COMPARE = (client: ClientQueueData, matchGroup: MatchGroup) => {
113
+ const DEFAULT_COMPARE = (client: QueueClientData, matchGroup: QueueMatchGroup) => {
114
114
  const diff = Math.abs(client.rank - matchGroup.averageRank);
115
115
  const diffRatio = (diff / matchGroup.averageRank);
116
116
  // If diff ratio is too high, create a new match group
117
117
  return (diff < 10 || diffRatio <= 2);
118
118
  }
119
119
 
120
- export class RankedQueueRoom extends Room {
120
+ export class QueueRoom extends Room {
121
121
  maxPlayers = 4;
122
122
  maxTeamSize: number;
123
123
  allowIncompleteGroups: boolean = false;
@@ -133,13 +133,13 @@ export class RankedQueueRoom extends Room {
133
133
  /**
134
134
  * Groups of players per iteration
135
135
  */
136
- groups: MatchGroup[] = [];
137
- highPriorityGroups: MatchGroup[] = [];
136
+ groups: QueueMatchGroup[] = [];
137
+ highPriorityGroups: QueueMatchGroup[] = [];
138
138
 
139
139
  matchRoomName: string;
140
140
 
141
141
  protected compare = DEFAULT_COMPARE;
142
- protected onGroupReady = (group: MatchGroup) => matchMaker.createRoom(this.matchRoomName, {});
142
+ protected onGroupReady = (group: QueueMatchGroup) => matchMaker.createRoom(this.matchRoomName, {});
143
143
 
144
144
  messages = {
145
145
  confirm: (client: Client, _: unknown) => {
@@ -153,7 +153,7 @@ export class RankedQueueRoom extends Room {
153
153
  },
154
154
  }
155
155
 
156
- onCreate(options: RankedQueueOptions) {
156
+ onCreate(options: QueueOptions) {
157
157
  if (typeof(options.maxWaitingCycles) === "number") {
158
158
  this.maxWaitingCycles = options.maxWaitingCycles;
159
159
  }
@@ -182,10 +182,10 @@ export class RankedQueueRoom extends Room {
182
182
  this.matchRoomName = options.matchRoomName;
183
183
 
184
184
  } else {
185
- throw new ServerError(ErrorCode.APPLICATION_ERROR, "RankedQueueRoom: 'matchRoomName' option is required.");
185
+ throw new ServerError(ErrorCode.APPLICATION_ERROR, "QueueRoom: 'matchRoomName' option is required.");
186
186
  }
187
187
 
188
- debugMatchMaking("RankedQueueRoom#onCreate() maxPlayers: %d, maxWaitingCycles: %d, maxTeamSize: %d, allowIncompleteGroups: %d, roomNameToCreate: %s", this.maxPlayers, this.maxWaitingCycles, this.maxTeamSize, this.allowIncompleteGroups, this.matchRoomName);
188
+ debugMatchMaking("QueueRoom#onCreate() maxPlayers: %d, maxWaitingCycles: %d, maxTeamSize: %d, allowIncompleteGroups: %d, roomNameToCreate: %s", this.maxPlayers, this.maxWaitingCycles, this.maxTeamSize, this.allowIncompleteGroups, this.matchRoomName);
189
189
 
190
190
  /**
191
191
  * Redistribute clients into groups at every interval
@@ -201,7 +201,7 @@ export class RankedQueueRoom extends Room {
201
201
  });
202
202
  }
203
203
 
204
- addToQueue(client: Client, queueData: ClientQueueData) {
204
+ addToQueue(client: Client, queueData: QueueClientData) {
205
205
  if (queueData.currentCycle === undefined) {
206
206
  queueData.currentCycle = 0;
207
207
  }
@@ -212,7 +212,7 @@ export class RankedQueueRoom extends Room {
212
212
  }
213
213
 
214
214
  createMatchGroup() {
215
- const group: MatchGroup = { clients: [], averageRank: 0 };
215
+ const group: QueueMatchGroup = { clients: [], averageRank: 0 };
216
216
  this.groups.push(group);
217
217
  return group;
218
218
  }
@@ -253,8 +253,8 @@ export class RankedQueueRoom extends Room {
253
253
  this.processGroupsReady();
254
254
  }
255
255
 
256
- redistributeTeams(sortedClients: Client<{ userData: ClientQueueData }>[]) {
257
- const teamsByID: { [teamId: string | symbol]: MatchTeam } = {};
256
+ redistributeTeams(sortedClients: Client<{ userData: QueueClientData }>[]) {
257
+ const teamsByID: { [teamId: string | symbol]: QueueMatchTeam } = {};
258
258
 
259
259
  sortedClients.forEach((client) => {
260
260
  const teamId = client.userData.teamId || DEFAULT_TEAM;
@@ -279,7 +279,7 @@ export class RankedQueueRoom extends Room {
279
279
 
280
280
  // Iterate over teams multiple times until all clients are assigned to a group
281
281
  do {
282
- let currentGroup: MatchGroup = this.createMatchGroup();
282
+ let currentGroup: QueueMatchGroup = this.createMatchGroup();
283
283
  teams = teams.filter((team) => {
284
284
  // Remove clients from the team and add them to the current group
285
285
  const totalRank = team.averageRank * team.clients.length;
@@ -303,8 +303,8 @@ export class RankedQueueRoom extends Room {
303
303
  }
304
304
 
305
305
  redistributeClients(
306
- sortedClients: Client<{ userData: ClientQueueData }>[],
307
- currentGroup: MatchGroup = this.createMatchGroup(),
306
+ sortedClients: Client<{ userData: QueueClientData }>[],
307
+ currentGroup: QueueMatchGroup = this.createMatchGroup(),
308
308
  totalRank: number = 0,
309
309
  ) {
310
310
  for (let i = 0, l = sortedClients.length; i < l; i++) {
@@ -99,7 +99,7 @@ function expressRootRoute(expressApp: express.Application) {
99
99
  const stack = (expressApp as any)?._router?.stack ?? (expressApp as any)?.router?.stack;
100
100
 
101
101
  if (!stack) {
102
- throw new Error("Express app is not initialized");
102
+ return false;
103
103
  }
104
104
 
105
105
  return stack.find((layer: any) => layer.match('/') && !['query', 'expressInit'].includes(layer.name));