@colyseus/core 0.17.32 → 0.17.34

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/LICENSE CHANGED
@@ -1,6 +1,4 @@
1
- Copyright (c) 2023 Endel Dreyer
2
- Copyright (c) 2021-2022 Lucid Sight
3
- Copyright (c) 2015-2021 Endel Dreyer
1
+ Copyright (c) 2015-2026 Endel Dreyer
4
2
 
5
3
  MIT License:
6
4
 
package/README.md CHANGED
@@ -7,19 +7,19 @@
7
7
  <a href="https://npmjs.com/package/colyseus">
8
8
  <img src="https://img.shields.io/npm/dm/colyseus.svg?style=for-the-badge&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QAAKqNIzIAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAAHdElNRQfjAgETESWYxR33AAAAtElEQVQoz4WQMQrCQBRE38Z0QoTcwF4Qg1h4BO0sxGOk80iCtViksrIQRRBTewWxMI1mbELYjYu+4rPMDPtn12ChMT3gavb4US5Jym0tcBIta3oDHv4Gwmr7nC4QAxBrCdzM2q6XqUnm9m9r59h7Rc0n2pFv24k4ttGMUXW+sGELTJjSr7QDKuqLS6UKFChVWWuFkZw9Z2AAvAirKT+JTlppIRnd6XgaP4goefI2Shj++OnjB3tBmHYK8z9zAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE5LTAyLTAxVDE4OjE3OjM3KzAxOjAwGQQixQAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxOS0wMi0wMVQxODoxNzozNyswMTowMGhZmnkAAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb7jwaAAAAAElFTkSuQmCC">
9
9
  </a>
10
- <a href="https://github.com/colyseus/colyseus/discussions" title="Discuss on Forum">
11
- <img src="https://img.shields.io/badge/discuss-on%20forum-brightgreen.svg?style=for-the-badge&colorB=0069b8&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QAAKqNIzIAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAAHdElNRQfjAgETDROxCNUzAAABB0lEQVQoz4WRvyvEARjGP193CnWRH+dHQmGwKZtFGcSmxHAL400GN95ktIpV2dzlLzDJgsGgGNRdDAzoQueS/PgY3HXHyT3T+/Y87/s89UANBKXBdoZo5J6L4K1K5ZxHfnjnlQUf3bKvkgy57a0r9hS3cXfMO1kWJMza++tj3Ac7/LY343x1NA9cNmYMwnSS/SP8JVFuSJmr44iFqvtmpjhmhBCrOOazCesq6H4P3bPBjFoIBydOk2bUA17I080Es+wSZ51B4DIA2zgjSpYcEe44Js01G0XjRcCU+y4ZMrDeLmfc9EnVd5M/o0VMeu6nJZxWJivLmhyw1WHTvrr2b4+2OFqra+ALwouTMDcqmjMAAAAldEVYdGRhdGU6Y3JlYXRlADIwMTktMDItMDFUMTg6MTM6MTkrMDE6MDAC9f6fAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE5LTAyLTAxVDE4OjEzOjE5KzAxOjAwc6hGIwAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAAASUVORK5CYII=" alt="Discussion forum" />
12
- </a>
13
10
  <a href="http://chat.colyseus.io">
14
11
  <img src="https://img.shields.io/discord/525739117951320081.svg?style=for-the-badge&colorB=7581dc&logo=discord&logoColor=white">
15
12
  </a>
13
+ <a href="https://github.com/colyseus/colyseus/discussions" title="Discuss Forum">
14
+ <img src="https://img.shields.io/badge/discuss-forum-brightgreen.svg?style=for-the-badge&colorB=0069b8&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QAAKqNIzIAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAAHdElNRQfjAgETDROxCNUzAAABB0lEQVQoz4WRvyvEARjGP193CnWRH+dHQmGwKZtFGcSmxHAL400GN95ktIpV2dzlLzDJgsGgGNRdDAzoQueS/PgY3HXHyT3T+/Y87/s89UANBKXBdoZo5J6L4K1K5ZxHfnjnlQUf3bKvkgy57a0r9hS3cXfMO1kWJMza++tj3Ac7/LY343x1NA9cNmYMwnSS/SP8JVFuSJmr44iFqvtmpjhmhBCrOOazCesq6H4P3bPBjFoIBydOk2bUA17I080Es+wSZ51B4DIA2zgjSpYcEe44Js01G0XjRcCU+y4ZMrDeLmfc9EnVd5M/o0VMeu6nJZxWJivLmhyw1WHTvrr2b4+2OFqra+ALwouTMDcqmjMAAAAldEVYdGRhdGU6Y3JlYXRlADIwMTktMDItMDFUMTg6MTM6MTkrMDE6MDAC9f6fAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE5LTAyLTAxVDE4OjEzOjE5KzAxOjAwc6hGIwAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAAASUVORK5CYII=" alt="Discussion forum" />
15
+ </a>
16
16
  <h3>
17
17
  Multiplayer Framework for Node.js. <br /><a href="https://docs.colyseus.io/">View documentation</a>
