@babylonjs-toolkit/server 0.0.0-stage → 9.35.1

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.
Files changed (236) hide show
  1. package/CUSTOM.md +1690 -0
  2. package/DEPLOY.md +2012 -0
  3. package/README.md +1081 -2
  4. package/lib/AbuseLimits.d.ts +64 -0
  5. package/lib/AbuseLimits.js +121 -0
  6. package/lib/Authentication.d.ts +86 -0
  7. package/lib/Authentication.js +272 -0
  8. package/lib/BootSessionOwner.d.ts +86 -0
  9. package/lib/BootSessionOwner.js +116 -0
  10. package/lib/ColyseusLoggerAdapter.d.ts +32 -0
  11. package/lib/ColyseusLoggerAdapter.js +73 -0
  12. package/lib/DedicatedSceneRegistry.d.ts +52 -0
  13. package/lib/DedicatedSceneRegistry.js +74 -0
  14. package/lib/DedicatedSession.d.ts +152 -0
  15. package/lib/DedicatedSession.js +173 -0
  16. package/lib/DualTransport.d.ts +112 -0
  17. package/lib/DualTransport.js +197 -0
  18. package/lib/GameServer.d.ts +64 -0
  19. package/lib/GameServer.js +647 -0
  20. package/lib/GameServerConfig.d.ts +387 -0
  21. package/lib/GameServerConfig.js +1059 -0
  22. package/lib/GameServerLobbyRoom.d.ts +33 -0
  23. package/lib/GameServerLobbyRoom.js +56 -0
  24. package/lib/GameServerLogger.d.ts +111 -0
  25. package/lib/GameServerLogger.js +190 -0
  26. package/lib/GameServerMetrics.d.ts +158 -0
  27. package/lib/GameServerMetrics.js +276 -0
  28. package/lib/GameServerState.d.ts +164 -0
  29. package/lib/GameServerState.js +26 -0
  30. package/lib/HeadlessRuntime.d.ts +316 -0
  31. package/lib/HeadlessRuntime.js +380 -0
  32. package/lib/JoinGate.d.ts +34 -0
  33. package/lib/JoinGate.js +221 -0
  34. package/lib/NetworkAddresses.d.ts +33 -0
  35. package/lib/NetworkAddresses.js +90 -0
  36. package/lib/PlayerTokens.d.ts +17 -0
  37. package/lib/PlayerTokens.js +24 -0
  38. package/lib/RoomServerTransport.d.ts +73 -0
  39. package/lib/RoomServerTransport.js +90 -0
  40. package/lib/ServerEndpoints.d.ts +133 -0
  41. package/lib/ServerEndpoints.js +247 -0
  42. package/lib/ServerInit.d.ts +28 -0
  43. package/lib/ServerInit.js +113 -0
  44. package/lib/SessionRoom.d.ts +391 -0
  45. package/lib/SessionRoom.js +930 -0
  46. package/lib/TlsCertificates.d.ts +35 -0
  47. package/lib/TlsCertificates.js +130 -0
  48. package/lib/admin/AccountRoutes.d.ts +8 -0
  49. package/lib/admin/AccountRoutes.js +502 -0
  50. package/lib/admin/AdminAccounts.d.ts +329 -0
  51. package/lib/admin/AdminAccounts.js +607 -0
  52. package/lib/admin/AdminApiRouter.d.ts +202 -0
  53. package/lib/admin/AdminApiRouter.js +465 -0
  54. package/lib/admin/AdminApiTypes.d.ts +1782 -0
  55. package/lib/admin/AdminApiTypes.js +4 -0
  56. package/lib/admin/AdminAudit.d.ts +113 -0
  57. package/lib/admin/AdminAudit.js +266 -0
  58. package/lib/admin/AdminCli.d.ts +7 -0
  59. package/lib/admin/AdminCli.js +351 -0
  60. package/lib/admin/AdminClock.d.ts +51 -0
  61. package/lib/admin/AdminClock.js +10 -0
  62. package/lib/admin/AdminConsole.d.ts +39 -0
  63. package/lib/admin/AdminConsole.js +325 -0
  64. package/lib/admin/AdminConstants.d.ts +147 -0
  65. package/lib/admin/AdminConstants.js +167 -0
  66. package/lib/admin/AdminCrypto.d.ts +19 -0
  67. package/lib/admin/AdminCrypto.js +29 -0
  68. package/lib/admin/AdminExtensionsHost.d.ts +176 -0
  69. package/lib/admin/AdminExtensionsHost.js +307 -0
  70. package/lib/admin/AdminPasswords.d.ts +33 -0
  71. package/lib/admin/AdminPasswords.js +92 -0
  72. package/lib/admin/AdminPermissions.d.ts +28 -0
  73. package/lib/admin/AdminPermissions.js +74 -0
  74. package/lib/admin/AdminRecords.d.ts +196 -0
  75. package/lib/admin/AdminRecords.js +3 -0
  76. package/lib/admin/AdminRequestBodies.d.ts +47 -0
  77. package/lib/admin/AdminRequestBodies.js +84 -0
  78. package/lib/admin/AdminRequestGate.d.ts +38 -0
  79. package/lib/admin/AdminRequestGate.js +59 -0
  80. package/lib/admin/AdminResponses.d.ts +103 -0
  81. package/lib/admin/AdminResponses.js +164 -0
  82. package/lib/admin/AdminServices.d.ts +99 -0
  83. package/lib/admin/AdminServices.js +4 -0
  84. package/lib/admin/AdminStaticFiles.d.ts +29 -0
  85. package/lib/admin/AdminStaticFiles.js +97 -0
  86. package/lib/admin/AdminStore.d.ts +152 -0
  87. package/lib/admin/AdminStore.js +46 -0
  88. package/lib/admin/AlertChannels.d.ts +43 -0
  89. package/lib/admin/AlertChannels.js +120 -0
  90. package/lib/admin/AlertEngine.d.ts +231 -0
  91. package/lib/admin/AlertEngine.js +681 -0
  92. package/lib/admin/AlertRoutes.d.ts +8 -0
  93. package/lib/admin/AlertRoutes.js +180 -0
  94. package/lib/admin/ApiKeyRoutes.d.ts +8 -0
  95. package/lib/admin/ApiKeyRoutes.js +53 -0
  96. package/lib/admin/ApiKeys.d.ts +63 -0
  97. package/lib/admin/ApiKeys.js +167 -0
  98. package/lib/admin/AuditRoutes.d.ts +8 -0
  99. package/lib/admin/AuditRoutes.js +106 -0
  100. package/lib/admin/AuthToolRoutes.d.ts +13 -0
  101. package/lib/admin/AuthToolRoutes.js +164 -0
  102. package/lib/admin/BanList.d.ts +87 -0
  103. package/lib/admin/BanList.js +152 -0
  104. package/lib/admin/CborDecoder.d.ts +18 -0
  105. package/lib/admin/CborDecoder.js +201 -0
  106. package/lib/admin/ColyseusCloudClient.d.ts +313 -0
  107. package/lib/admin/ColyseusCloudClient.js +272 -0
  108. package/lib/admin/ColyseusCloudRoutes.d.ts +8 -0
  109. package/lib/admin/ColyseusCloudRoutes.js +91 -0
  110. package/lib/admin/ColyseusCloudService.d.ts +180 -0
  111. package/lib/admin/ColyseusCloudService.js +476 -0
  112. package/lib/admin/ColyseusCloudSettings.d.ts +16 -0
  113. package/lib/admin/ColyseusCloudSettings.js +29 -0
  114. package/lib/admin/ColyseusCloudViews.d.ts +105 -0
  115. package/lib/admin/ColyseusCloudViews.js +371 -0
  116. package/lib/admin/CommonPasswords.d.ts +6 -0
  117. package/lib/admin/CommonPasswords.js +19 -0
  118. package/lib/admin/ConfigOverrides.d.ts +174 -0
  119. package/lib/admin/ConfigOverrides.js +406 -0
  120. package/lib/admin/ConfigRoutes.d.ts +8 -0
  121. package/lib/admin/ConfigRoutes.js +91 -0
  122. package/lib/admin/ConsoleSessions.d.ts +112 -0
  123. package/lib/admin/ConsoleSessions.js +201 -0
  124. package/lib/admin/DedicatedRoutes.d.ts +21 -0
  125. package/lib/admin/DedicatedRoutes.js +254 -0
  126. package/lib/admin/ExtensionRoutes.d.ts +8 -0
  127. package/lib/admin/ExtensionRoutes.js +145 -0
  128. package/lib/admin/FileAdminStore.d.ts +157 -0
  129. package/lib/admin/FileAdminStore.js +349 -0
  130. package/lib/admin/FleetDirectory.d.ts +323 -0
  131. package/lib/admin/FleetDirectory.js +489 -0
  132. package/lib/admin/FleetLeader.d.ts +43 -0
  133. package/lib/admin/FleetLeader.js +89 -0
  134. package/lib/admin/FleetRoutes.d.ts +55 -0
  135. package/lib/admin/FleetRoutes.js +465 -0
  136. package/lib/admin/HealthWarnings.d.ts +10 -0
  137. package/lib/admin/HealthWarnings.js +95 -0
  138. package/lib/admin/LeaderboardRoutes.d.ts +8 -0
  139. package/lib/admin/LeaderboardRoutes.js +569 -0
  140. package/lib/admin/LogBuffer.d.ts +60 -0
  141. package/lib/admin/LogBuffer.js +92 -0
  142. package/lib/admin/LogRedaction.d.ts +15 -0
  143. package/lib/admin/LogRedaction.js +72 -0
  144. package/lib/admin/LogRoutes.d.ts +45 -0
  145. package/lib/admin/LogRoutes.js +307 -0
  146. package/lib/admin/MaintenanceMode.d.ts +41 -0
  147. package/lib/admin/MaintenanceMode.js +74 -0
  148. package/lib/admin/MaintenanceWindows.d.ts +91 -0
  149. package/lib/admin/MaintenanceWindows.js +207 -0
  150. package/lib/admin/MetricsRoutes.d.ts +8 -0
  151. package/lib/admin/MetricsRoutes.js +209 -0
  152. package/lib/admin/MetricsSampler.d.ts +124 -0
  153. package/lib/admin/MetricsSampler.js +211 -0
  154. package/lib/admin/OneTimeCodes.d.ts +60 -0
  155. package/lib/admin/OneTimeCodes.js +162 -0
  156. package/lib/admin/OpenIdConnect.d.ts +146 -0
  157. package/lib/admin/OpenIdConnect.js +335 -0
  158. package/lib/admin/Passkeys.d.ts +130 -0
  159. package/lib/admin/Passkeys.js +432 -0
  160. package/lib/admin/PlayerRoutes.d.ts +20 -0
  161. package/lib/admin/PlayerRoutes.js +676 -0
  162. package/lib/admin/RedisAdminStore.d.ts +114 -0
  163. package/lib/admin/RedisAdminStore.js +258 -0
  164. package/lib/admin/RolloutCoordinator.d.ts +99 -0
  165. package/lib/admin/RolloutCoordinator.js +321 -0
  166. package/lib/admin/ServerEvents.d.ts +57 -0
  167. package/lib/admin/ServerEvents.js +89 -0
  168. package/lib/admin/SessionRoutes.d.ts +113 -0
  169. package/lib/admin/SessionRoutes.js +386 -0
  170. package/lib/admin/UserRoutes.d.ts +8 -0
  171. package/lib/admin/UserRoutes.js +214 -0
  172. package/lib/cli.d.ts +2 -0
  173. package/lib/cli.js +221 -0
  174. package/lib/console/assets/index-CI5N7c-T.js +21 -0
  175. package/lib/console/assets/index-DPitvzLp.css +1 -0
  176. package/lib/console/favicon.svg +1 -0
  177. package/lib/console/index.html +16 -0
  178. package/lib/discord/DiscordOAuth.d.ts +57 -0
  179. package/lib/discord/DiscordOAuth.js +127 -0
  180. package/lib/discord/DiscordSessions.d.ts +79 -0
  181. package/lib/discord/DiscordSessions.js +135 -0
  182. package/lib/discord/DiscordSignInConstants.d.ts +54 -0
  183. package/lib/discord/DiscordSignInConstants.js +55 -0
  184. package/lib/discord/DiscordSignInRoutes.d.ts +51 -0
  185. package/lib/discord/DiscordSignInRoutes.js +359 -0
  186. package/lib/index.d.ts +24 -0
  187. package/lib/index.js +18 -0
  188. package/lib/leaderboards/FileLeaderboardRankStore.d.ts +293 -0
  189. package/lib/leaderboards/FileLeaderboardRankStore.js +808 -0
  190. package/lib/leaderboards/LeaderboardConstants.d.ts +63 -0
  191. package/lib/leaderboards/LeaderboardConstants.js +70 -0
  192. package/lib/leaderboards/LeaderboardError.d.ts +15 -0
  193. package/lib/leaderboards/LeaderboardError.js +20 -0
  194. package/lib/leaderboards/LeaderboardIdentity.d.ts +44 -0
  195. package/lib/leaderboards/LeaderboardIdentity.js +72 -0
  196. package/lib/leaderboards/LeaderboardPublicApi.d.ts +17 -0
  197. package/lib/leaderboards/LeaderboardPublicApi.js +389 -0
  198. package/lib/leaderboards/LeaderboardRankStore.d.ts +296 -0
  199. package/lib/leaderboards/LeaderboardRankStore.js +18 -0
  200. package/lib/leaderboards/LeaderboardRules.d.ts +122 -0
  201. package/lib/leaderboards/LeaderboardRules.js +472 -0
  202. package/lib/leaderboards/LeaderboardScheduler.d.ts +43 -0
  203. package/lib/leaderboards/LeaderboardScheduler.js +103 -0
  204. package/lib/leaderboards/LeaderboardService.d.ts +669 -0
  205. package/lib/leaderboards/LeaderboardService.js +1667 -0
  206. package/lib/leaderboards/LeaderboardTransfer.d.ts +35 -0
  207. package/lib/leaderboards/LeaderboardTransfer.js +580 -0
  208. package/lib/leaderboards/RedisLeaderboardRankStore.d.ts +282 -0
  209. package/lib/leaderboards/RedisLeaderboardRankStore.js +691 -0
  210. package/package.json +64 -4
  211. package/templates/init/Caddyfile +6 -0
  212. package/templates/init/DEPLOY.md +233 -0
  213. package/templates/init/Dockerfile +12 -0
  214. package/templates/init/app.json +21 -0
  215. package/templates/init/aws/README.md +118 -0
  216. package/templates/init/aws/ecs-fargate-alb.yml +207 -0
  217. package/templates/init/aws/ecs-fargate-nlb-quic.yml +210 -0
  218. package/templates/init/babylon-game-server.config.mjs +158 -0
  219. package/templates/init/colyseus-cloud/README.md +133 -0
  220. package/templates/init/colyseus-cloud/babylon-game-server.config.mjs +36 -0
  221. package/templates/init/colyseus-cloud/ecosystem.config.cjs +35 -0
  222. package/templates/init/colyseus-cloud/gitignore +6 -0
  223. package/templates/init/colyseus-cloud/package.json +15 -0
  224. package/templates/init/digitalocean-app.yaml +30 -0
  225. package/templates/init/docker-compose.full.yml +45 -0
  226. package/templates/init/docker-compose.websocket.yml +41 -0
  227. package/templates/init/fly.toml +56 -0
  228. package/templates/init/heroku.yml +11 -0
  229. package/templates/init/kubernetes/deployment.yaml +71 -0
  230. package/templates/init/kubernetes/redis.yaml +73 -0
  231. package/templates/init/kubernetes/service.yaml +24 -0
  232. package/templates/init/monitoring/grafana-dashboard.json +539 -0
  233. package/templates/init/monitoring/prometheus-alerts.yml +51 -0
  234. package/templates/init/monitoring/prometheus-scrape.yml +17 -0
  235. package/templates/init/railway.json +13 -0
  236. package/templates/init/render.yaml +19 -0
