@colyseus/monitor 0.18.2 → 0.18.4

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/build/index.cjs CHANGED
@@ -33,7 +33,6 @@ __export(index_exports, {
33
33
  monitor: () => monitor
34
34
  });
35
35
  module.exports = __toCommonJS(index_exports);
36
- var import_promises = __toESM(require("fs/promises"), 1);
37
36
  var import_path = __toESM(require("path"), 1);
38
37
  var import_zod = require("zod");
39
38
  var import_core = require("@colyseus/core");
@@ -76,7 +75,8 @@ function monitor(opts = {}) {
76
75
  }),
77
76
  connections,
78
77
  cpu,
79
- memory: { totalMemMb, usedMemMb }
78
+ // rssMb is this process only — processId says which one it is
79
+ memory: { totalMemMb, usedMemMb, rssMb: process.memoryUsage.rss() / 1024 / 1024, processId: import_core.matchMaker.processId }
80
80
  };
81
81
  } catch (e) {
82
82
  console.error(e.message);
@@ -125,43 +125,10 @@ function monitor(opts = {}) {
125
125
  return (0, import_serve_static.serveStatic)(SPA_DIST, ctx.params.splat);
126
126
  })
127
127
  };
128
- const SPA_DIST_RESOLVED = import_path.default.resolve(SPA_DIST);
129
128
  return (0, import_core.dualModeEndpoints)(endpoints, {
130
129
  catchAllKey: "monitor-static",
131
- buildMiddleware: ({ specificRouter, specificHandler, fullHandler }) => (req, res, next) => {
132
- var _a2, _b2, _c;
133
- if (req.method !== "GET") {
134
- return next();
135
- }
136
- const dispatchUrl = ((_b2 = (_a2 = req.originalUrl) != null ? _a2 : req.url) != null ? _b2 : "").split("?")[0];
137
- if (prefix && dispatchUrl === prefix) {
138
- res.writeHead(301, { location: `${prefix}/` });
139
- res.end();
140
- return;
141
- }
142
- const route = specificRouter.findRoute("GET", dispatchUrl);
143
- if (route && ((_c = route.data) == null ? void 0 : _c.path) === dispatchUrl) {
144
- return specificHandler(req, res).catch(next);
145
- }
146
- if (!dispatchUrl.startsWith(prefix)) {
147
- return next();
148
- }
149
- const rel = dispatchUrl.slice(prefix.length).replace(/^\/+/, "");
150
- if (!rel || rel.includes("..")) {
151
- return next();
152
- }
153
- const filePath = import_path.default.resolve(SPA_DIST_RESOLVED, rel);
154
- if (!filePath.startsWith(SPA_DIST_RESOLVED + import_path.default.sep)) {
155
- return next();
156
- }
157
- import_promises.default.stat(filePath).then((stat) => {
158
- if (stat.isFile()) {
159
- fullHandler(req, res).catch(next);
160
- } else {
161
- next();
162
- }
163
- }).catch(() => next());
164
- }
130
+ prefix,
131
+ staticDir: SPA_DIST
165
132
  });
166
133
  }