18
18
  </h3>
19
19
  </div>
20
20
 
21
- Colyseus is an Authoritative Multiplayer Framework for Node.js, with clients
22
- available for the Web, Unity3d, Defold, Haxe, and Cocos. ([See official clients](#%EF%B8%8F-official-client-integration))
21
+ Colyseus is an Authoritative Multiplayer Framework for Node.js, with SDKs
22
+ available for the Web, Unity, Defold, Haxe, Cocos and Construct3. ([See official SDKs](https://docs.colyseus.io/getting-started))
23
23
 
24
24
  The project focuses on providing synchronizable data structures for realtime and
25
25
  turn-based games, matchmaking, and ease of usage both on the server-side and
@@ -28,23 +28,24 @@ client-side.
28
28
  The mission of the framework is to be a standard netcode & matchmaking solution
29
29
  for any kind of project you can think of!
30
30
 
31
- ## Key features:
31
+ ## Why developers choose Colyseus:
32
32
 
33
- - WebSocket-based communication
34
- - Simple API in the server-side and client-side.
35
- - Automatic state synchronization from server-to-client (delta compressed)
36
- - Matchmaking clients into game rooms/sessions
37
- - Scale vertically or horizontally
33
+ - ⚡️ **Real-time state sync that just works** → Define your state on the server and it automatically synchronizes to all clients, delta-compressed and binary-encoded.
34
+ - ⚔️ **Built-in matchmaking** → Room-based architecture with filtering, queuing, and reconnection support out of the box.
35
+ - 📈 **Scalable** Go from 10 to 10,000+ CCU by scaling vertically or horizontally with Redis and load balancers.
36
+ - 🛡️ **Cheat-proof by design** → Authoritative server model ensures game logic runs on the server, not the client.
37
+ - 🛠️ **Use the tools you already know** → Built on Node.js and TypeScript with a simple, familiar API on both server and client.
38
+ - 💙 **Free forever** → MIT licensed, even for commercial games.
38
39
 
39
- See [public roadmap](https://github.com/colyseus/colyseus/wiki/Public-Roadmap) for future plans.
40
+ See [public roadmap](https://docs.colyseus.io/roadmap) for version 1.0.
40
41
 
41
42
  # 🚀 Quickstart
42
43
 
43
- Create a bare-bones Colyseus server by using `npm create colyseus-app@latest`:
44
+ Set up your own Colyseus server project for your game using `npm create colyseus-app@latest`:
44
45
 
45
46
  ```
46
- npm create colyseus-app@latest my-colyseus-server
47
- cd my-colyseus-server
47
+ npm create colyseus-app@latest ./my-server
48
+ cd my-server
48
49
  npm start
49
50
  ```
50
51
 
@@ -87,7 +88,7 @@ Thanks goes to these wonderful people ([emoji key](https://github.com/kentcdodds
87
88
  <td align="center"><a href="https://github.com/TinyDobbins"><img src="https://avatars2.githubusercontent.com/u/20824844?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Nikita Borisov</b></sub></a><br /><a href="https://github.com/colyseus/colyseus/issues?q=author%3ATinyDobbins" title="Bug reports">🐛</a> <a href="https://github.com/colyseus/colyseus/commits?author=TinyDobbins" title="Code">💻</a> <a href="#business-TinyDobbins" title="Business development">💼</a> <a href="#ideas-TinyDobbins" title="Ideas, Planning, & Feedback">🤔</a></td>
88
89
  <td align="center"><a href="https://acemobe.com/"><img src="https://avatars2.githubusercontent.com/u/232101?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Phil Harvey</b></sub></a><br /><a href="https://github.com/colyseus/colyseus/commits?author=filharvey" title="Documentation">📖</a></td>
89
90
  <td align="center"><a href="https://github.com/serjek"><img src="https://avatars2.githubusercontent.com/u/18265157?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sergey</b></sub></a><br /><a href="https://github.com/colyseus/colyseus/issues?q=author%3Aserjek" title="Bug reports">🐛</a> <a href="https://github.com/colyseus/colyseus/commits?author=serjek" title="Code">💻</a></td>
90
- <td align="center"><a href="https://oyed.io"><img src="https://avatars0.githubusercontent.com/u/853683?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Tom</b></sub></a><br /><a href="#question-oyed" title="Answering Questions">💬</a> <a href="https://github.com/colyseus/colyseus/issues?q=author%3Aoyed" title="Bug reports">🐛</a> <a href="#ideas-oyed" title="Ideas, Planning, & Feedback">🤔</a></td>
91
+ <td align="center"><a href="https://devlsh.com"><img src="https://avatars0.githubusercontent.com/u/853683?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sophie</b></sub></a><br /><a href="#question-devlsh" title="Answering Questions">💬</a> <a href="https://github.com/colyseus/colyseus/issues?q=author%3Adevlsh" title="Bug reports">🐛</a> <a href="#ideas-devlsh" title="Ideas, Planning, & Feedback">🤔</a></td>
91
92
  <td align="center"><a href="https://github.com/supertommy"><img src="https://avatars0.githubusercontent.com/u/2236153?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Tommy Leung</b></sub></a><br /><a href="#mentoring-supertommy" title="Mentoring">🧑‍🏫</a></td>
92
93
  <td align="center"><a href="https://github.com/digimbyte"><img src="https://avatars2.githubusercontent.com/u/6645396?v=4?s=100" width="100px;" alt=""/><br /><sub><b>digimbyte</b></sub></a><br /><a href="https://github.com/colyseus/colyseus/commits?author=digimbyte" title="Documentation">📖</a></td>
93
94
  </tr>
@@ -1,94 +1,202 @@
1
- export declare const postMatchmakeMethod: import("@colyseus/better-call").StrictEndpoint<"/matchmake/:method/:roomName", {
1
+ export declare const postMatchmakeMethod: import("@colyseus/better-call").StrictEndpoint<"/matchmake/:method/:roomName", {} & {
2
2
  method: "POST";
3
+ body: import("@colyseus/better-call").StandardSchemaV1<unknown, unknown>;
3
4
  }, any>;
4
5
  export declare function getDefaultRouter(): {
5
6
  handler: (request: Request) => Promise<Response>;
6
7
  endpoints: {
7
- postMatchmakeMethod: import("@colyseus/better-call").StrictEndpoint<"/matchmake/:method/:roomName", {
8
+ postMatchmakeMethod: import("@colyseus/better-call").StrictEndpoint<"/matchmake/:method/:roomName", {} & {
8
9
  method: "POST";
10
+ body: import("@colyseus/better-call").StandardSchemaV1<unknown, unknown>;
9
11
  }, any>;
10
12
  };
11
13
  addEndpoint: (endpoint: import("@colyseus/better-call").Endpoint) => void;
14
+ findRoute: (method: string, path: string) => {
15
+ data: import("@colyseus/better-call").Endpoint & {
16
+ path: string;
17
+ };
18
+ params: Record<string, string>;
19
+ };
12
20
  extend: <NE extends Record<string, import("@colyseus/better-call").Endpoint>>(newEndpoints: NE) => {
13
21
  handler: (request: Request) => Promise<Response>;
14
22
  endpoints: {
15
- postMatchmakeMethod: import("@colyseus/better-call").StrictEndpoint<"/matchmake/:method/:roomName", {
23
+ postMatchmakeMethod: import("@colyseus/better-call").StrictEndpoint<"/matchmake/:method/:roomName", {} & {
16
24
  method: "POST";
25
+ body: import("@colyseus/better-call").StandardSchemaV1<unknown, unknown>;
17
26
  }, any>;
18
27
  } & NE;
19
28
  addEndpoint: (endpoint: import("@colyseus/better-call").Endpoint) => void;
29
+ findRoute: (method: string, path: string) => {
30
+ data: ((inputCtx: any) => Promise<any>) & {
31
+ options: import("@colyseus/better-call").EndpointOptions;
32
+ path: string;
33
+ } & {
34
+ path: string;
35
+ };
36
+ params: Record<string, string>;
37
+ };
20
38
  extend: <NE_1 extends Record<string, import("@colyseus/better-call").Endpoint>>(newEndpoints: NE_1) => {
21
39
  handler: (request: Request) => Promise<Response>;
22
40
  endpoints: {
23
- postMatchmakeMethod: import("@colyseus/better-call").StrictEndpoint<"/matchmake/:method/:roomName", {
41
+ postMatchmakeMethod: import("@colyseus/better-call").StrictEndpoint<"/matchmake/:method/:roomName", {} & {
24
42
  method: "POST";
43
+ body: import("@colyseus/better-call").StandardSchemaV1<unknown, unknown>;
25
44
  }, any>;
26
45
  } & NE & NE_1;
27
46
  addEndpoint: (endpoint: import("@colyseus/better-call").Endpoint) => void;
47
+ findRoute: (method: string, path: string) => {
48
+ data: ((inputCtx: any) => Promise<any>) & {
49
+ options: import("@colyseus/better-call").EndpointOptions;
50
+ path: string;
51
+ } & {
52
+ path: string;
53
+ };
54
+ params: Record<string, string>;
55
+ };
28
56
  extend: <NE_2 extends Record<string, import("@colyseus/better-call").Endpoint>>(newEndpoints: NE_2) => {
29
57
  handler: (request: Request) => Promise<Response>;
30
58
  endpoints: {
31
- postMatchmakeMethod: import("@colyseus/better-call").StrictEndpoint<"/matchmake/:method/:roomName", {
59
+ postMatchmakeMethod: import("@colyseus/better-call").StrictEndpoint<"/matchmake/:method/:roomName", {} & {
32
60
  method: "POST";
61
+ body: import("@colyseus/better-call").StandardSchemaV1<unknown, unknown>;
33
62
  }, any>;
34
63
  } & NE & NE_1 & NE_2;
35
64
  addEndpoint: (endpoint: import("@colyseus/better-call").Endpoint) => void;
65
+ findRoute: (method: string, path: string) => {
66
+ data: ((inputCtx: any) => Promise<any>) & {
67
+ options: import("@colyseus/better-call").EndpointOptions;
68
+ path: string;
69
+ } & {
70
+ path: string;
71
+ };
72
+ params: Record<string, string>;
73
+ };
36
74
  extend: <NE_3 extends Record<string, import("@colyseus/better-call").Endpoint>>(newEndpoints: NE_3) => {
37
75
  handler: (request: Request) => Promise<Response>;
38
76
  endpoints: {
39
- postMatchmakeMethod: import("@colyseus/better-call").StrictEndpoint<"/matchmake/:method/:roomName", {
77
+ postMatchmakeMethod: import("@colyseus/better-call").StrictEndpoint<"/matchmake/:method/:roomName", {} & {
40
78
  method: "POST";
79
+ body: import("@colyseus/better-call").StandardSchemaV1<unknown, unknown>;
41
80
  }, any>;
42
81
  } & NE & NE_1 & NE_2 & NE_3;
43
82
  addEndpoint: (endpoint: import("@colyseus/better-call").Endpoint) => void;
83
+ findRoute: (method: string, path: string) => {
84
+ data: ((inputCtx: any) => Promise<any>) & {
85
+ options: import("@colyseus/better-call").EndpointOptions;
86
+ path: string;
87
+ } & {
88
+ path: string;
89
+ };
90
+ params: Record<string, string>;
91
+ };
44
92
  extend: <NE_4 extends Record<string, import("@colyseus/better-call").Endpoint>>(newEndpoints: NE_4) => {
45
93
  handler: (request: Request) => Promise<Response>;
46
94
  endpoints: {
47
- postMatchmakeMethod: import("@colyseus/better-call").StrictEndpoint<"/matchmake/:method/:roomName", {
95
+ postMatchmakeMethod: import("@colyseus/better-call").StrictEndpoint<"/matchmake/:method/:roomName", {} & {
48
96
  method: "POST";
97
+ body: import("@colyseus/better-call").StandardSchemaV1<unknown, unknown>;
49
98
  }, any>;
50
99
  } & NE & NE_1 & NE_2 & NE_3 & NE_4;
51
100
  addEndpoint: (endpoint: import("@colyseus/better-call").Endpoint) => void;
101
+ findRoute: (method: string, path: string) => {
102
+ data: ((inputCtx: any) => Promise<any>) & {
103
+ options: import("@colyseus/better-call").EndpointOptions;
104
+ path: string;
105
+ } & {
106
+ path: string;
107
+ };
108
+ params: Record<string, string>;
109
+ };
52
110
  extend: <NE_5 extends Record<string, import("@colyseus/better-call").Endpoint>>(newEndpoints: NE_5) => {
53
111
  handler: (request: Request) => Promise<Response>;
54
112
  endpoints: {
55
- postMatchmakeMethod: import("@colyseus/better-call").StrictEndpoint<"/matchmake/:method/:roomName", {
113
+ postMatchmakeMethod: import("@colyseus/better-call").StrictEndpoint<"/matchmake/:method/:roomName", {} & {
56
114
  method: "POST";
115
+ body: import("@colyseus/better-call").StandardSchemaV1<unknown, unknown>;
57
116
  }, any>;
58
117
  } & NE & NE_1 & NE_2 & NE_3 & NE_4 & NE_5;
59
118
  addEndpoint: (endpoint: import("@colyseus/better-call").Endpoint) => void;
119
+ findRoute: (method: string, path: string) => {
120
+ data: ((inputCtx: any) => Promise<any>) & {
121
+ options: import("@colyseus/better-call").EndpointOptions;
122
+ path: string;
123
+ } & {
124
+ path: string;
125
+ };
126
+ params: Record<string, string>;
127
+ };
60
128
  extend: <NE_6 extends Record<string, import("@colyseus/better-call").Endpoint>>(newEndpoints: NE_6) => {
61
129
  handler: (request: Request) => Promise<Response>;
62
130
  endpoints: {
63
- postMatchmakeMethod: import("@colyseus/better-call").StrictEndpoint<"/matchmake/:method/:roomName", {
131
+ postMatchmakeMethod: import("@colyseus/better-call").StrictEndpoint<"/matchmake/:method/:roomName", {} & {
64
132
  method: "POST";
133
+ body: import("@colyseus/better-call").StandardSchemaV1<unknown, unknown>;
65
134
  }, any>;
66
135
  } & NE & NE_1 & NE_2 & NE_3 & NE_4 & NE_5 & NE_6;
67
136
  addEndpoint: (endpoint: import("@colyseus/better-call").Endpoint) => void;
137
+ findRoute: (method: string, path: string) => {
138
+ data: ((inputCtx: any) => Promise<any>) & {
139
+ options: import("@colyseus/better-call").EndpointOptions;
140
+ path: string;
141
+ } & {
142
+ path: string;
143
+ };
144
+ params: Record<string, string>;
145
+ };
68
146
  extend: <NE_7 extends Record<string, import("@colyseus/better-call").Endpoint>>(newEndpoints: NE_7) => {
69
147
  handler: (request: Request) => Promise<Response>;
70
148
  endpoints: {
71
- postMatchmakeMethod: import("@colyseus/better-call").StrictEndpoint<"/matchmake/:method/:roomName", {
149
+ postMatchmakeMethod: import("@colyseus/better-call").StrictEndpoint<"/matchmake/:method/:roomName", {} & {
72
150
  method: "POST";
151
+ body: import("@colyseus/better-call").StandardSchemaV1<unknown, unknown>;
73
152
  }, any>;
74
153
  } & NE & NE_1 & NE_2 & NE_3 & NE_4 & NE_5 & NE_6 & NE_7;
75
154
  addEndpoint: (endpoint: import("@colyseus/better-call").Endpoint) => void;
155
+ findRoute: (method: string, path: string) => {
156
+ data: ((inputCtx: any) => Promise<any>) & {
157
+ options: import("@colyseus/better-call").EndpointOptions;
158
+ path: string;
159
+ } & {
160
+ path: string;
161
+ };
162
+ params: Record<string, string>;
163
+ };
76
164
  extend: <NE_8 extends Record<string, import("@colyseus/better-call").Endpoint>>(newEndpoints: NE_8) => {
77
165
  handler: (request: Request) => Promise<Response>;
78
166
  endpoints: {
79
- postMatchmakeMethod: import("@colyseus/better-call").StrictEndpoint<"/matchmake/:method/:roomName", {
167
+ postMatchmakeMethod: import("@colyseus/better-call").StrictEndpoint<"/matchmake/:method/:roomName", {} & {
80
168
  method: "POST";
169
+ body: import("@colyseus/better-call").StandardSchemaV1<unknown, unknown>;
81
170
  }, any>;
82
171
  } & NE & NE_1 & NE_2 & NE_3 & NE_4 & NE_5 & NE_6 & NE_7 & NE_8;
83
172
  addEndpoint: (endpoint: import("@colyseus/better-call").Endpoint) => void;
173
+ findRoute: (method: string, path: string) => {
174
+ data: ((inputCtx: any) => Promise<any>) & {
175
+ options: import("@colyseus/better-call").EndpointOptions;
176
+ path: string;
177
+ } & {
178
+ path: string;
179
+ };
180
+ params: Record<string, string>;
181
+ };
84
182
  extend: <NE_9 extends Record<string, import("@colyseus/better-call").Endpoint>>(newEndpoints: NE_9) => {
85
183
  handler: (request: Request) => Promise<Response>;
86
184
  endpoints: {
87
- postMatchmakeMethod: import("@colyseus/better-call").StrictEndpoint<"/matchmake/:method/:roomName", {
185
+ postMatchmakeMethod: import("@colyseus/better-call").StrictEndpoint<"/matchmake/:method/:roomName", {} & {
88
186
  method: "POST";
187
+ body: import("@colyseus/better-call").StandardSchemaV1<unknown, unknown>;
89
188
  }, any>;
90
189
  } & NE & NE_1 & NE_2 & NE_3 & NE_4 & NE_5 & NE_6 & NE_7 & NE_8 & NE_9;
91
190
  addEndpoint: (endpoint: import("@colyseus/better-call").Endpoint) => void;
191
+ findRoute: (method: string, path: string) => {
192
+ data: ((inputCtx: any) => Promise<any>) & {
193
+ options: import("@colyseus/better-call").EndpointOptions;
194
+ path: string;
195
+ } & {
196
+ path: string;
197
+ };
198
+ params: Record<string, string>;
199
+ };
92
200
  extend: <NE_10 extends Record<string, import("@colyseus/better-call").Endpoint>>(newEndpoints: NE_10) => any;
93
201
  };
94
202
  };
@@ -65,11 +65,21 @@ function bindRouterToTransport(transport, router) {
65
65
  transport.bindRouter(router);
66
66
  return;
67
67
  }
68
- let next = (0, import_node.toNodeHandler)(router.handler);
68
+ let next;
69
69
  if (expressApp) {
70
70
  server.removeListener("request", expressApp);
71
- expressApp.use(next);
72
- next = expressApp;
71
+ next = async (req, res) => {
72
+ if (router.findRoute(req.method, req.url) !== void 0) {
73
+ const protocol = req.headers["x-forwarded-proto"] || (req.socket.encrypted ? "https" : "http");
74
+ const base = `${protocol}://${req.headers[":authority"] || req.headers.host}`;
75
+ const response = await router.handler((0, import_node.getRequest)({ base, request: req }));
76
+ return (0, import_node.setResponse)(res, response);
77
+ } else {
78
+ return expressApp["handle"](req, res);
79
+ }
80
+ };
81
+ } else {
82
+ next = (0, import_node.toNodeHandler)(router.handler);
73
83
  }
74
84
  server.prependListener("request", (req, res) => {
75
85
  const corsHeaders = {
@@ -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 //\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;",
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, getRequest, setResponse } 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 // which route handler to use\n // (router + fallback to express, or just router)\n let next: any;\n\n if (expressApp) {\n server.removeListener('request', expressApp);\n\n next = async (req: IncomingMessage, res: ServerResponse) => {\n // check if the route is defined in the router\n // if so, use the router handler, otherwise fallback to express\n if (router.findRoute(req.method, req.url) !== undefined) {\n const protocol = req.headers[\"x-forwarded-proto\"] || ((req.socket as any).encrypted ? \"https\" : \"http\");\n const base = `${protocol}://${req.headers[\":authority\"] || req.headers.host}`;\n const response = await router.handler(getRequest({ base, request: req }));\n return setResponse(res, response);\n\n } else {\n return expressApp['handle'](req, res);\n }\n };\n\n } else {\n next = toNodeHandler(router.handler);\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,kBAAuD;AACvD,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;AAIA,MAAI;AAEJ,MAAI,YAAY;AACd,WAAO,eAAe,WAAW,UAAU;AAE3C,WAAO,OAAO,KAAsB,QAAwB;AAG1D,UAAI,OAAO,UAAU,IAAI,QAAQ,IAAI,GAAG,MAAM,QAAW;AACvD,cAAM,WAAW,IAAI,QAAQ,mBAAmB,MAAO,IAAI,OAAe,YAAY,UAAU;AAChG,cAAM,OAAO,GAAG,QAAQ,MAAM,IAAI,QAAQ,YAAY,KAAK,IAAI,QAAQ,IAAI;AAC3E,cAAM,WAAW,MAAM,OAAO,YAAQ,wBAAW,EAAE,MAAM,SAAS,IAAI,CAAC,CAAC;AACxE,mBAAO,yBAAY,KAAK,QAAQ;AAAA,MAElC,OAAO;AACL,eAAO,WAAW,QAAQ,EAAE,KAAK,GAAG;AAAA,MACtC;AAAA,IACF;AAAA,EAEF,OAAO;AACL,eAAO,2BAAc,OAAO,OAAO;AAAA,EACrC;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
  }
@@ -14,46 +14,142 @@ export declare function createRouter<E extends Record<string, Endpoint>, Config
14
14
  handler: (request: Request) => Promise<Response>;
15
15
  endpoints: E;
16
16
  addEndpoint: (endpoint: Endpoint) => void;
17
+ findRoute: (method: string, path: string) => {
18
+ data: Endpoint & {
19
+ path: string;
20
+ };
21
+ params: Record<string, string>;
22
+ };
17
23
  extend: <NE extends Record<string, Endpoint>>(newEndpoints: NE) => {
18
24
  handler: (request: Request) => Promise<Response>;
19
25
  endpoints: E & NE;
20
26
  addEndpoint: (endpoint: Endpoint) => void;
27
+ findRoute: (method: string, path: string) => {
28
+ data: ((inputCtx: any) => Promise<any>) & {
29
+ options: import("@colyseus/better-call").EndpointOptions;
30
+ path: string;
31
+ } & {
32
+ path: string;
33
+ };
34
+ params: Record<string, string>;
35
+ };
21
36
  extend: <NE_1 extends Record<string, Endpoint>>(newEndpoints: NE_1) => {
22
37
  handler: (request: Request) => Promise<Response>;
23
38
  endpoints: E & NE & NE_1;
24
39
  addEndpoint: (endpoint: Endpoint) => void;
40
+ findRoute: (method: string, path: string) => {
41
+ data: ((inputCtx: any) => Promise<any>) & {
42
+ options: import("@colyseus/better-call").EndpointOptions;
43
+ path: string;
44
+ } & {
45
+ path: string;
46
+ };
47
+ params: Record<string, string>;
48
+ };
25
49
  extend: <NE_2 extends Record<string, Endpoint>>(newEndpoints: NE_2) => {
26
50
  handler: (request: Request) => Promise<Response>;
27
51
  endpoints: E & NE & NE_1 & NE_2;
28
52
  addEndpoint: (endpoint: Endpoint) => void;
53
+ findRoute: (method: string, path: string) => {
54
+ data: ((inputCtx: any) => Promise<any>) & {
55
+ options: import("@colyseus/better-call").EndpointOptions;
56
+ path: string;
57
+ } & {
58
+ path: string;
59
+ };
60
+ params: Record<string, string>;
61
+ };
29
62
  extend: <NE_3 extends Record<string, Endpoint>>(newEndpoints: NE_3) => {
30
63
  handler: (request: Request) => Promise<Response>;
31
64
  endpoints: E & NE & NE_1 & NE_2 & NE_3;
32
65
  addEndpoint: (endpoint: Endpoint) => void;
66
+ findRoute: (method: string, path: string) => {
67
+ data: ((inputCtx: any) => Promise<any>) & {
68
+ options: import("@colyseus/better-call").EndpointOptions;
69
+ path: string;
70
+ } & {
71
+ path: string;
72
+ };
73
+ params: Record<string, string>;
74
+ };
33
75
  extend: <NE_4 extends Record<string, Endpoint>>(newEndpoints: NE_4) => {
34
76
  handler: (request: Request) => Promise<Response>;
35
77
  endpoints: E & NE & NE_1 & NE_2 & NE_3 & NE_4;
36
78
  addEndpoint: (endpoint: Endpoint) => void;
79
+ findRoute: (method: string, path: string) => {
80
+ data: ((inputCtx: any) => Promise<any>) & {
81
+ options: import("@colyseus/better-call").EndpointOptions;
82
+ path: string;
83
+ } & {
84
+ path: string;
85
+ };
86
+ params: Record<string, string>;
87
+ };
37
88
  extend: <NE_5 extends Record<string, Endpoint>>(newEndpoints: NE_5) => {
38
89
  handler: (request: Request) => Promise<Response>;
39
90
  endpoints: E & NE & NE_1 & NE_2 & NE_3 & NE_4 & NE_5;
40
91
  addEndpoint: (endpoint: Endpoint) => void;
92
+ findRoute: (method: string, path: string) => {
93
+ data: ((inputCtx: any) => Promise<any>) & {
94
+ options: import("@colyseus/better-call").EndpointOptions;
95
+ path: string;
96
+ } & {
97
+ path: string;
98
+ };
99
+ params: Record<string, string>;
100
+ };
41
101
  extend: <NE_6 extends Record<string, Endpoint>>(newEndpoints: NE_6) => {
42
102
  handler: (request: Request) => Promise<Response>;
43
103
  endpoints: E & NE & NE_1 & NE_2 & NE_3 & NE_4 & NE_5 & NE_6;
44
104
  addEndpoint: (endpoint: Endpoint) => void;
105
+ findRoute: (method: string, path: string) => {
106
+ data: ((inputCtx: any) => Promise<any>) & {
107
+ options: import("@colyseus/better-call").EndpointOptions;
108
+ path: string;
109
+ } & {
110
+ path: string;
111
+ };
112
+ params: Record<string, string>;
113
+ };
45
114
  extend: <NE_7 extends Record<string, Endpoint>>(newEndpoints: NE_7) => {
46
115
  handler: (request: Request) => Promise<Response>;
47
116
  endpoints: E & NE & NE_1 & NE_2 & NE_3 & NE_4 & NE_5 & NE_6 & NE_7;
48
117
  addEndpoint: (endpoint: Endpoint) => void;
118
+ findRoute: (method: string, path: string) => {
119
+ data: ((inputCtx: any) => Promise<any>) & {
120
+ options: import("@colyseus/better-call").EndpointOptions;
121
+ path: string;
122
+ } & {
123
+ path: string;
124
+ };
125
+ params: Record<string, string>;
126
+ };
49
127
  extend: <NE_8 extends Record<string, Endpoint>>(newEndpoints: NE_8) => {
50
128
  handler: (request: Request) => Promise<Response>;
51
129
  endpoints: E & NE & NE_1 & NE_2 & NE_3 & NE_4 & NE_5 & NE_6 & NE_7 & NE_8;
52
130
  addEndpoint: (endpoint: Endpoint) => void;
131
+ findRoute: (method: string, path: string) => {
132
+ data: ((inputCtx: any) => Promise<any>) & {
133
+ options: import("@colyseus/better-call").EndpointOptions;
134
+ path: string;
135
+ } & {
136
+ path: string;
137
+ };
138
+ params: Record<string, string>;
139
+ };
53
140
  extend: <NE_9 extends Record<string, Endpoint>>(newEndpoints: NE_9) => {
54
141
  handler: (request: Request) => Promise<Response>;
55
142
  endpoints: E & NE & NE_1 & NE_2 & NE_3 & NE_4 & NE_5 & NE_6 & NE_7 & NE_8 & NE_9;
56
143
  addEndpoint: (endpoint: Endpoint) => void;
144
+ findRoute: (method: string, path: string) => {
145
+ data: ((inputCtx: any) => Promise<any>) & {
146
+ options: import("@colyseus/better-call").EndpointOptions;
147
+ path: string;
148
+ } & {
149
+ path: string;
150
+ };
151
+ params: Record<string, string>;
152
+ };
57
153
  extend: <NE_10 extends Record<string, Endpoint>>(newEndpoints: NE_10) => any;
58
154
  };
59
155
  };
@@ -1,6 +1,6 @@
1
1
  // packages/core/src/router/index.ts
2
2
  import { createRouter as createBetterCallRouter, createEndpoint } from "@colyseus/better-call";
3
- import { toNodeHandler } from "@colyseus/better-call/node";
3
+ import { toNodeHandler, getRequest, setResponse } from "@colyseus/better-call/node";
4
4
  import "../Transport.mjs";
5
5
  import { controller } from "../matchmaker/controller.mjs";
6
6
  import pkg from "../../package.json" with { type: "json" };
@@ -29,11 +29,21 @@ function bindRouterToTransport(transport, router) {
29
29
  transport.bindRouter(router);
30
30
  return;
31
31
  }
32
- let next = toNodeHandler(router.handler);
32
+ let next;
33
33
  if (expressApp) {
34
34
  server.removeListener("request", expressApp);
35
- expressApp.use(next);
36
- next = expressApp;
35
+ next = async (req, res) => {
36
+ if (router.findRoute(req.method, req.url) !== void 0) {
37
+ const protocol = req.headers["x-forwarded-proto"] || (req.socket.encrypted ? "https" : "http");
38
+ const base = `${protocol}://${req.headers[":authority"] || req.headers.host}`;
39
+ const response = await router.handler(getRequest({ base, request: req }));
40
+ return setResponse(res, response);
41
+ } else {
42
+ return expressApp["handle"](req, res);
43
+ }
44
+ };
45
+ } else {
46
+ next = toNodeHandler(router.handler);
37
47
  }
38
48
  server.prependListener("request", (req, res) => {
39
49
  const corsHeaders = {
@@ -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 //\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;",
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, getRequest, setResponse } 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 // which route handler to use\n // (router + fallback to express, or just router)\n let next: any;\n\n if (expressApp) {\n server.removeListener('request', expressApp);\n\n next = async (req: IncomingMessage, res: ServerResponse) => {\n // check if the route is defined in the router\n // if so, use the router handler, otherwise fallback to express\n if (router.findRoute(req.method, req.url) !== undefined) {\n const protocol = req.headers[\"x-forwarded-proto\"] || ((req.socket as any).encrypted ? \"https\" : \"http\");\n const base = `${protocol}://${req.headers[\":authority\"] || req.headers.host}`;\n const response = await router.handler(getRequest({ base, request: req }));\n return setResponse(res, response);\n\n } else {\n return expressApp['handle'](req, res);\n }\n };\n\n } else {\n next = toNodeHandler(router.handler);\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,eAAe,YAAY,mBAAmB;AACvD,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;AAIA,MAAI;AAEJ,MAAI,YAAY;AACd,WAAO,eAAe,WAAW,UAAU;AAE3C,WAAO,OAAO,KAAsB,QAAwB;AAG1D,UAAI,OAAO,UAAU,IAAI,QAAQ,IAAI,GAAG,MAAM,QAAW;AACvD,cAAM,WAAW,IAAI,QAAQ,mBAAmB,MAAO,IAAI,OAAe,YAAY,UAAU;AAChG,cAAM,OAAO,GAAG,QAAQ,MAAM,IAAI,QAAQ,YAAY,KAAK,IAAI,QAAQ,IAAI;AAC3E,cAAM,WAAW,MAAM,OAAO,QAAQ,WAAW,EAAE,MAAM,SAAS,IAAI,CAAC,CAAC;AACxE,eAAO,YAAY,KAAK,QAAQ;AAAA,MAElC,OAAO;AACL,eAAO,WAAW,QAAQ,EAAE,KAAK,GAAG;AAAA,MACtC;AAAA,IACF;AAAA,EAEF,OAAO;AACL,WAAO,cAAc,OAAO,OAAO;AAAA,EACrC;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.32",
3
+ "version": "0.17.34",
4
4
  "description": "Multiplayer Framework for Node.js.",
5
5
  "type": "module",
6
6
  "input": "./src/index.ts",
@@ -52,14 +52,14 @@
52
52
  "debug": "^4.3.4",
53
53
  "nanoid": "^3.3.11",
54
54
  "@colyseus/shared-types": "^0.17.6",
55
- "@colyseus/better-call": "^1.2.1",
55
+ "@colyseus/better-call": "^1.3.1",
56
56
  "@colyseus/greeting-banner": "^3.0.8"
57
57
  },
58
58
  "devDependencies": {
59
59
  "@colyseus/schema": "^4.0.7",
60
60
  "express": "^5.0.0",
61
- "@colyseus/redis-presence": "^0.17.6",
62
61
  "@colyseus/redis-driver": "^0.17.6",
62
+ "@colyseus/redis-presence": "^0.17.6",
63
63
  "@colyseus/tools": "^0.17.18"
64
64
  },
65
65
  "peerDependencies": {
@@ -67,8 +67,8 @@
67
67
  "@pm2/io": "^6.1.0",
68
68
  "express": "^4.16.0 || ^5.0.0",
69
69
  "zod": "^4.1.12",
70
- "@colyseus/better-call": "^1.2.1",
71
- "@colyseus/ws-transport": "^0.17.9"
70
+ "@colyseus/ws-transport": "^0.17.9",
71
+ "@colyseus/better-call": "^1.3.1"
72
72
  },
73
73
  "optionalPeerDependencies": {
74
74
  "@colyseus/tools": "0.17.x",