@@ -0,0 +1,325 @@
1
+ // The console's composition root (game-server-admin-console D1, D6, D30): it builds the admin services, owns the four
2
+ // router entries of the app and its API, and starts and stops the console's timers.
3
+ import { createEndpoint } from "colyseus";
4
+ import { fileURLToPath } from "node:url";
5
+ import { getLogger } from "../GameServerLogger.js";
6
+ import { registerAccountRoutes } from "./AccountRoutes.js";
7
+ import { AdminAccounts } from "./AdminAccounts.js";
8
+ import { AdminAudit } from "./AdminAudit.js";
9
+ import { ADMIN_API_PREFIX, AUDIT_RETENTION_INTERVAL_MS, CONSOLE_BASE_PATH, CONSOLE_ROOT_PATH, SESSION_SWEEP_INTERVAL_MS } from "./AdminConstants.js";
10
+ import { registerApiKeyRoutes } from "./ApiKeyRoutes.js";
11
+ import { ApiKeys } from "./ApiKeys.js";
12
+ import { registerAuditRoutes } from "./AuditRoutes.js";
13
+ import { registerUserRoutes } from "./UserRoutes.js";
14
+ import { AdminApiRouter, requestOf } from "./AdminApiRouter.js";
15
+ import { AdminRequestGate } from "./AdminRequestGate.js";
16
+ import { adminJsonResponse, consoleOriginOf, redirectResponse } from "./AdminResponses.js";
17
+ import { AdminStaticFiles } from "./AdminStaticFiles.js";
18
+ import { registerAuthToolCommands, registerAuthToolRoutes } from "./AuthToolRoutes.js";
19
+ import { ConfigOverrides } from "./ConfigOverrides.js";
20
+ import { registerConfigRoutes } from "./ConfigRoutes.js";
21
+ import { ConsoleSessions } from "./ConsoleSessions.js";
22
+ import { registerDedicatedCommands, registerDedicatedRoutes } from "./DedicatedRoutes.js";
23
+ import { FleetDirectory } from "./FleetDirectory.js";
24
+ import { createNoticePayload, registerFleetCommands, registerFleetRoutes } from "./FleetRoutes.js";
25
+ import { MaintenanceMode } from "./MaintenanceMode.js";
26
+ import { registerLogCommands, registerLogRoutes, TemporaryLogLevel } from "./LogRoutes.js";
27
+ import { registerMetricsRoutes } from "./MetricsRoutes.js";
28
+ import { MetricsSampler } from "./MetricsSampler.js";
29
+ import { BanList } from "./BanList.js";
30
+ import { registerPlayerCommands, registerPlayerRoutes, reloadBanList } from "./PlayerRoutes.js";
31
+ import { registerSessionCommands, registerSessionRoutes, RoomAdminClient } from "./SessionRoutes.js";
32
+ import { AlertEngine } from "./AlertEngine.js";
33
+ import { registerAlertRoutes } from "./AlertRoutes.js";
34
+ import { registerExtensionRoutes } from "./ExtensionRoutes.js";
35
+ import { registerColyseusCloudRoutes } from "./ColyseusCloudRoutes.js";
36
+ import { registerLeaderboardRoutes } from "./LeaderboardRoutes.js";
37
+ import { ColyseusCloudService } from "./ColyseusCloudService.js";
38
+ import { FleetLeader } from "./FleetLeader.js";
39
+ import { MaintenanceWindows } from "./MaintenanceWindows.js";
40
+ import { RolloutCoordinator } from "./RolloutCoordinator.js";
41
+ import { OpenIdConnectClient } from "./OpenIdConnect.js";
42
+ import { Passkeys } from "./Passkeys.js";
43
+ import { InstanceEventTracker, ServerEvents } from "./ServerEvents.js";
44
+ /** Where Vite builds the console app: lib/console/, beside lib/admin/. */
45
+ const CONSOLE_FILES_FOLDER = fileURLToPath(new URL("../console/", import.meta.url));
46
+ /** The asset path prefix that belongs to the API, never to the app. */
47
+ const API_ASSET_PREFIX = "api";
48
+ /** HTTP status of a refused or unknown console path. */
49
+ const HTTP_NOT_FOUND = 404;
50
+ /** HTTP status of the transport rule's refusal. */
51
+ const HTTP_FORBIDDEN = 403;
52
+ /** Warning logged when the file store would lose its data on a container restart (DR §9). */
53
+ const STORE_NOT_PERSISTENT_WARNING = "admin data is stored inside the container and will be lost on restart";
54
+ /** The console of one game server process. */
55
+ class AdminConsoleHost {
56
+ /** The shared services. */
57
+ services;
58
+ /** The built app's files. */
59
+ staticFiles;
60
+ /** The network restriction and transport rule. */
61
+ gate;
62
+ /** The API dispatcher. */
63
+ apiRouter;
64
+ /** The expired-session sweep timer, while started. */
65
+ sweepTimer = null;
66
+ /** The hourly audit retention timer, while started. */
67
+ retentionTimer = null;
68
+ /** Instances joining and getting lost, as the leader sees them. */
69
+ instanceEvents;
70
+ /**
71
+ * Builds the console's parts; nothing runs until start().
72
+ * @param services The shared services.
73
+ */
74
+ constructor(services) {
75
+ this.services = services;
76
+ this.staticFiles = new AdminStaticFiles(CONSOLE_FILES_FOLDER);
77
+ this.gate = new AdminRequestGate(services.config);
78
+ this.apiRouter = new AdminApiRouter(services, this.gate, () => this.isAvailable());
79
+ registerAccountRoutes(this.apiRouter, services);
80
+ registerUserRoutes(this.apiRouter, services);
81
+ registerApiKeyRoutes(this.apiRouter, services);
82
+ registerAuditRoutes(this.apiRouter, services);
83
+ registerFleetRoutes(this.apiRouter, services);
84
+ registerFleetCommands(services);
85
+ registerSessionRoutes(this.apiRouter, services);
86
+ registerSessionCommands(services);
87
+ registerPlayerRoutes(this.apiRouter, services);
88
+ registerPlayerCommands(services);
89
+ registerDedicatedRoutes(this.apiRouter, services);
90
+ registerDedicatedCommands(services);
91
+ registerMetricsRoutes(this.apiRouter, services);
92
+ registerLogRoutes(this.apiRouter, services);
93
+ registerLogCommands(services);
94
+ registerConfigRoutes(this.apiRouter, services);
95
+ registerAuthToolRoutes(this.apiRouter, services);
96
+ registerAuthToolCommands(services);
97
+ registerAlertRoutes(this.apiRouter, services);
98
+ registerExtensionRoutes(this.apiRouter, services);
99
+ registerColyseusCloudRoutes(this.apiRouter, services);
100
+ registerLeaderboardRoutes(this.apiRouter, services);
101
+ services.alerts.onAlertFired((alert) => services.extensions.callHook("onAlertFired", { alertId: alert.alertId, ruleId: alert.ruleId, severity: alert.severity, summary: alert.summary }));
102
+ services.maintenanceWindows.onMaintenanceChanged((enabled, message) => services.extensions.callHook("onMaintenanceChanged", { enabled: enabled, scope: "fleet", message: message, by: "maintenance window" }));
103
+ this.instanceEvents = new InstanceEventTracker(services.serverEvents);
104
+ services.leader.addTickHandler(async () => this.instanceEvents.observe(await services.fleet.listInstances()));
105
+ services.leader.addTickHandler(() => services.alerts.evaluate());
106
+ services.leader.addTickHandler(() => services.maintenanceWindows.tick());
107
+ services.leader.addTickHandler(() => services.rollouts.tick());
108
+ if (services.colyseusCloud.isConfigured)
109
+ services.leader.addTickHandler(() => services.colyseusCloud.refreshDue());
110
+ services.fleet.onChange((collection) => this.reloadCollection(collection));
111
+ services.accounts.onLockout((user, clientAddress) => this.auditLockout(user, clientAddress));
112
+ services.routeContext.auditLegacyAdmin = (action, target) => this.auditLegacyCall(action, target);
113
+ }
114
+ /**
115
+ * Builds the router endpoints of the console app and its API (D1, D6).
116
+ * @returns The endpoints, keyed for createRouter.
117
+ */
118
+ routes() {
119
+ return {
120
+ adminConsoleIndex: createEndpoint(CONSOLE_BASE_PATH, { method: "GET" }, async (context) => this.respondStatic("", context)),
121
+ adminConsoleAsset: createEndpoint(CONSOLE_BASE_PATH + "**:assetPath", { method: "GET" }, async (context) => this.respondStatic(String(context.params?.assetPath ?? ""), context)),
122
+ adminConsoleApi: createEndpoint(ADMIN_API_PREFIX + "**:apiPath", { method: ["GET", "POST", "PUT", "DELETE"], disableBody: true }, async (context) => this.apiRouter.handle(context))
123
+ };
124
+ }
125
+ /**
126
+ * Answers GET /game-server/admin with a 308 to /game-server/admin/ (see AdminConsole.redirectBarePath).
127
+ * @param request The incoming request.
128
+ * @returns The redirect, or undefined for any other request.
129
+ */
130
+ redirectBarePath(request) {
131
+ if (request.method !== "GET" || new URL(request.url).pathname !== CONSOLE_ROOT_PATH)
132
+ return undefined;
133
+ return redirectResponse(CONSOLE_BASE_PATH);
134
+ }
135
+ /** Reads the built app into memory. */
136
+ async loadFiles() {
137
+ await this.staticFiles.load();
138
+ }
139
+ /**
140
+ * Starts the console: warns when its file store would not survive a container restart, offers the first-owner
141
+ * setup link when no account exists (D30), applies the stored fleet maintenance and bans, keeps player history, joins
142
+ * the fleet (D16), samples metrics (D22), applies a stored fleet log level (D21) and this instance's own config
143
+ * overrides (D20), and sweeps expired sessions every SESSION_SWEEP_INTERVAL_MS.
144
+ */
145
+ async start() {
146
+ if (!this.services.store.isPersistent)
147
+ getLogger().warn(STORE_NOT_PERSISTENT_WARNING, { dataDir: this.services.config.admin.dataDir });
148
+ await this.services.accounts.ensureSetupLink(this.services.routeContext.urls());
149
+ await this.services.maintenance.reloadFleetSetting(this.services.store);
150
+ await reloadBanList(this.services);
151
+ await this.services.temporaryLogLevel.applyStored();
152
+ await this.services.configOverrides.reload();
153
+ this.services.state.banList = this.services.banList;
154
+ this.services.state.onPlayerSessionEvent = (event) => this.recordPlayerSession(event);
155
+ await this.services.fleet.start();
156
+ await this.services.leader.start();
157
+ this.services.metricsSampler.start();
158
+ this.sweepTimer = this.services.clock.setInterval(() => this.sweepSessions(), SESSION_SWEEP_INTERVAL_MS);
159
+ this.retentionTimer = this.services.clock.setInterval(() => this.applyAuditRetention(), AUDIT_RETENTION_INTERVAL_MS);
160
+ }
161
+ /**
162
+ * Stops the console's timers, metrics sampling and the pending log level revert, leaves the fleet, stops enforcing
163
+ * bans and removes the legacy audit and history hooks.
164
+ */
165
+ async stop() {
166
+ this.services.leader.stop();
167
+ this.services.metricsSampler.stop();
168
+ this.services.temporaryLogLevel.stop();
169
+ await this.services.fleet.stop();
170
+ this.services.state.banList = null;
171
+ this.services.state.onPlayerSessionEvent = null;
172
+ if (this.sweepTimer != null)
173
+ this.services.clock.clearInterval(this.sweepTimer);
174
+ if (this.retentionTimer != null)
175
+ this.services.clock.clearInterval(this.retentionTimer);
176
+ this.sweepTimer = null;
177
+ this.retentionTimer = null;
178
+ delete this.services.routeContext.auditLegacyAdmin;
179
+ }
180
+ /**
181
+ * Whether the API answers (R6).
182
+ * @returns True when admin.console is on and a user exists or admin.token is set.
183
+ */
184
+ async isAvailable() {
185
+ if (!this.services.config.admin.console)
186
+ return false;
187
+ return this.services.config.admin.token != null || await this.isAppAvailable();
188
+ }
189
+ /**
190
+ * Whether the app pages are served (R6): admin.console on and a user exists or a setup is pending.
191
+ * @returns True when they are served.
192
+ */
193
+ async isAppAvailable() {
194
+ if (!this.services.config.admin.console)
195
+ return false;
196
+ return this.services.accounts.hasPendingSetup() || await this.services.accounts.hasUsers();
197
+ }
198
+ /**
199
+ * Reloads what a change announcement names: the fleet maintenance setting and the config overrides, or the bans. A
200
+ * store failure is logged.
201
+ * @param collection The changed collection.
202
+ */
203
+ reloadCollection(collection) {
204
+ const logFailure = (error) => getLogger().warn("admin " + collection + " could not be reloaded", { error: String(error) });
205
+ if (collection === "settings")
206
+ this.services.maintenance.reloadFleetSetting(this.services.store).catch(logFailure);
207
+ if (collection === "settings")
208
+ this.services.configOverrides.reload().catch(logFailure);
209
+ if (collection === "bans")
210
+ reloadBanList(this.services).catch(logFailure);
211
+ }
212
+ /**
213
+ * Appends a player join or leave to the playerHistory stream, under the same rule as legacy audit records (R3).
214
+ * @param event The join or leave.
215
+ */
216
+ recordPlayerSession(event) {
217
+ this.isRecordKeepingOn()
218
+ .then((isKept) => isKept ? this.services.store.appendRecord("playerHistory", event) : undefined)
219
+ .catch((error) => getLogger().warn("player history could not be recorded", { error: String(error) }));
220
+ }
221
+ /** Applies the audit retention; a store failure is logged and retried next hour. */
222
+ applyAuditRetention() {
223
+ this.services.audit.applyRetention().catch((error) => getLogger().warn("admin audit retention failed", { error: String(error) }));
224
+ }
225
+ /**
226
+ * Audits an account lockout as the system actor.
227
+ * @param user The locked account.
228
+ * @param clientAddress The address of the last failure.
229
+ */
230
+ auditLockout(user, clientAddress) {
231
+ void this.services.audit.recordSafely({ actor: { kind: "system", id: "system", name: "system" }, clientAddress: clientAddress, processId: this.services.processId(), action: "auth.lockout", target: user.username, parameters: {}, result: { ok: true, detail: null } });
232
+ }
233
+ /**
234
+ * Audits a successful legacy admin endpoint call as the legacy token (T3). A token-only server with a file store and
235
+ * no admin account skips it, so such deployments never create the data folder (R3).
236
+ * @param action The legacy action.
237
+ * @param target The room id or session name, or null.
238
+ */
239
+ auditLegacyCall(action, target) {
240
+ const entry = { actor: { kind: "legacyToken", id: "legacy", name: "legacy admin token" }, clientAddress: null, processId: this.services.processId(), action: action, target: target, parameters: {}, result: { ok: true, detail: null } };
241
+ this.isRecordKeepingOn().then((isKept) => isKept ? this.services.audit.recordSafely(entry) : undefined, (error) => getLogger().error("admin audit record failed", { action: action, error: String(error) }));
242
+ }
243
+ /**
244
+ * Appends a server event of this instance to the activity feed.
245
+ * @param text What happened.
246
+ */
247
+ recordServerEvent(text) {
248
+ this.services.serverEvents.record(text, this.services.processId());
249
+ }
250
+ /**
251
+ * Whether the console writes records nobody asked for (R3, see ServerEvents.isRecordKeepingOn).
252
+ * @returns True when such records are kept.
253
+ */
254
+ isRecordKeepingOn() {
255
+ return this.services.serverEvents.isRecordKeepingOn();
256
+ }
257
+ /** Deletes expired sessions and pending sign-ins; a store failure is logged and retried next time. */
258
+ sweepSessions() {
259
+ this.services.sessions.sweepExpired().catch((error) => getLogger().warn("admin session sweep failed", { error: String(error) }));
260
+ }
261
+ /**
262
+ * Answers an app path: refused outside admin.allowedNetworks or while the app is off (404), never for an api/
263
+ * path (404 JSON), refused without HTTPS from other machines (403), else the static file.
264
+ * @param assetPath The path after /game-server/admin/.
265
+ * @param context The router context.
266
+ * @returns The response.
267
+ */
268
+ async respondStatic(assetPath, context) {
269
+ const headers = requestOf(context).headers;
270
+ const clientAddress = AdminRequestGate.clientAddressOf(headers);
271
+ const consoleOrigin = consoleOriginOf(headers, this.gate.isSecureRequest(headers));
272
+ const isApiPath = assetPath === API_ASSET_PREFIX || assetPath.startsWith(API_ASSET_PREFIX + "/");
273
+ if (isApiPath || !this.gate.isNetworkAllowed(clientAddress) || !(await this.isAppAvailable())) {
274
+ return adminJsonResponse(HTTP_NOT_FOUND, { error: "not found" }, consoleOrigin);
275
+ }
276
+ if (!this.gate.isTransportSafe(headers, clientAddress))
277
+ return adminJsonResponse(HTTP_FORBIDDEN, { error: "the console needs HTTPS" }, consoleOrigin);
278
+ return this.staticFiles.respond(assetPath);
279
+ }
280
+ }
281
+ /**
282
+ * Builds the console of this process: its services, its static files (read into memory now) and its API routes. The
283
+ * console is started but not listening; GameServer.ts merges routes() into the router and calls start() after listen.
284
+ * @param core What GameServer.ts hands the console.
285
+ * @returns The console.
286
+ */
287
+ export async function createAdminConsole(core) {
288
+ const sessions = new ConsoleSessions(core.store, core.clock, core.config.admin.sessionIdleMinutes, core.config.admin.sessionMaxHours);
289
+ const accounts = new AdminAccounts(core.store, core.clock, sessions, core.config.admin.console);
290
+ const apiKeys = new ApiKeys(core.store, core.clock);
291
+ const audit = new AdminAudit(core.store, core.clock, core.processId);
292
+ const fleet = new FleetDirectory(core);
293
+ const maintenance = new MaintenanceMode(core.state);
294
+ const banList = new BanList(() => core.clock.now());
295
+ const configOverrides = new ConfigOverrides(core, fleet);
296
+ // The stored fleet overrides apply before the server listens, so no session starts with the old values (D20).
297
+ await configOverrides.applyStored();
298
+ const metricsSampler = new MetricsSampler(core);
299
+ const serverEvents = new ServerEvents(core.store, core.clock, accounts);
300
+ const createWarningNotice = (text, countdownSeconds) => createNoticePayload(core, text, "warning", countdownSeconds);
301
+ const services = Object.assign({}, core, {
302
+ sessions: sessions,
303
+ accounts: accounts,
304
+ apiKeys: apiKeys,
305
+ audit: audit,
306
+ fleet: fleet,
307
+ maintenance: maintenance,
308
+ roomClient: new RoomAdminClient(),
309
+ banList: banList,
310
+ metricsSampler: metricsSampler,
311
+ temporaryLogLevel: new TemporaryLogLevel(core),
312
+ configOverrides: configOverrides,
313
+ serverEvents: serverEvents,
314
+ leader: new FleetLeader(core),
315
+ alerts: new AlertEngine(core, fleet, serverEvents, metricsSampler),
316
+ maintenanceWindows: new MaintenanceWindows(core, fleet, maintenance, serverEvents, createWarningNotice),
317
+ rollouts: new RolloutCoordinator(core, fleet, serverEvents),
318
+ passkeys: new Passkeys(core.store, core.clock, core.config.admin.passkeys, accounts),
319
+ openId: new OpenIdConnectClient(core.config.admin.oidc, core.store, core.clock, accounts),
320
+ colyseusCloud: new ColyseusCloudService(core)
321
+ });
322
+ const host = new AdminConsoleHost(services);
323
+ await host.loadFiles();
324
+ return host;
325
+ }
@@ -0,0 +1,147 @@
1
+ import type { CloudResourceName } from "./AdminApiTypes.js";
2
+ /** URL path of the console app (with its trailing slash, D1). */
3
+ export declare const CONSOLE_BASE_PATH: string;
4
+ /** URL of the console without its trailing slash (the redirect source). */
5
+ export declare const CONSOLE_ROOT_PATH: string;
6
+ /** URL path prefix of the console API (D1, D6). */
7
+ export declare const ADMIN_API_PREFIX: string;
8
+ /** Largest admin request body read, in bytes (D6). */
9
+ export declare const ADMIN_MAX_BODY_BYTES: number;
10
+ /** How long a step-up (second factor re-check) stays valid, in milliseconds (D10). */
11
+ export declare const STEP_UP_WINDOW_MS: number;
12
+ /** How long a first-owner setup link stays valid, in milliseconds (D30). */
13
+ export declare const SETUP_LINK_LIFETIME_MS: number;
14
+ /** How long a half-finished sign-in (password checked, second factor pending) stays valid, in milliseconds. */
15
+ export declare const PENDING_SIGN_IN_LIFETIME_MS: number;
16
+ /** Failed sign-ins of one account within the lockout window that lock it (spec 1). */
17
+ export declare const ACCOUNT_LOCKOUT_FAILURES: number;
18
+ /** The lockout counting window and the lock duration, in milliseconds. */
19
+ export declare const ACCOUNT_LOCKOUT_WINDOW_MS: number;
20
+ /** Failed sign-ins from one address within the lockout window before it is refused with 429. */
21
+ export declare const ADDRESS_SIGN_IN_FAILURES: number;
22
+ /** Extra delay added per recent failure before a failed sign-in answers, in milliseconds. */
23
+ export declare const SIGN_IN_DELAY_STEP_MS: number;
24
+ /** Cap of the failed sign-in delay, in milliseconds. */
25
+ export declare const SIGN_IN_DELAY_MAX_MS: number;
26
+ /** Minimum admin password length (D8). */
27
+ export declare const MINIMUM_PASSWORD_LENGTH: number;
28
+ /** Number of one-time recovery codes an account gets (D8). */
29
+ export declare const RECOVERY_CODE_COUNT: number;
30
+ /** TOTP time step, in seconds (D8). */
31
+ export declare const TOTP_STEP_SECONDS: number;
32
+ /** Digits of a TOTP code (D8). */
33
+ export declare const TOTP_DIGITS: number;
34
+ /** Steps before and after the current one a TOTP code may come from (clock skew, D8). */
35
+ export declare const TOTP_ALLOWED_DRIFT_STEPS: number;
36
+ /** Bytes of a TOTP secret (D8). */
37
+ export declare const TOTP_SECRET_BYTES: number;
38
+ /** scrypt CPU/memory cost N (D8). */
39
+ export declare const SCRYPT_COST: number;
40
+ /** scrypt block size r (D8). */
41
+ export declare const SCRYPT_BLOCK_SIZE: number;
42
+ /** scrypt parallelism p (D8). */
43
+ export declare const SCRYPT_PARALLELISM: number;
44
+ /** Bytes of a scrypt password hash (D8). */
45
+ export declare const SCRYPT_KEY_BYTES: number;
46
+ /** Bytes of a scrypt salt (D8). */
47
+ export declare const SCRYPT_SALT_BYTES: number;
48
+ /** How often each instance publishes its heartbeat, in milliseconds (D16). */
49
+ export declare const FLEET_HEARTBEAT_INTERVAL_MS: number;
50
+ /** An instance silent this long is "lost", in milliseconds (D16). */
51
+ export declare const FLEET_LOST_AFTER_MS: number;
52
+ /** A lost instance is forgotten after this long, in milliseconds (D16). */
53
+ export declare const FLEET_FORGET_AFTER_MS: number;
54
+ /** How long a fleet command waits for its reply, in milliseconds (D16). */
55
+ export declare const FLEET_COMMAND_TIMEOUT_MS: number;
56
+ /** Presence hash of the fleet's heartbeats (D16). */
57
+ export declare const FLEET_INSTANCES_KEY: string;
58
+ /** Presence topic prefix of the commands to one instance (D16). */
59
+ export declare const FLEET_COMMAND_TOPIC_PREFIX: string;
60
+ /** Presence topic prefix of a command's reply (D16). */
61
+ export declare const FLEET_REPLY_TOPIC_PREFIX: string;
62
+ /** Presence topic announcing a changed store collection (D16). */
63
+ export declare const ADMIN_CHANGED_TOPIC: string;
64
+ /** Redis key prefix of the admin store (D7). */
65
+ export declare const ADMIN_REDIS_PREFIX: string;
66
+ /** How long a kicked player is refused a fresh join to the same session, in seconds (D12). */
67
+ export declare const KICK_REJOIN_BLOCK_SECONDS: number;
68
+ /** How often a metrics sample is taken, in milliseconds (D22). */
69
+ export declare const METRICS_SAMPLE_INTERVAL_MS: number;
70
+ /** Metrics samples per hour of history (D22). */
71
+ export declare const METRICS_SAMPLES_PER_HOUR: number;
72
+ /** Store lease name of the fleet leader (D24). */
73
+ export declare const LEADER_LEASE_NAME: string;
74
+ /** How long the leader lease lasts without renewal, in milliseconds (D24). */
75
+ export declare const LEADER_LEASE_TTL_MS: number;
76
+ /** How often the leader renews its lease, in milliseconds (D24). */
77
+ export declare const LEADER_RENEW_INTERVAL_MS: number;
78
+ /** How often the leader evaluates alerts, windows and rollouts, in milliseconds (D24). */
79
+ export declare const LEADER_TICK_MS: number;
80
+ /** The PagerDuty Events v2 endpoint alert channels post to (DR §8). */
81
+ export declare const PAGERDUTY_EVENTS_URL: string;
82
+ /** Alert channel request timeout, in milliseconds (D24). */
83
+ export declare const ALERT_CHANNEL_TIMEOUT_MS: number;
84
+ /** Audit retention default, in days (D19). */
85
+ export declare const DEFAULT_AUDIT_RETENTION_DAYS: number;
86
+ /** How often audit retention runs, in milliseconds (D19). */
87
+ export declare const AUDIT_RETENTION_INTERVAL_MS: number;
88
+ /** Default automatic revert of a temporary log level, in minutes (D21). */
89
+ export declare const DEFAULT_LOG_LEVEL_REVERT_MINUTES: number;
90
+ /** Hash chain seed of the first audit record (D19). */
91
+ export declare const AUDIT_CHAIN_SEED: string;
92
+ /** The options a console override may change live (D20); every other option needs a restart (R23). */
93
+ export declare const LIVE_EDITABLE_OPTION_PATHS: string[];
94
+ /** Rows per page of server-side lists. */
95
+ export declare const ADMIN_PAGE_SIZE: number;
96
+ /** How often a console session's lastSeenAt is written, in milliseconds. */
97
+ export declare const SESSION_TOUCH_INTERVAL_MS: number;
98
+ /** How often an API key's lastUsedAt is written, in milliseconds. */
99
+ export declare const API_KEY_TOUCH_INTERVAL_MS: number;
100
+ /** How often expired console sessions and pending sign-ins are swept, in milliseconds. */
101
+ export declare const SESSION_SWEEP_INTERVAL_MS: number;
102
+ /** OpenID discovery cache lifetime, in milliseconds. */
103
+ export declare const OIDC_DISCOVERY_CACHE_MS: number;
104
+ /** How often Colyseus refreshes each Cloud API resource, in seconds; the leader refreshes no faster (colyseus-cloud-console D4). */
105
+ export declare const COLYSEUS_CLOUD_REFRESH_SECONDS: Readonly<Record<CloudResourceName, number>>;
106
+ /** Cloud API request timeout, in milliseconds. */
107
+ export declare const COLYSEUS_CLOUD_TIMEOUT_MS: number;
108
+ /** Seconds to wait after a 429, 5xx or no answer when Retry-After is missing or not a number (Colyseus's polling guide). */
109
+ export declare const COLYSEUS_CLOUD_DEFAULT_RETRY_SECONDS: number;
110
+ /** Fewest seconds to wait after a 429, 5xx or no answer. */
111
+ export declare const COLYSEUS_CLOUD_MIN_RETRY_SECONDS: number;
112
+ /** Slack when deciding a resource is due, in milliseconds, so a tick a little early still refreshes. */
113
+ export declare const COLYSEUS_CLOUD_DUE_TOLERANCE_MS: number;
114
+ /** A part counts as stale once its data is older than this many refresh intervals plus COLYSEUS_CLOUD_STALE_GRACE_MS. */
115
+ export declare const COLYSEUS_CLOUD_STALE_REFRESH_MULTIPLIER: number;
116
+ /** Grace beyond the stale multiple, in milliseconds. */
117
+ export declare const COLYSEUS_CLOUD_STALE_GRACE_MS: number;
118
+ /** Fewest milliseconds between two log requests of the fleet (Colyseus allows 2 a minute per team). */
119
+ export declare const COLYSEUS_CLOUD_LOG_INTERVAL_MS: number;
120
+ /** How long a log answer is shared with other askers of the same instance, stream and lines, in milliseconds. */
121
+ export declare const COLYSEUS_CLOUD_SHARED_LOGS_MS: number;
122
+ /** How long one process reuses a deploy's output, in milliseconds (Colyseus refreshes deploys every 15 s). */
123
+ export declare const COLYSEUS_CLOUD_DEPLOY_DETAIL_CACHE_MS: number;
124
+ /** How many recent deploys the page lists. */
125
+ export declare const COLYSEUS_CLOUD_DEPLOY_LIMIT: number;
126
+ /** Milliseconds per second, for Colyseus's second-based intervals and Retry-After. */
127
+ export declare const MILLISECONDS_PER_SECOND: number;
128
+ /** Passkey and OIDC challenge lifetime, in milliseconds. */
129
+ export declare const CHALLENGE_LIFETIME_MS: number;
130
+ /** More live players than this on one address marks it as a possible shared proxy (ban confirmation). */
131
+ export declare const SHARED_ADDRESS_PLAYER_THRESHOLD: number;
132
+ /** The newAdminAddress alert looks this many days back. */
133
+ export declare const NEW_ADMIN_ADDRESS_LOOKBACK_DAYS: number;
134
+ /** Longest notice text, in characters. */
135
+ export declare const NOTICE_TEXT_MAX_LENGTH: number;
136
+ /** Resolution of the event-loop delay monitor, in milliseconds. */
137
+ export declare const EVENT_LOOP_MONITOR_RESOLUTION_MS: number;
138
+ /** Length of one dedicated frame statistics bucket, in seconds. */
139
+ export declare const DEDICATED_FRAME_BUCKET_SECONDS: number;
140
+ /** Dedicated frame statistics buckets kept (one hour). */
141
+ export declare const DEDICATED_FRAME_BUCKET_COUNT: number;
142
+ /** Window of a room's traffic rate, in milliseconds. */
143
+ export declare const ROOM_TRAFFIC_WINDOW_MS: number;
144
+ /** Timeout of a room admin call, in milliseconds. */
145
+ export declare const ROOM_CALL_TIMEOUT_MS: number;
146
+ /** Timeout of a dedicated session stop, in milliseconds. */
147
+ export declare const ROOM_STOP_TIMEOUT_MS: number;
@@ -0,0 +1,167 @@
1
+ // Constants of the admin console and its API (game-server-admin-console DR §3 and §13 R23). Times are in milliseconds
2
+ // unless the name says otherwise.
3
+ /** URL path of the console app (with its trailing slash, D1). */
4
+ export const CONSOLE_BASE_PATH = "/game-server/admin/";
5
+ /** URL of the console without its trailing slash (the redirect source). */
6
+ export const CONSOLE_ROOT_PATH = "/game-server/admin";
7
+ /** URL path prefix of the console API (D1, D6). */
8
+ export const ADMIN_API_PREFIX = "/game-server/admin/api/";
9
+ /** Largest admin request body read, in bytes (D6). */
10
+ export const ADMIN_MAX_BODY_BYTES = 1048576;
11
+ /** How long a step-up (second factor re-check) stays valid, in milliseconds (D10). */
12
+ export const STEP_UP_WINDOW_MS = 300000;
13
+ /** How long a first-owner setup link stays valid, in milliseconds (D30). */
14
+ export const SETUP_LINK_LIFETIME_MS = 1800000;
15
+ /** How long a half-finished sign-in (password checked, second factor pending) stays valid, in milliseconds. */
16
+ export const PENDING_SIGN_IN_LIFETIME_MS = 300000;
17
+ /** Failed sign-ins of one account within the lockout window that lock it (spec 1). */
18
+ export const ACCOUNT_LOCKOUT_FAILURES = 10;
19
+ /** The lockout counting window and the lock duration, in milliseconds. */
20
+ export const ACCOUNT_LOCKOUT_WINDOW_MS = 900000;
21
+ /** Failed sign-ins from one address within the lockout window before it is refused with 429. */
22
+ export const ADDRESS_SIGN_IN_FAILURES = 30;
23
+ /** Extra delay added per recent failure before a failed sign-in answers, in milliseconds. */
24
+ export const SIGN_IN_DELAY_STEP_MS = 250;
25
+ /** Cap of the failed sign-in delay, in milliseconds. */
26
+ export const SIGN_IN_DELAY_MAX_MS = 2000;
27
+ /** Minimum admin password length (D8). */
28
+ export const MINIMUM_PASSWORD_LENGTH = 12;
29
+ /** Number of one-time recovery codes an account gets (D8). */
30
+ export const RECOVERY_CODE_COUNT = 10;
31
+ /** TOTP time step, in seconds (D8). */
32
+ export const TOTP_STEP_SECONDS = 30;
33
+ /** Digits of a TOTP code (D8). */
34
+ export const TOTP_DIGITS = 6;
35
+ /** Steps before and after the current one a TOTP code may come from (clock skew, D8). */
36
+ export const TOTP_ALLOWED_DRIFT_STEPS = 1;
37
+ /** Bytes of a TOTP secret (D8). */
38
+ export const TOTP_SECRET_BYTES = 20;
39
+ /** scrypt CPU/memory cost N (D8). */
40
+ export const SCRYPT_COST = 16384;
41
+ /** scrypt block size r (D8). */
42
+ export const SCRYPT_BLOCK_SIZE = 8;
43
+ /** scrypt parallelism p (D8). */
44
+ export const SCRYPT_PARALLELISM = 1;
45
+ /** Bytes of a scrypt password hash (D8). */
46
+ export const SCRYPT_KEY_BYTES = 64;
47
+ /** Bytes of a scrypt salt (D8). */
48
+ export const SCRYPT_SALT_BYTES = 16;
49
+ /** How often each instance publishes its heartbeat, in milliseconds (D16). */
50
+ export const FLEET_HEARTBEAT_INTERVAL_MS = 5000;
51
+ /** An instance silent this long is "lost", in milliseconds (D16). */
52
+ export const FLEET_LOST_AFTER_MS = 15000;
53
+ /** A lost instance is forgotten after this long, in milliseconds (D16). */
54
+ export const FLEET_FORGET_AFTER_MS = 600000;
55
+ /** How long a fleet command waits for its reply, in milliseconds (D16). */
56
+ export const FLEET_COMMAND_TIMEOUT_MS = 5000;
57
+ /** Presence hash of the fleet's heartbeats (D16). */
58
+ export const FLEET_INSTANCES_KEY = "bgs:fleet:instances";
59
+ /** Presence topic prefix of the commands to one instance (D16). */
60
+ export const FLEET_COMMAND_TOPIC_PREFIX = "bgs:fleet:command:";
61
+ /** Presence topic prefix of a command's reply (D16). */
62
+ export const FLEET_REPLY_TOPIC_PREFIX = "bgs:fleet:reply:";
63
+ /** Presence topic announcing a changed store collection (D16). */
64
+ export const ADMIN_CHANGED_TOPIC = "bgs:admin:changed";
65
+ /** Redis key prefix of the admin store (D7). */
66
+ export const ADMIN_REDIS_PREFIX = "bgs:admin:";
67
+ /** How long a kicked player is refused a fresh join to the same session, in seconds (D12). */
68
+ export const KICK_REJOIN_BLOCK_SECONDS = 300;
69
+ /** How often a metrics sample is taken, in milliseconds (D22). */
70
+ export const METRICS_SAMPLE_INTERVAL_MS = 15000;
71
+ /** Metrics samples per hour of history (D22). */
72
+ export const METRICS_SAMPLES_PER_HOUR = 240;
73
+ /** Store lease name of the fleet leader (D24). */
74
+ export const LEADER_LEASE_NAME = "fleet-leader";
75
+ /** How long the leader lease lasts without renewal, in milliseconds (D24). */
76
+ export const LEADER_LEASE_TTL_MS = 30000;
77
+ /** How often the leader renews its lease, in milliseconds (D24). */
78
+ export const LEADER_RENEW_INTERVAL_MS = 10000;
79
+ /** How often the leader evaluates alerts, windows and rollouts, in milliseconds (D24). */
80
+ export const LEADER_TICK_MS = 15000;
81
+ /** The PagerDuty Events v2 endpoint alert channels post to (DR §8). */
82
+ export const PAGERDUTY_EVENTS_URL = "https://events.pagerduty.com/v2/enqueue";
83
+ /** Alert channel request timeout, in milliseconds (D24). */
84
+ export const ALERT_CHANNEL_TIMEOUT_MS = 5000;
85
+ /** Audit retention default, in days (D19). */
86
+ export const DEFAULT_AUDIT_RETENTION_DAYS = 365;
87
+ /** How often audit retention runs, in milliseconds (D19). */
88
+ export const AUDIT_RETENTION_INTERVAL_MS = 3600000;
89
+ /** Default automatic revert of a temporary log level, in minutes (D21). */
90
+ export const DEFAULT_LOG_LEVEL_REVERT_MINUTES = 30;
91
+ /** Hash chain seed of the first audit record (D19). */
92
+ export const AUDIT_CHAIN_SEED = "0".repeat(64);
93
+ /** The options a console override may change live (D20); every other option needs a restart (R23). */
94
+ export const LIVE_EDITABLE_OPTION_PATHS = [
95
+ "logLevel",
96
+ "limits.allowedOrigins",
97
+ "limits.allowMissingOrigin",
98
+ "limits.joinRequestsPerMinutePerAddress",
99
+ "limits.maxSessions",
100
+ "limits.maxPlayersPerSession",
101
+ "limits.maxDedicatedSessions",
102
+ "limits.maxMessagesPerSecond",
103
+ "limits.maxSessionNameLength",
104
+ "drainSeconds",
105
+ "admin.grafanaUrl"
106
+ ];
107
+ /** Rows per page of server-side lists. */
108
+ export const ADMIN_PAGE_SIZE = 50;
109
+ /** How often a console session's lastSeenAt is written, in milliseconds. */
110
+ export const SESSION_TOUCH_INTERVAL_MS = 60000;
111
+ /** How often an API key's lastUsedAt is written, in milliseconds. */
112
+ export const API_KEY_TOUCH_INTERVAL_MS = 60000;
113
+ /** How often expired console sessions and pending sign-ins are swept, in milliseconds. */
114
+ export const SESSION_SWEEP_INTERVAL_MS = 600000;
115
+ /** OpenID discovery cache lifetime, in milliseconds. */
116
+ export const OIDC_DISCOVERY_CACHE_MS = 600000;
117
+ /** How often Colyseus refreshes each Cloud API resource, in seconds; the leader refreshes no faster (colyseus-cloud-console D4). */
118
+ export const COLYSEUS_CLOUD_REFRESH_SECONDS = {
119
+ applications: 60,
120
+ metricsCurrent: 30,
121
+ metricsDay: 600,
122
+ egress: 600,
123
+ deploys: 15,
124
+ billing: 600
125
+ };
126
+ /** Cloud API request timeout, in milliseconds. */
127
+ export const COLYSEUS_CLOUD_TIMEOUT_MS = 10000;
128
+ /** Seconds to wait after a 429, 5xx or no answer when Retry-After is missing or not a number (Colyseus's polling guide). */
129
+ export const COLYSEUS_CLOUD_DEFAULT_RETRY_SECONDS = 30;
130
+ /** Fewest seconds to wait after a 429, 5xx or no answer. */
131
+ export const COLYSEUS_CLOUD_MIN_RETRY_SECONDS = 5;
132
+ /** Slack when deciding a resource is due, in milliseconds, so a tick a little early still refreshes. */
133
+ export const COLYSEUS_CLOUD_DUE_TOLERANCE_MS = 1000;
134
+ /** A part counts as stale once its data is older than this many refresh intervals plus COLYSEUS_CLOUD_STALE_GRACE_MS. */
135
+ export const COLYSEUS_CLOUD_STALE_REFRESH_MULTIPLIER = 2;
136
+ /** Grace beyond the stale multiple, in milliseconds. */
137
+ export const COLYSEUS_CLOUD_STALE_GRACE_MS = 30000;
138
+ /** Fewest milliseconds between two log requests of the fleet (Colyseus allows 2 a minute per team). */
139
+ export const COLYSEUS_CLOUD_LOG_INTERVAL_MS = 30000;
140
+ /** How long a log answer is shared with other askers of the same instance, stream and lines, in milliseconds. */
141
+ export const COLYSEUS_CLOUD_SHARED_LOGS_MS = 60000;
142
+ /** How long one process reuses a deploy's output, in milliseconds (Colyseus refreshes deploys every 15 s). */
143
+ export const COLYSEUS_CLOUD_DEPLOY_DETAIL_CACHE_MS = 15000;
144
+ /** How many recent deploys the page lists. */
145
+ export const COLYSEUS_CLOUD_DEPLOY_LIMIT = 20;
146
+ /** Milliseconds per second, for Colyseus's second-based intervals and Retry-After. */
147
+ export const MILLISECONDS_PER_SECOND = 1000;
148
+ /** Passkey and OIDC challenge lifetime, in milliseconds. */
149
+ export const CHALLENGE_LIFETIME_MS = 300000;
150
+ /** More live players than this on one address marks it as a possible shared proxy (ban confirmation). */
151
+ export const SHARED_ADDRESS_PLAYER_THRESHOLD = 5;
152
+ /** The newAdminAddress alert looks this many days back. */
153
+ export const NEW_ADMIN_ADDRESS_LOOKBACK_DAYS = 90;
154
+ /** Longest notice text, in characters. */
155
+ export const NOTICE_TEXT_MAX_LENGTH = 500;
156
+ /** Resolution of the event-loop delay monitor, in milliseconds. */
157
+ export const EVENT_LOOP_MONITOR_RESOLUTION_MS = 20;
158
+ /** Length of one dedicated frame statistics bucket, in seconds. */
159
+ export const DEDICATED_FRAME_BUCKET_SECONDS = 15;
160
+ /** Dedicated frame statistics buckets kept (one hour). */
161
+ export const DEDICATED_FRAME_BUCKET_COUNT = 240;
162
+ /** Window of a room's traffic rate, in milliseconds. */
163
+ export const ROOM_TRAFFIC_WINDOW_MS = 5000;
164
+ /** Timeout of a room admin call, in milliseconds. */
165
+ export const ROOM_CALL_TIMEOUT_MS = 5000;
166
+ /** Timeout of a dedicated session stop, in milliseconds. */
167
+ export const ROOM_STOP_TIMEOUT_MS = 30000;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * A random token, URL-safe.
3
+ * @param byteCount Random bytes in the token.
4
+ * @returns base64url text.
5
+ */
6
+ export declare function randomToken(byteCount: number): string;
7
+ /**
8
+ * The SHA-256 of a text, as stored ids of secrets (session cookies, pending tokens, key secrets).
9
+ * @param text The text.
10
+ * @returns Lower-case hex.
11
+ */
12
+ export declare function sha256Hex(text: string): string;
13
+ /**
14
+ * Compares two texts in constant time when their lengths are equal.
15
+ * @param left One text.
16
+ * @param right The other.
17
+ * @returns True when equal.
18
+ */
19
+ export declare function textsMatch(left: string, right: string): boolean;