167
134
  // Annotate the CommonJS export names for ESM import in node:
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src-backend/index.ts"],
4
- "sourcesContent": ["import fs from 'fs/promises';\nimport path from 'path';\nimport { z } from 'zod';\nimport { createEndpoint, dualModeEndpoints, matchMaker, type Endpoint } from '@colyseus/core';\nimport { OSUtils } from 'node-os-utils';\n\nimport { serveStatic } from './serve-static.js';\nimport './ext/Room.js';\n\nconst osutils = new OSUtils();\nconst UNAVAILABLE_ROOM_ERROR = \"@colyseus/monitor: room $roomId is not available anymore.\";\nconst SPA_DIST = path.resolve(import.meta.dirname, '..', 'build', 'static');\n\nexport interface MonitorOptions {\n /** Mount prefix used when spread into `createRouter`. Ignored in express-middleware mode. Defaults to `''`. */\n prefix?: string;\n /** Better-call middleware applied to every monitor endpoint \u2014 use for auth gating. */\n use?: any[];\n /** Columns shown in the rooms grid. */\n columns?: Array<\n 'roomId' |\n 'name' |\n 'clients' |\n 'maxClients' |\n 'locked' |\n 'elapsedTime' |\n { metadata: string } |\n 'processId' |\n 'publicAddress'\n >;\n}\n\nexport function monitor(opts: MonitorOptions = {}) {\n const prefix = opts.prefix ?? '/monitor';\n const use = opts.use ?? [];\n const columnsOpt = opts.columns;\n\n const endpoints: Record<string, Endpoint> = {\n 'monitor-api-rooms': createEndpoint(`${prefix}/api`, { method: 'GET', use }, async () => {\n try {\n const rooms: any[] = await matchMaker.query({});\n const columns = columnsOpt ?? ['roomId', 'name', 'clients', 'maxClients', 'locked', 'elapsedTime'];\n\n if (!columnsOpt && rooms[0] && rooms[0].publicAddress !== undefined) {\n columns.push('publicAddress');\n }\n\n let connections = 0;\n const cpuUsage = await osutils.cpu.usage();\n const cpu = cpuUsage.success ? cpuUsage.data : NaN;\n const memoryInfo = await osutils.memory.info();\n const totalMemMb = memoryInfo.success ? memoryInfo.data.total?.toMB() : NaN;\n const usedMemMb = memoryInfo.success ? memoryInfo.data.used?.toMB() : NaN;\n\n return {\n columns,\n rooms: rooms.map((room) => {\n const data = JSON.parse(JSON.stringify(room));\n connections += room.clients;\n data.locked = room.locked || false;\n data.private = room.private;\n data.maxClients = `${room.maxClients}`;\n data.elapsedTime = Date.now() - new Date(room.createdAt).getTime();\n return data;\n }),\n connections,\n cpu,\n memory: { totalMemMb, usedMemMb },\n };\n } catch (e: any) {\n console.error(e.message);\n return new Response(JSON.stringify({ message: e.message }), {\n status: 500,\n headers: { 'content-type': 'application/json' },\n });\n }\n }),\n\n 'monitor-api-room': createEndpoint(`${prefix}/api/room`, {\n method: 'GET',\n query: z.object({ roomId: z.string() }),\n use,\n }, async (ctx) => {\n const roomId = ctx.query.roomId;\n try {\n return await matchMaker.remoteRoomCall(roomId, 'getInspectData');\n } catch {\n return new Response(JSON.stringify({ message: UNAVAILABLE_ROOM_ERROR.replace('$roomId', roomId) }), {\n status: 500,\n headers: { 'content-type': 'application/json' },\n });\n }\n }),\n\n 'monitor-api-room-call': createEndpoint(`${prefix}/api/room/call`, {\n method: 'GET',\n query: z.object({ roomId: z.string(), method: z.string(), args: z.string() }),\n use,\n }, async (ctx) => {\n const { roomId, method } = ctx.query;\n try {\n const args = JSON.parse(ctx.query.args);\n const data = await matchMaker.remoteRoomCall(roomId, method, args);\n return data ?? {};\n } catch {\n return new Response(JSON.stringify({ message: UNAVAILABLE_ROOM_ERROR.replace('$roomId', roomId) }), {\n status: 500,\n headers: { 'content-type': 'application/json' },\n });\n }\n }),\n\n 'monitor-index': createEndpoint(`${prefix}/`, { method: 'GET', use }, async () => {\n return serveStatic(SPA_DIST, '');\n }),\n\n 'monitor-static': createEndpoint(`${prefix}/**:splat`, { method: 'GET', use }, async (ctx) => {\n return serveStatic(SPA_DIST, (ctx.params as any).splat);\n }),\n };\n\n const SPA_DIST_RESOLVED = path.resolve(SPA_DIST);\n\n // Express compat \u2014 works with either `app.use(\"/monitor\", monitor())` or\n // `app.use(\"/\", monitor())`. Routing decisions use originalUrl (the same\n // string better-call's getRequest uses to build the dispatched Request URL),\n // so the middleware's match check and the actual dispatch always agree.\n return dualModeEndpoints(endpoints, {\n catchAllKey: 'monitor-static',\n buildMiddleware: ({ specificRouter, specificHandler, fullHandler }) => (req, res, next) => {\n if (req.method !== 'GET') { return next(); }\n\n const dispatchUrl = ((req as any).originalUrl ?? req.url ?? '').split('?')[0]!;\n\n // Bare prefix (`/monitor`) \u2192 301 to canonical `/monitor/`.\n if (prefix && dispatchUrl === prefix) {\n res.writeHead(301, { location: `${prefix}/` });\n res.end();\n return;\n }\n\n const route = specificRouter.findRoute('GET', dispatchUrl);\n if (route && route.data?.path === dispatchUrl) {\n return specificHandler(req as any, res as any).catch(next);\n }\n\n // Asset request \u2014 only delegate if the file exists on disk.\n if (!dispatchUrl.startsWith(prefix)) { return next(); }\n const rel = dispatchUrl.slice(prefix.length).replace(/^\\/+/, '');\n if (!rel || rel.includes('..')) { return next(); }\n const filePath = path.resolve(SPA_DIST_RESOLVED, rel);\n if (!filePath.startsWith(SPA_DIST_RESOLVED + path.sep)) { return next(); }\n\n fs.stat(filePath).then((stat) => {\n if (stat.isFile()) {\n fullHandler(req as any, res as any).catch(next);\n } else {\n next();\n }\n }).catch(() => next());\n },\n });\n}\n"],
5
- "mappings": "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",
6
- "names": ["path", "_a", "_b", "fs"]
4
+ "sourcesContent": ["import path from 'path';\nimport { z } from 'zod';\nimport { createEndpoint, dualModeEndpoints, matchMaker, type Endpoint } from '@colyseus/core';\nimport { OSUtils } from 'node-os-utils';\n\nimport { serveStatic } from './serve-static.js';\nimport './ext/Room.js';\n\nconst osutils = new OSUtils();\nconst UNAVAILABLE_ROOM_ERROR = \"@colyseus/monitor: room $roomId is not available anymore.\";\nconst SPA_DIST = path.resolve(import.meta.dirname, '..', 'build', 'static');\n\nexport interface MonitorOptions {\n /** Endpoint path prefix \u2014 namespaces the routes when spread into `createRouter`, honored at root express mounts. Under a path mount (`app.use(\"/stats\", monitor())`) the mount path takes over. Defaults to `'/monitor'`. */\n prefix?: string;\n /** Better-call middleware applied to every monitor endpoint \u2014 use for auth gating. */\n use?: any[];\n /** Columns shown in the rooms grid. */\n columns?: Array<\n 'roomId' |\n 'name' |\n 'clients' |\n 'maxClients' |\n 'locked' |\n 'elapsedTime' |\n { metadata: string } |\n 'processId' |\n 'publicAddress'\n >;\n}\n\nexport function monitor(opts: MonitorOptions = {}) {\n const prefix = opts.prefix ?? '/monitor';\n const use = opts.use ?? [];\n const columnsOpt = opts.columns;\n\n const endpoints: Record<string, Endpoint> = {\n 'monitor-api-rooms': createEndpoint(`${prefix}/api`, { method: 'GET', use }, async () => {\n try {\n const rooms: any[] = await matchMaker.query({});\n const columns = columnsOpt ?? ['roomId', 'name', 'clients', 'maxClients', 'locked', 'elapsedTime'];\n\n if (!columnsOpt && rooms[0] && rooms[0].publicAddress !== undefined) {\n columns.push('publicAddress');\n }\n\n let connections = 0;\n const cpuUsage = await osutils.cpu.usage();\n const cpu = cpuUsage.success ? cpuUsage.data : NaN;\n const memoryInfo = await osutils.memory.info();\n const totalMemMb = memoryInfo.success ? memoryInfo.data.total?.toMB() : NaN;\n const usedMemMb = memoryInfo.success ? memoryInfo.data.used?.toMB() : NaN;\n\n return {\n columns,\n rooms: rooms.map((room) => {\n const data = JSON.parse(JSON.stringify(room));\n connections += room.clients;\n data.locked = room.locked || false;\n data.private = room.private;\n data.maxClients = `${room.maxClients}`;\n data.elapsedTime = Date.now() - new Date(room.createdAt).getTime();\n return data;\n }),\n connections,\n cpu,\n // rssMb is this process only \u2014 processId says which one it is\n memory: { totalMemMb, usedMemMb, rssMb: process.memoryUsage.rss() / 1024 / 1024, processId: matchMaker.processId },\n };\n } catch (e: any) {\n console.error(e.message);\n return new Response(JSON.stringify({ message: e.message }), {\n status: 500,\n headers: { 'content-type': 'application/json' },\n });\n }\n }),\n\n 'monitor-api-room': createEndpoint(`${prefix}/api/room`, {\n method: 'GET',\n query: z.object({ roomId: z.string() }),\n use,\n }, async (ctx) => {\n const roomId = ctx.query.roomId;\n try {\n return await matchMaker.remoteRoomCall(roomId, 'getInspectData');\n } catch {\n return new Response(JSON.stringify({ message: UNAVAILABLE_ROOM_ERROR.replace('$roomId', roomId) }), {\n status: 500,\n headers: { 'content-type': 'application/json' },\n });\n }\n }),\n\n 'monitor-api-room-call': createEndpoint(`${prefix}/api/room/call`, {\n method: 'GET',\n query: z.object({ roomId: z.string(), method: z.string(), args: z.string() }),\n use,\n }, async (ctx) => {\n const { roomId, method } = ctx.query;\n try {\n const args = JSON.parse(ctx.query.args);\n const data = await matchMaker.remoteRoomCall(roomId, method, args);\n return data ?? {};\n } catch {\n return new Response(JSON.stringify({ message: UNAVAILABLE_ROOM_ERROR.replace('$roomId', roomId) }), {\n status: 500,\n headers: { 'content-type': 'application/json' },\n });\n }\n }),\n\n 'monitor-index': createEndpoint(`${prefix}/`, { method: 'GET', use }, async () => {\n return serveStatic(SPA_DIST, '');\n }),\n\n 'monitor-static': createEndpoint(`${prefix}/**:splat`, { method: 'GET', use }, async (ctx) => {\n return serveStatic(SPA_DIST, (ctx.params as any).splat);\n }),\n };\n\n return dualModeEndpoints(endpoints, {\n catchAllKey: 'monitor-static',\n prefix,\n staticDir: SPA_DIST,\n });\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["path", "_a", "_b"]
7
7
  }
package/build/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { type Endpoint } from '@colyseus/core';
2
2
  import './ext/Room.js';
3
3
  export interface MonitorOptions {
4
- /** Mount prefix used when spread into `createRouter`. Ignored in express-middleware mode. Defaults to `''`. */
4
+ /** Endpoint path prefix namespaces the routes when spread into `createRouter`, honored at root express mounts. Under a path mount (`app.use("/stats", monitor())`) the mount path takes over. Defaults to `'/monitor'`. */
5
5
  prefix?: string;
6
6
  /** Better-call middleware applied to every monitor endpoint — use for auth gating. */
7
7
  use?: any[];
package/build/index.mjs CHANGED
@@ -1,5 +1,4 @@
1
1
  // src-backend/index.ts
2
- import fs from "fs/promises";
3
2
  import path from "path";
4
3
  import { z } from "zod";
5
4
  import { createEndpoint, dualModeEndpoints, matchMaker } from "@colyseus/core";
@@ -40,7 +39,8 @@ function monitor(opts = {}) {
40
39
  }),
41
40
  connections,
42
41
  cpu,
43
- memory: { totalMemMb, usedMemMb }
42
+ // rssMb is this process only — processId says which one it is
43
+ memory: { totalMemMb, usedMemMb, rssMb: process.memoryUsage.rss() / 1024 / 1024, processId: matchMaker.processId }
44
44
  };
45
45
  } catch (e) {
46
46
  console.error(e.message);
@@ -89,42 +89,10 @@ function monitor(opts = {}) {
89
89
  return serveStatic(SPA_DIST, ctx.params.splat);
90
90
  })
91
91
  };
92
- const SPA_DIST_RESOLVED = path.resolve(SPA_DIST);
93
92
  return dualModeEndpoints(endpoints, {
94
93
  catchAllKey: "monitor-static",
95
- buildMiddleware: ({ specificRouter, specificHandler, fullHandler }) => (req, res, next) => {
96
- if (req.method !== "GET") {
97
- return next();
98
- }
99
- const dispatchUrl = (req.originalUrl ?? req.url ?? "").split("?")[0];
100
- if (prefix && dispatchUrl === prefix) {
101
- res.writeHead(301, { location: `${prefix}/` });
102
- res.end();
103
- return;
104
- }
105
- const route = specificRouter.findRoute("GET", dispatchUrl);
106
- if (route && route.data?.path === dispatchUrl) {
107
- return specificHandler(req, res).catch(next);
108
- }
109
- if (!dispatchUrl.startsWith(prefix)) {
110
- return next();
111
- }
112
- const rel = dispatchUrl.slice(prefix.length).replace(/^\/+/, "");
113
- if (!rel || rel.includes("..")) {
114
- return next();
115
- }
116
- const filePath = path.resolve(SPA_DIST_RESOLVED, rel);
117
- if (!filePath.startsWith(SPA_DIST_RESOLVED + path.sep)) {
118
- return next();
119
- }
120
- fs.stat(filePath).then((stat) => {
121
- if (stat.isFile()) {
122
- fullHandler(req, res).catch(next);
123
- } else {
124
- next();
125
- }
126
- }).catch(() => next());
127
- }
94
+ prefix,
95
+ staticDir: SPA_DIST
128
96
  });
129
97
  }
130
98
  export {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src-backend/index.ts"],
4
- "sourcesContent": ["import fs from 'fs/promises';\nimport path from 'path';\nimport { z } from 'zod';\nimport { createEndpoint, dualModeEndpoints, matchMaker, type Endpoint } from '@colyseus/core';\nimport { OSUtils } from 'node-os-utils';\n\nimport { serveStatic } from './serve-static.js';\nimport './ext/Room.js';\n\nconst osutils = new OSUtils();\nconst UNAVAILABLE_ROOM_ERROR = \"@colyseus/monitor: room $roomId is not available anymore.\";\nconst SPA_DIST = path.resolve(import.meta.dirname, '..', 'build', 'static');\n\nexport interface MonitorOptions {\n /** Mount prefix used when spread into `createRouter`. Ignored in express-middleware mode. Defaults to `''`. */\n prefix?: string;\n /** Better-call middleware applied to every monitor endpoint \u2014 use for auth gating. */\n use?: any[];\n /** Columns shown in the rooms grid. */\n columns?: Array<\n 'roomId' |\n 'name' |\n 'clients' |\n 'maxClients' |\n 'locked' |\n 'elapsedTime' |\n { metadata: string } |\n 'processId' |\n 'publicAddress'\n >;\n}\n\nexport function monitor(opts: MonitorOptions = {}) {\n const prefix = opts.prefix ?? '/monitor';\n const use = opts.use ?? [];\n const columnsOpt = opts.columns;\n\n const endpoints: Record<string, Endpoint> = {\n 'monitor-api-rooms': createEndpoint(`${prefix}/api`, { method: 'GET', use }, async () => {\n try {\n const rooms: any[] = await matchMaker.query({});\n const columns = columnsOpt ?? ['roomId', 'name', 'clients', 'maxClients', 'locked', 'elapsedTime'];\n\n if (!columnsOpt && rooms[0] && rooms[0].publicAddress !== undefined) {\n columns.push('publicAddress');\n }\n\n let connections = 0;\n const cpuUsage = await osutils.cpu.usage();\n const cpu = cpuUsage.success ? cpuUsage.data : NaN;\n const memoryInfo = await osutils.memory.info();\n const totalMemMb = memoryInfo.success ? memoryInfo.data.total?.toMB() : NaN;\n const usedMemMb = memoryInfo.success ? memoryInfo.data.used?.toMB() : NaN;\n\n return {\n columns,\n rooms: rooms.map((room) => {\n const data = JSON.parse(JSON.stringify(room));\n connections += room.clients;\n data.locked = room.locked || false;\n data.private = room.private;\n data.maxClients = `${room.maxClients}`;\n data.elapsedTime = Date.now() - new Date(room.createdAt).getTime();\n return data;\n }),\n connections,\n cpu,\n memory: { totalMemMb, usedMemMb },\n };\n } catch (e: any) {\n console.error(e.message);\n return new Response(JSON.stringify({ message: e.message }), {\n status: 500,\n headers: { 'content-type': 'application/json' },\n });\n }\n }),\n\n 'monitor-api-room': createEndpoint(`${prefix}/api/room`, {\n method: 'GET',\n query: z.object({ roomId: z.string() }),\n use,\n }, async (ctx) => {\n const roomId = ctx.query.roomId;\n try {\n return await matchMaker.remoteRoomCall(roomId, 'getInspectData');\n } catch {\n return new Response(JSON.stringify({ message: UNAVAILABLE_ROOM_ERROR.replace('$roomId', roomId) }), {\n status: 500,\n headers: { 'content-type': 'application/json' },\n });\n }\n }),\n\n 'monitor-api-room-call': createEndpoint(`${prefix}/api/room/call`, {\n method: 'GET',\n query: z.object({ roomId: z.string(), method: z.string(), args: z.string() }),\n use,\n }, async (ctx) => {\n const { roomId, method } = ctx.query;\n try {\n const args = JSON.parse(ctx.query.args);\n const data = await matchMaker.remoteRoomCall(roomId, method, args);\n return data ?? {};\n } catch {\n return new Response(JSON.stringify({ message: UNAVAILABLE_ROOM_ERROR.replace('$roomId', roomId) }), {\n status: 500,\n headers: { 'content-type': 'application/json' },\n });\n }\n }),\n\n 'monitor-index': createEndpoint(`${prefix}/`, { method: 'GET', use }, async () => {\n return serveStatic(SPA_DIST, '');\n }),\n\n 'monitor-static': createEndpoint(`${prefix}/**:splat`, { method: 'GET', use }, async (ctx) => {\n return serveStatic(SPA_DIST, (ctx.params as any).splat);\n }),\n };\n\n const SPA_DIST_RESOLVED = path.resolve(SPA_DIST);\n\n // Express compat \u2014 works with either `app.use(\"/monitor\", monitor())` or\n // `app.use(\"/\", monitor())`. Routing decisions use originalUrl (the same\n // string better-call's getRequest uses to build the dispatched Request URL),\n // so the middleware's match check and the actual dispatch always agree.\n return dualModeEndpoints(endpoints, {\n catchAllKey: 'monitor-static',\n buildMiddleware: ({ specificRouter, specificHandler, fullHandler }) => (req, res, next) => {\n if (req.method !== 'GET') { return next(); }\n\n const dispatchUrl = ((req as any).originalUrl ?? req.url ?? '').split('?')[0]!;\n\n // Bare prefix (`/monitor`) \u2192 301 to canonical `/monitor/`.\n if (prefix && dispatchUrl === prefix) {\n res.writeHead(301, { location: `${prefix}/` });\n res.end();\n return;\n }\n\n const route = specificRouter.findRoute('GET', dispatchUrl);\n if (route && route.data?.path === dispatchUrl) {\n return specificHandler(req as any, res as any).catch(next);\n }\n\n // Asset request \u2014 only delegate if the file exists on disk.\n if (!dispatchUrl.startsWith(prefix)) { return next(); }\n const rel = dispatchUrl.slice(prefix.length).replace(/^\\/+/, '');\n if (!rel || rel.includes('..')) { return next(); }\n const filePath = path.resolve(SPA_DIST_RESOLVED, rel);\n if (!filePath.startsWith(SPA_DIST_RESOLVED + path.sep)) { return next(); }\n\n fs.stat(filePath).then((stat) => {\n if (stat.isFile()) {\n fullHandler(req as any, res as any).catch(next);\n } else {\n next();\n }\n }).catch(() => next());\n },\n });\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import path from 'path';\nimport { z } from 'zod';\nimport { createEndpoint, dualModeEndpoints, matchMaker, type Endpoint } from '@colyseus/core';\nimport { OSUtils } from 'node-os-utils';\n\nimport { serveStatic } from './serve-static.js';\nimport './ext/Room.js';\n\nconst osutils = new OSUtils();\nconst UNAVAILABLE_ROOM_ERROR = \"@colyseus/monitor: room $roomId is not available anymore.\";\nconst SPA_DIST = path.resolve(import.meta.dirname, '..', 'build', 'static');\n\nexport interface MonitorOptions {\n /** Endpoint path prefix \u2014 namespaces the routes when spread into `createRouter`, honored at root express mounts. Under a path mount (`app.use(\"/stats\", monitor())`) the mount path takes over. Defaults to `'/monitor'`. */\n prefix?: string;\n /** Better-call middleware applied to every monitor endpoint \u2014 use for auth gating. */\n use?: any[];\n /** Columns shown in the rooms grid. */\n columns?: Array<\n 'roomId' |\n 'name' |\n 'clients' |\n 'maxClients' |\n 'locked' |\n 'elapsedTime' |\n { metadata: string } |\n 'processId' |\n 'publicAddress'\n >;\n}\n\nexport function monitor(opts: MonitorOptions = {}) {\n const prefix = opts.prefix ?? '/monitor';\n const use = opts.use ?? [];\n const columnsOpt = opts.columns;\n\n const endpoints: Record<string, Endpoint> = {\n 'monitor-api-rooms': createEndpoint(`${prefix}/api`, { method: 'GET', use }, async () => {\n try {\n const rooms: any[] = await matchMaker.query({});\n const columns = columnsOpt ?? ['roomId', 'name', 'clients', 'maxClients', 'locked', 'elapsedTime'];\n\n if (!columnsOpt && rooms[0] && rooms[0].publicAddress !== undefined) {\n columns.push('publicAddress');\n }\n\n let connections = 0;\n const cpuUsage = await osutils.cpu.usage();\n const cpu = cpuUsage.success ? cpuUsage.data : NaN;\n const memoryInfo = await osutils.memory.info();\n const totalMemMb = memoryInfo.success ? memoryInfo.data.total?.toMB() : NaN;\n const usedMemMb = memoryInfo.success ? memoryInfo.data.used?.toMB() : NaN;\n\n return {\n columns,\n rooms: rooms.map((room) => {\n const data = JSON.parse(JSON.stringify(room));\n connections += room.clients;\n data.locked = room.locked || false;\n data.private = room.private;\n data.maxClients = `${room.maxClients}`;\n data.elapsedTime = Date.now() - new Date(room.createdAt).getTime();\n return data;\n }),\n connections,\n cpu,\n // rssMb is this process only \u2014 processId says which one it is\n memory: { totalMemMb, usedMemMb, rssMb: process.memoryUsage.rss() / 1024 / 1024, processId: matchMaker.processId },\n };\n } catch (e: any) {\n console.error(e.message);\n return new Response(JSON.stringify({ message: e.message }), {\n status: 500,\n headers: { 'content-type': 'application/json' },\n });\n }\n }),\n\n 'monitor-api-room': createEndpoint(`${prefix}/api/room`, {\n method: 'GET',\n query: z.object({ roomId: z.string() }),\n use,\n }, async (ctx) => {\n const roomId = ctx.query.roomId;\n try {\n return await matchMaker.remoteRoomCall(roomId, 'getInspectData');\n } catch {\n return new Response(JSON.stringify({ message: UNAVAILABLE_ROOM_ERROR.replace('$roomId', roomId) }), {\n status: 500,\n headers: { 'content-type': 'application/json' },\n });\n }\n }),\n\n 'monitor-api-room-call': createEndpoint(`${prefix}/api/room/call`, {\n method: 'GET',\n query: z.object({ roomId: z.string(), method: z.string(), args: z.string() }),\n use,\n }, async (ctx) => {\n const { roomId, method } = ctx.query;\n try {\n const args = JSON.parse(ctx.query.args);\n const data = await matchMaker.remoteRoomCall(roomId, method, args);\n return data ?? {};\n } catch {\n return new Response(JSON.stringify({ message: UNAVAILABLE_ROOM_ERROR.replace('$roomId', roomId) }), {\n status: 500,\n headers: { 'content-type': 'application/json' },\n });\n }\n }),\n\n 'monitor-index': createEndpoint(`${prefix}/`, { method: 'GET', use }, async () => {\n return serveStatic(SPA_DIST, '');\n }),\n\n 'monitor-static': createEndpoint(`${prefix}/**:splat`, { method: 'GET', use }, async (ctx) => {\n return serveStatic(SPA_DIST, (ctx.params as any).splat);\n }),\n };\n\n return dualModeEndpoints(endpoints, {\n catchAllKey: 'monitor-static',\n prefix,\n staticDir: SPA_DIST,\n });\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }