omegga 1.5.2 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/CHANGELOG.md +19 -2
  2. package/bin/omegga +1 -1
  3. package/dist/cli/terminal.js +46 -0
  4. package/dist/cli/terminal.js.map +1 -1
  5. package/dist/omegga/commandInjector.js +13 -6
  6. package/dist/omegga/commandInjector.js.map +1 -1
  7. package/dist/omegga/player.js +2 -2
  8. package/dist/omegga/player.js.map +1 -1
  9. package/dist/plugin.js.map +1 -1
  10. package/dist/webserver/backend/database.js +219 -7
  11. package/dist/webserver/backend/database.js.map +1 -1
  12. package/dist/webserver/backend/events.js +1 -1
  13. package/dist/webserver/backend/events.js.map +1 -1
  14. package/dist/webserver/backend/index.js +120 -2
  15. package/dist/webserver/backend/index.js.map +1 -1
  16. package/dist/webserver/backend/permissions.js +74 -0
  17. package/dist/webserver/backend/permissions.js.map +1 -0
  18. package/dist/webserver/backend/router/chat.js +9 -7
  19. package/dist/webserver/backend/router/chat.js.map +1 -1
  20. package/dist/webserver/backend/router/index.js +3 -1
  21. package/dist/webserver/backend/router/index.js.map +1 -1
  22. package/dist/webserver/backend/router/mfa.js +162 -0
  23. package/dist/webserver/backend/router/mfa.js.map +1 -0
  24. package/dist/webserver/backend/router/player.js +7 -6
  25. package/dist/webserver/backend/router/player.js.map +1 -1
  26. package/dist/webserver/backend/router/plugin.js +14 -10
  27. package/dist/webserver/backend/router/plugin.js.map +1 -1
  28. package/dist/webserver/backend/router/role.js +2 -1
  29. package/dist/webserver/backend/router/role.js.map +1 -1
  30. package/dist/webserver/backend/router/server.js +85 -71
  31. package/dist/webserver/backend/router/server.js.map +1 -1
  32. package/dist/webserver/backend/router/session.js +11 -2
  33. package/dist/webserver/backend/router/session.js.map +1 -1
  34. package/dist/webserver/backend/router/user.js +175 -13
  35. package/dist/webserver/backend/router/user.js.map +1 -1
  36. package/dist/webserver/backend/router/world.js +10 -9
  37. package/dist/webserver/backend/router/world.js.map +1 -1
  38. package/dist/webserver/backend/scopes.js +303 -0
  39. package/dist/webserver/backend/scopes.js.map +1 -0
  40. package/dist/webserver/backend/totp.js +32 -0
  41. package/dist/webserver/backend/totp.js.map +1 -0
  42. package/dist/webserver/backend/trpc.js +47 -4
  43. package/dist/webserver/backend/trpc.js.map +1 -1
  44. package/doc/permissions.md +193 -0
  45. package/package.json +7 -2
  46. package/public/app.html +932 -526
  47. package/public/assets/IconShieldCheck-Bjlm8mX2.js +2 -0
  48. package/public/assets/IconShieldCheck-Bjlm8mX2.js.map +1 -0
  49. package/public/assets/IconWorld-XmQNg6JI.js +2 -0
  50. package/public/assets/IconWorld-XmQNg6JI.js.map +1 -0
  51. package/public/assets/IconWorldPlus-CxGGv2eD.js +2 -0
  52. package/public/assets/IconWorldPlus-CxGGv2eD.js.map +1 -0
  53. package/public/assets/app-DMr_-wik.js +7 -0
  54. package/public/assets/app-DMr_-wik.js.map +1 -0
  55. package/public/assets/auth-CEYiizOt.js +2 -0
  56. package/public/assets/auth-CEYiizOt.js.map +1 -0
  57. package/public/assets/index-BDkarAkX.js +3 -0
  58. package/public/assets/index-BDkarAkX.js.map +1 -0
  59. package/public/assets/{index-2cgXLhrt.js → index-DEL-PD_8.js} +2 -2
  60. package/public/assets/{index-2cgXLhrt.js.map → index-DEL-PD_8.js.map} +1 -1
  61. package/public/assets/index-D_STNela.js +2 -0
  62. package/public/assets/index-D_STNela.js.map +1 -0
  63. package/public/assets/index-Dkh3HiBz.js +4 -0
  64. package/public/assets/index-Dkh3HiBz.js.map +1 -0
  65. package/public/assets/shared/@components-CgsSYMe6.js +2 -0
  66. package/public/assets/shared/@components-CgsSYMe6.js.map +1 -0
  67. package/public/assets/shared/@hooks-DT93N7wd.js +2 -0
  68. package/public/assets/shared/{@hooks-Ch_hJYh0.js.map → @hooks-DT93N7wd.js.map} +1 -1
  69. package/public/assets/shared/@tabler_icons-react-DrVFX3uL.js +3 -0
  70. package/public/assets/shared/{@tabler_icons-react-iQk11eD_.js.map → @tabler_icons-react-DrVFX3uL.js.map} +1 -1
  71. package/public/assets/shared/{wouter-CUC1caxu.js → wouter-CNISJ5i6.js} +2 -2
  72. package/public/assets/shared/wouter-CNISJ5i6.js.map +1 -0
  73. package/public/assets/useHasScope-BOdFktko.js +2 -0
  74. package/public/assets/useHasScope-BOdFktko.js.map +1 -0
  75. package/public/auth.html +97 -33
  76. package/templates/safe-ts/omegga.d.ts +1 -1
  77. package/public/assets/IconArrowRight-BuVxhqKX.js +0 -2
  78. package/public/assets/IconArrowRight-BuVxhqKX.js.map +0 -1
  79. package/public/assets/IconWorld-B6GK5qpx.js +0 -2
  80. package/public/assets/IconWorld-B6GK5qpx.js.map +0 -1
  81. package/public/assets/IconWorldPlus-Dkos72Ws.js +0 -2
  82. package/public/assets/IconWorldPlus-Dkos72Ws.js.map +0 -1
  83. package/public/assets/app-CLZ-5FIi.js +0 -6
  84. package/public/assets/app-CLZ-5FIi.js.map +0 -1
  85. package/public/assets/auth-6N37o421.js +0 -2
  86. package/public/assets/auth-6N37o421.js.map +0 -1
  87. package/public/assets/index-DLZ8-XzO.js +0 -4
  88. package/public/assets/index-DLZ8-XzO.js.map +0 -1
  89. package/public/assets/index-DY750sgZ.js +0 -2
  90. package/public/assets/index-DY750sgZ.js.map +0 -1
  91. package/public/assets/shared/@components-DPHARroA.js +0 -2
  92. package/public/assets/shared/@components-DPHARroA.js.map +0 -1
  93. package/public/assets/shared/@hooks-Ch_hJYh0.js +0 -2
  94. package/public/assets/shared/@tabler_icons-react-iQk11eD_.js +0 -3
  95. package/public/assets/shared/wouter-CUC1caxu.js.map +0 -1
@@ -6,11 +6,12 @@ const time = require("../../../util/time.js");
6
6
  const uuid = require("../../../util/uuid.js");
7
7
  const _ = require("lodash");
8
8
  const v4 = require("zod/v4");
9
+ const scopes = require("../scopes.js");
9
10
  const trpc = require("../trpc.js");
10
11
  const util = require("../util.js");
11
12
  const playerRouter = trpc.router({
12
13
  player: trpc.router({
13
- list: trpc.protectedProcedure().input(
14
+ list: trpc.protectedProcedure(scopes.ScopeName.PlayerList).input(
14
15
  v4.z.object({
15
16
  page: v4.z.number().optional().default(0),
16
17
  search: v4.z.string().optional().default(""),
@@ -68,7 +69,7 @@ const playerRouter = trpc.router({
68
69
  });
69
70
  return { ...resp, players };
70
71
  }),
71
- get: trpc.protectedProcedure().input(v4.z.string()).query(async ({ input: id }) => {
72
+ get: trpc.protectedProcedure(scopes.ScopeName.PlayerGet).input(v4.z.string()).query(async ({ input: id }) => {
72
73
  const { database, omegga } = trpc.getContextDeps();
73
74
  const entry = await database.getPlayer(id);
74
75
  if (!entry) return null;
@@ -138,7 +139,7 @@ const playerRouter = trpc.router({
138
139
  })
139
140
  };
140
141
  }),
141
- ban: trpc.protectedProcedure().input(
142
+ ban: trpc.protectedProcedure(scopes.ScopeName.PlayerBan).input(
142
143
  v4.z.object({
143
144
  id: v4.z.string(),
144
145
  duration: v4.z.number().optional().default(-1),
@@ -178,7 +179,7 @@ const playerRouter = trpc.router({
178
179
  }
179
180
  return !!ban;
180
181
  }),
181
- kick: trpc.protectedProcedure().input(
182
+ kick: trpc.protectedProcedure(scopes.ScopeName.PlayerKick).input(
182
183
  v4.z.object({
183
184
  id: v4.z.string(),
184
185
  reason: v4.z.string().max(128).optional().default("No Reason")
@@ -214,7 +215,7 @@ const playerRouter = trpc.router({
214
215
  }
215
216
  return ok;
216
217
  }),
217
- unban: trpc.protectedProcedure().input(v4.z.object({ id: v4.z.string() })).mutation(async ({ input, ctx }) => {
218
+ unban: trpc.protectedProcedure(scopes.ScopeName.PlayerUnban).input(v4.z.object({ id: v4.z.string() })).mutation(async ({ input, ctx }) => {
218
219
  const { database, omegga } = trpc.getContextDeps();
219
220
  const { id } = input;
220
221
  if (!uuid.match(id)) return false;
@@ -231,7 +232,7 @@ const playerRouter = trpc.router({
231
232
  });
232
233
  return ok;
233
234
  }),
234
- clearBricks: trpc.protectedProcedure().input(v4.z.object({ id: v4.z.string() })).mutation(async ({ input, ctx }) => {
235
+ clearBricks: trpc.protectedProcedure(scopes.ScopeName.PlayerClearBricks).input(v4.z.object({ id: v4.z.string() })).mutation(async ({ input, ctx }) => {
235
236
  const { omegga } = trpc.getContextDeps();
236
237
  const { id } = input;
237
238
  if (!uuid.match(id)) return false;
@@ -1 +1 @@
1
- {"version":3,"file":"player.js","sources":["../../../../src/webserver/backend/router/player.ts"],"sourcesContent":["import Player from '@omegga/player';\nimport { rgbToHex } from '@util/color';\nimport { parseBrickadiaTime } from '@util/time';\nimport * as uuid from '@util/uuid';\nimport _ from 'lodash';\nimport { z } from 'zod/v4';\nimport { getContextDeps, protectedProcedure, router } from '../trpc';\nimport type { IStoreBanHistory, IStoreKickHistory } from '../types';\nimport { waitForEvent } from '../util';\n\nexport const playerRouter = router({\n player: router({\n list: protectedProcedure('player.list')\n .input(\n z.object({\n page: z.number().optional().default(0),\n search: z.string().optional().default(''),\n sort: z.string().optional().default('name'),\n direction: z.number().optional().default(1),\n filter: z.string().optional().default(''),\n }),\n )\n .query(async ({ input }) => {\n const { database, omegga } = getContextDeps();\n const { page, search, sort, direction, filter } = input;\n const banList = (omegga.getBanList() || { banList: {} }).banList;\n const now = Date.now();\n let limitId: string[] | undefined;\n if (filter === 'banned') {\n limitId = Object.keys(banList).filter(\n b =>\n banList[b].expires <= banList[b].created ||\n parseBrickadiaTime(banList[b].expires) > Date.now(),\n );\n }\n const resp = await database.getPlayers({\n page,\n search,\n sort,\n direction,\n limitId,\n });\n const players = resp.players.map(player => {\n const foundBan = banList[player.id];\n let ban: {\n bannerId: string;\n reason: string;\n created: number;\n expires: number;\n duration: number;\n remainingTime: number;\n bannerName: string;\n } | null = null;\n if (foundBan) {\n const created = parseBrickadiaTime(foundBan.created);\n const expires = parseBrickadiaTime(foundBan.expires);\n const duration = expires - created;\n if (!(expires < now && duration > 0)) {\n ban = {\n bannerId: foundBan.bannerId,\n reason: foundBan.reason,\n created,\n expires,\n duration,\n remainingTime: expires - now,\n bannerName: _.get(\n omegga.getNameCache(),\n ['savedPlayerNames', foundBan.bannerId],\n '',\n ),\n };\n }\n }\n return {\n ...player,\n seenAgo: now - player.lastSeen,\n createdAgo: now - player.created,\n ban,\n };\n });\n return { ...resp, players };\n }),\n\n get: protectedProcedure('player.get')\n .input(z.string())\n .query(async ({ input: id }) => {\n const { database, omegga } = getContextDeps();\n const entry = await database.getPlayer(id);\n if (!entry) return null;\n const now = Date.now();\n const nameHistory = entry.nameHistory.map(n => ({\n ...n,\n ago: now - n.date,\n }));\n const banHistory = entry.banHistory.map(b => ({\n ...b,\n duration: (b.expires as number) - (b.created as number),\n bannerName: _.get(\n omegga.getNameCache(),\n ['savedPlayerNames', b.bannerId],\n '',\n ) as string,\n }));\n const kickHistory = entry.kickHistory.map(b => ({\n ...b,\n kickerName: _.get(\n omegga.getNameCache(),\n ['savedPlayerNames', b.kickerId],\n '',\n ) as string,\n }));\n const playerRoles = Player.getRoles(omegga, id) || [];\n const { roles: serverRoles = [] } = omegga.getRoleSetup() ?? {};\n const foundBan = (omegga.getBanList() || { banList: {} }).banList[id];\n let currentBan: {\n bannerId: string;\n reason: string;\n created: number;\n expires: number;\n duration: number;\n remainingTime: number;\n bannerName: string;\n } | null = null;\n if (foundBan) {\n const created = parseBrickadiaTime(foundBan.created);\n const expires = parseBrickadiaTime(foundBan.expires);\n const duration = expires - created;\n if (!(expires < now && duration > 0)) {\n currentBan = {\n bannerId: foundBan.bannerId,\n reason: foundBan.reason,\n created,\n expires,\n duration,\n remainingTime: expires - now,\n bannerName: _.get(\n omegga.getNameCache(),\n ['savedPlayerNames', foundBan.bannerId],\n '',\n ),\n };\n }\n }\n return {\n ...entry,\n nameHistory,\n banHistory,\n kickHistory,\n seenAgo: now - entry.lastSeen,\n createdAgo: now - entry.created,\n isHost: omegga.getHostId() === id,\n isOnline: omegga.players.some(p => p.id === id),\n currentBan,\n roles: playerRoles.map(r => {\n let color = 'ffffff';\n const role = serverRoles.find(\n sr => sr.name.toLowerCase() === r.toLowerCase(),\n );\n if (role && role.bHasColor) color = rgbToHex(role.color);\n return { name: r, color };\n }),\n };\n }),\n\n ban: protectedProcedure('player.ban')\n .input(\n z.object({\n id: z.string(),\n duration: z.number().optional().default(-1),\n reason: z.string().max(128).optional().default('No Reason'),\n }),\n )\n .mutation(async ({ input, ctx }) => {\n const { database, omegga } = getContextDeps();\n const { id, duration } = input;\n let { reason } = input;\n if (typeof duration !== 'number') return false;\n if (!uuid.match(id)) return false;\n reason = reason.replace(/\\n/g, ' ').replace(/\"/g, \"'\");\n ctx.log(\n 'Banning player',\n omegga.getNameCache()?.savedPlayerNames?.[id].yellow ??\n 'with id ' + id.yellow,\n );\n omegga.writeln(`Chat.Command /Ban \"${id}\" ${duration} \"${reason}\"`);\n const ban = await waitForEvent(database, 'update.bans', () => {\n const banList = (omegga.getBanList() || { banList: {} }).banList;\n if (!banList[id]) return false;\n return banList[id];\n });\n if (ban) {\n const entry: IStoreBanHistory = {\n type: 'banHistory',\n banned: id,\n bannerId: null,\n created: parseBrickadiaTime(ban.created),\n expires: parseBrickadiaTime(ban.expires),\n reason: ban.reason,\n };\n await database.stores.players.update(\n entry,\n { $set: entry },\n { upsert: true },\n );\n }\n return !!ban;\n }),\n\n kick: protectedProcedure('player.kick')\n .input(\n z.object({\n id: z.string(),\n reason: z.string().max(128).optional().default('No Reason'),\n }),\n )\n .mutation(async ({ input, ctx }) => {\n const { database, omegga } = getContextDeps();\n const { id } = input;\n let { reason } = input;\n if (!uuid.match(id)) return false;\n reason = reason.replace(/\\n/g, ' ').replace(/\"/g, \"'\");\n const player = omegga.players.find(p => p.id === id);\n if (!player) return false;\n ctx.log('Kicking player', player.name.yellow);\n omegga.writeln(`Chat.Command /Kick \"${id}\" \"${reason}\"`);\n const ok = await waitForEvent(\n omegga,\n 'leave',\n (leavingPlayer: { id: string }) => leavingPlayer.id === id,\n );\n if (ok) {\n const entry: IStoreKickHistory = {\n type: 'kickHistory',\n kicked: id,\n kickerId: null,\n created: Date.now(),\n reason,\n };\n await database.stores.players.update(\n entry,\n { $set: entry },\n { upsert: true },\n );\n }\n return ok;\n }),\n\n unban: protectedProcedure('player.unban')\n .input(z.object({ id: z.string() }))\n .mutation(async ({ input, ctx }) => {\n const { database, omegga } = getContextDeps();\n const { id } = input;\n if (!uuid.match(id)) return false;\n const banList = (omegga.getBanList() || { banList: {} }).banList;\n if (!banList[id]) return false;\n ctx.log(\n 'Unbanning player',\n omegga.getNameCache()?.savedPlayerNames?.[id].yellow ??\n 'with id ' + id.yellow,\n );\n omegga.writeln(`Chat.Command /Unban \"${id}\"`);\n const ok = await waitForEvent(database, 'update.bans', () => {\n const banList = (omegga.getBanList() || { banList: {} }).banList;\n return (\n !banList[id] || parseBrickadiaTime(banList[id].expires) < Date.now()\n );\n });\n return ok;\n }),\n\n clearBricks: protectedProcedure('player.clearBricks')\n .input(z.object({ id: z.string() }))\n .mutation(async ({ input, ctx }) => {\n const { omegga } = getContextDeps();\n const { id } = input;\n if (!uuid.match(id)) return false;\n ctx.log(\n 'Clearing bricks for player',\n omegga.getNameCache()?.savedPlayerNames?.[id]?.yellow ??\n 'with id ' + id.yellow,\n );\n omegga.writeln(`Bricks.Clear \"${id}\"`);\n return true;\n }),\n }),\n});\n"],"names":["router","protectedProcedure","z","getContextDeps","parseBrickadiaTime","player","Player","color","rgbToHex","uuid.match","waitForEvent","banList"],"mappings":"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"}
1
+ {"version":3,"file":"player.js","sources":["../../../../src/webserver/backend/router/player.ts"],"sourcesContent":["import Player from '@omegga/player';\nimport { rgbToHex } from '@util/color';\nimport { parseBrickadiaTime } from '@util/time';\nimport * as uuid from '@util/uuid';\nimport _ from 'lodash';\nimport { z } from 'zod/v4';\nimport { ScopeName } from '../scopes';\nimport { getContextDeps, protectedProcedure, router } from '../trpc';\nimport type { IStoreBanHistory, IStoreKickHistory } from '../types';\nimport { waitForEvent } from '../util';\n\nexport const playerRouter = router({\n player: router({\n list: protectedProcedure(ScopeName.PlayerList)\n .input(\n z.object({\n page: z.number().optional().default(0),\n search: z.string().optional().default(''),\n sort: z.string().optional().default('name'),\n direction: z.number().optional().default(1),\n filter: z.string().optional().default(''),\n }),\n )\n .query(async ({ input }) => {\n const { database, omegga } = getContextDeps();\n const { page, search, sort, direction, filter } = input;\n const banList = (omegga.getBanList() || { banList: {} }).banList;\n const now = Date.now();\n let limitId: string[] | undefined;\n if (filter === 'banned') {\n limitId = Object.keys(banList).filter(\n b =>\n banList[b].expires <= banList[b].created ||\n parseBrickadiaTime(banList[b].expires) > Date.now(),\n );\n }\n const resp = await database.getPlayers({\n page,\n search,\n sort,\n direction,\n limitId,\n });\n const players = resp.players.map(player => {\n const foundBan = banList[player.id];\n let ban: {\n bannerId: string;\n reason: string;\n created: number;\n expires: number;\n duration: number;\n remainingTime: number;\n bannerName: string;\n } | null = null;\n if (foundBan) {\n const created = parseBrickadiaTime(foundBan.created);\n const expires = parseBrickadiaTime(foundBan.expires);\n const duration = expires - created;\n if (!(expires < now && duration > 0)) {\n ban = {\n bannerId: foundBan.bannerId,\n reason: foundBan.reason,\n created,\n expires,\n duration,\n remainingTime: expires - now,\n bannerName: _.get(\n omegga.getNameCache(),\n ['savedPlayerNames', foundBan.bannerId],\n '',\n ),\n };\n }\n }\n return {\n ...player,\n seenAgo: now - player.lastSeen,\n createdAgo: now - player.created,\n ban,\n };\n });\n return { ...resp, players };\n }),\n\n get: protectedProcedure(ScopeName.PlayerGet)\n .input(z.string())\n .query(async ({ input: id }) => {\n const { database, omegga } = getContextDeps();\n const entry = await database.getPlayer(id);\n if (!entry) return null;\n const now = Date.now();\n const nameHistory = entry.nameHistory.map(n => ({\n ...n,\n ago: now - n.date,\n }));\n const banHistory = entry.banHistory.map(b => ({\n ...b,\n duration: (b.expires as number) - (b.created as number),\n bannerName: _.get(\n omegga.getNameCache(),\n ['savedPlayerNames', b.bannerId],\n '',\n ) as string,\n }));\n const kickHistory = entry.kickHistory.map(b => ({\n ...b,\n kickerName: _.get(\n omegga.getNameCache(),\n ['savedPlayerNames', b.kickerId],\n '',\n ) as string,\n }));\n const playerRoles = Player.getRoles(omegga, id) || [];\n const { roles: serverRoles = [] } = omegga.getRoleSetup() ?? {};\n const foundBan = (omegga.getBanList() || { banList: {} }).banList[id];\n let currentBan: {\n bannerId: string;\n reason: string;\n created: number;\n expires: number;\n duration: number;\n remainingTime: number;\n bannerName: string;\n } | null = null;\n if (foundBan) {\n const created = parseBrickadiaTime(foundBan.created);\n const expires = parseBrickadiaTime(foundBan.expires);\n const duration = expires - created;\n if (!(expires < now && duration > 0)) {\n currentBan = {\n bannerId: foundBan.bannerId,\n reason: foundBan.reason,\n created,\n expires,\n duration,\n remainingTime: expires - now,\n bannerName: _.get(\n omegga.getNameCache(),\n ['savedPlayerNames', foundBan.bannerId],\n '',\n ),\n };\n }\n }\n return {\n ...entry,\n nameHistory,\n banHistory,\n kickHistory,\n seenAgo: now - entry.lastSeen,\n createdAgo: now - entry.created,\n isHost: omegga.getHostId() === id,\n isOnline: omegga.players.some(p => p.id === id),\n currentBan,\n roles: playerRoles.map(r => {\n let color = 'ffffff';\n const role = serverRoles.find(\n sr => sr.name.toLowerCase() === r.toLowerCase(),\n );\n if (role && role.bHasColor) color = rgbToHex(role.color);\n return { name: r, color };\n }),\n };\n }),\n\n ban: protectedProcedure(ScopeName.PlayerBan)\n .input(\n z.object({\n id: z.string(),\n duration: z.number().optional().default(-1),\n reason: z.string().max(128).optional().default('No Reason'),\n }),\n )\n .mutation(async ({ input, ctx }) => {\n const { database, omegga } = getContextDeps();\n const { id, duration } = input;\n let { reason } = input;\n if (typeof duration !== 'number') return false;\n if (!uuid.match(id)) return false;\n reason = reason.replace(/\\n/g, ' ').replace(/\"/g, \"'\");\n ctx.log(\n 'Banning player',\n omegga.getNameCache()?.savedPlayerNames?.[id].yellow ??\n 'with id ' + id.yellow,\n );\n omegga.writeln(`Chat.Command /Ban \"${id}\" ${duration} \"${reason}\"`);\n const ban = await waitForEvent(database, 'update.bans', () => {\n const banList = (omegga.getBanList() || { banList: {} }).banList;\n if (!banList[id]) return false;\n return banList[id];\n });\n if (ban) {\n const entry: IStoreBanHistory = {\n type: 'banHistory',\n banned: id,\n bannerId: null,\n created: parseBrickadiaTime(ban.created),\n expires: parseBrickadiaTime(ban.expires),\n reason: ban.reason,\n };\n await database.stores.players.update(\n entry,\n { $set: entry },\n { upsert: true },\n );\n }\n return !!ban;\n }),\n\n kick: protectedProcedure(ScopeName.PlayerKick)\n .input(\n z.object({\n id: z.string(),\n reason: z.string().max(128).optional().default('No Reason'),\n }),\n )\n .mutation(async ({ input, ctx }) => {\n const { database, omegga } = getContextDeps();\n const { id } = input;\n let { reason } = input;\n if (!uuid.match(id)) return false;\n reason = reason.replace(/\\n/g, ' ').replace(/\"/g, \"'\");\n const player = omegga.players.find(p => p.id === id);\n if (!player) return false;\n ctx.log('Kicking player', player.name.yellow);\n omegga.writeln(`Chat.Command /Kick \"${id}\" \"${reason}\"`);\n const ok = await waitForEvent(\n omegga,\n 'leave',\n (leavingPlayer: { id: string }) => leavingPlayer.id === id,\n );\n if (ok) {\n const entry: IStoreKickHistory = {\n type: 'kickHistory',\n kicked: id,\n kickerId: null,\n created: Date.now(),\n reason,\n };\n await database.stores.players.update(\n entry,\n { $set: entry },\n { upsert: true },\n );\n }\n return ok;\n }),\n\n unban: protectedProcedure(ScopeName.PlayerUnban)\n .input(z.object({ id: z.string() }))\n .mutation(async ({ input, ctx }) => {\n const { database, omegga } = getContextDeps();\n const { id } = input;\n if (!uuid.match(id)) return false;\n const banList = (omegga.getBanList() || { banList: {} }).banList;\n if (!banList[id]) return false;\n ctx.log(\n 'Unbanning player',\n omegga.getNameCache()?.savedPlayerNames?.[id].yellow ??\n 'with id ' + id.yellow,\n );\n omegga.writeln(`Chat.Command /Unban \"${id}\"`);\n const ok = await waitForEvent(database, 'update.bans', () => {\n const banList = (omegga.getBanList() || { banList: {} }).banList;\n return (\n !banList[id] || parseBrickadiaTime(banList[id].expires) < Date.now()\n );\n });\n return ok;\n }),\n\n clearBricks: protectedProcedure(ScopeName.PlayerClearBricks)\n .input(z.object({ id: z.string() }))\n .mutation(async ({ input, ctx }) => {\n const { omegga } = getContextDeps();\n const { id } = input;\n if (!uuid.match(id)) return false;\n ctx.log(\n 'Clearing bricks for player',\n omegga.getNameCache()?.savedPlayerNames?.[id]?.yellow ??\n 'with id ' + id.yellow,\n );\n omegga.writeln(`Bricks.Clear \"${id}\"`);\n return true;\n }),\n }),\n});\n"],"names":["router","protectedProcedure","ScopeName","z","getContextDeps","parseBrickadiaTime","player","Player","color","rgbToHex","uuid.match","waitForEvent","banList"],"mappings":"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"}
@@ -3,11 +3,12 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const v4 = require("zod/v4");
4
4
  const _ = require("lodash");
5
5
  const trpc = require("../trpc.js");
6
+ const scopes = require("../scopes.js");
6
7
  const events = require("../events.js");
7
8
  const EventEmitter = require("events");
8
9
  const pluginRouter = trpc.router({
9
10
  plugin: trpc.router({
10
- list: trpc.protectedProcedure().query(() => {
11
+ list: trpc.protectedProcedure(scopes.ScopeName.PluginList).query(() => {
11
12
  const { omegga } = trpc.getContextDeps();
12
13
  return _.sortBy(
13
14
  omegga.pluginLoader.plugins.map((p) => ({
@@ -20,7 +21,7 @@ const pluginRouter = trpc.router({
20
21
  (p) => p.name.toLowerCase()
21
22
  );
22
23
  }),
23
- get: trpc.protectedProcedure().input(v4.z.object({ shortPath: v4.z.string() })).query(async ({ input }) => {
24
+ get: trpc.protectedProcedure(scopes.ScopeName.PluginGet).input(v4.z.object({ shortPath: v4.z.string() })).query(async ({ input }) => {
24
25
  const { omegga } = trpc.getContextDeps();
25
26
  const plugin = omegga.pluginLoader.plugins.find(
26
27
  (p) => p.shortPath === input.shortPath
@@ -44,7 +45,7 @@ const pluginRouter = trpc.router({
44
45
  isEnabled: plugin.isEnabled()
45
46
  };
46
47
  }),
47
- config: trpc.protectedProcedure().input(
48
+ config: trpc.protectedProcedure(scopes.ScopeName.PluginConfig).input(
48
49
  v4.z.object({
49
50
  shortPath: v4.z.string(),
50
51
  config: v4.z.record(v4.z.string(), v4.z.unknown())
@@ -58,7 +59,7 @@ const pluginRouter = trpc.router({
58
59
  await plugin.storage.setConfig(input.config);
59
60
  return true;
60
61
  }),
61
- reloadAll: trpc.protectedProcedure().mutation(
62
+ reloadAll: trpc.protectedProcedure(scopes.ScopeName.PluginReloadAll).mutation(
62
63
  async ({ ctx }) => {
63
64
  const { omegga } = trpc.getContextDeps();
64
65
  const { log, error } = ctx;
@@ -90,7 +91,7 @@ const pluginRouter = trpc.router({
90
91
  }
91
92
  }
92
93
  ),
93
- unload: trpc.protectedProcedure().input(v4.z.object({ shortPath: v4.z.string() })).mutation(async ({ input, ctx }) => {
94
+ unload: trpc.protectedProcedure(scopes.ScopeName.PluginUnload).input(v4.z.object({ shortPath: v4.z.string() })).mutation(async ({ input, ctx }) => {
94
95
  const { omegga } = trpc.getContextDeps();
95
96
  const { log } = ctx;
96
97
  const plugin = omegga.pluginLoader.plugins.find(
@@ -101,7 +102,7 @@ const pluginRouter = trpc.router({
101
102
  log("Unloading".red, "plugin", plugin.getName().yellow);
102
103
  return await plugin.unload();
103
104
  }),
104
- load: trpc.protectedProcedure().input(v4.z.object({ shortPath: v4.z.string() })).mutation(async ({ input, ctx }) => {
105
+ load: trpc.protectedProcedure(scopes.ScopeName.PluginLoad).input(v4.z.object({ shortPath: v4.z.string() })).mutation(async ({ input, ctx }) => {
105
106
  const { omegga } = trpc.getContextDeps();
106
107
  const { log } = ctx;
107
108
  const plugin = omegga.pluginLoader.plugins.find(
@@ -112,7 +113,7 @@ const pluginRouter = trpc.router({
112
113
  log("Loading".green, "plugin", plugin.getName().yellow);
113
114
  return await plugin.load();
114
115
  }),
115
- toggle: trpc.protectedProcedure().input(v4.z.object({ shortPath: v4.z.string(), enabled: v4.z.boolean() })).mutation(({ input, ctx }) => {
116
+ toggle: trpc.protectedProcedure(scopes.ScopeName.PluginToggle).input(v4.z.object({ shortPath: v4.z.string(), enabled: v4.z.boolean() })).mutation(({ input, ctx }) => {
116
117
  const { omegga } = trpc.getContextDeps();
117
118
  const { log, error } = ctx;
118
119
  const plugin = omegga.pluginLoader.plugins.find(
@@ -137,9 +138,12 @@ const pluginRouter = trpc.router({
137
138
  return false;
138
139
  }
139
140
  }),
140
- onStatus: trpc.protectedProcedure().subscription(
141
- async function* () {
142
- for await (const [payload] of EventEmitter.on(events.serverEvents, "plugin")) {
141
+ onStatus: trpc.protectedProcedure(scopes.ScopeName.PluginList).subscription(
142
+ async function* ({ signal, ctx }) {
143
+ const combined = AbortSignal.any([signal, ctx.userAbort.signal]);
144
+ for await (const [payload] of EventEmitter.on(events.serverEvents, "plugin", {
145
+ signal: combined
146
+ })) {
143
147
  yield payload;
144
148
  }
145
149
  }
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.js","sources":["../../../../src/webserver/backend/router/plugin.ts"],"sourcesContent":["import { z } from 'zod/v4';\nimport _ from 'lodash';\nimport { Plugin } from '@omegga/plugin/interface';\nimport { router, protectedProcedure, getContextDeps } from '../trpc';\nimport { serverEvents } from '../events';\nimport { on } from 'events';\n\nexport const pluginRouter = router({\n plugin: router({\n list: protectedProcedure('plugin.list').query(() => {\n const { omegga } = getContextDeps();\n return _.sortBy(\n omegga.pluginLoader.plugins.map(p => ({\n name: p.getName(),\n documentation: p.getDocumentation(),\n path: p.shortPath,\n isLoaded: p.isLoaded(),\n isEnabled: p.isEnabled(),\n })),\n p => p.name.toLowerCase(),\n );\n }),\n\n get: protectedProcedure('plugin.get')\n .input(z.object({ shortPath: z.string() }))\n .query(async ({ input }) => {\n const { omegga } = getContextDeps();\n const plugin = omegga.pluginLoader.plugins.find(\n p => p.shortPath === input.shortPath,\n );\n if (!plugin) return null;\n\n const [defaultConfig, config, objCount] = await Promise.all([\n plugin.storage.getDefaultConfig(),\n plugin.storage.getConfig(),\n plugin.storage.count(),\n ]);\n\n return {\n name: plugin.getName(),\n format: (plugin.constructor as typeof Plugin).getFormat(),\n info: plugin.getInfo(),\n documentation: plugin.getDocumentation(),\n config,\n defaultConfig,\n objCount,\n path: plugin.shortPath,\n isLoaded: plugin.isLoaded(),\n isEnabled: plugin.isEnabled(),\n };\n }),\n\n config: protectedProcedure('plugin.config')\n .input(\n z.object({\n shortPath: z.string(),\n config: z.record(z.string(), z.unknown()),\n }),\n )\n .mutation(async ({ input }) => {\n const { omegga } = getContextDeps();\n const plugin = omegga.pluginLoader.plugins.find(\n p => p.shortPath === input.shortPath,\n );\n if (!plugin) return null;\n\n await plugin.storage.setConfig(input.config);\n return true;\n }),\n\n reloadAll: protectedProcedure('plugin.reloadAll').mutation(\n async ({ ctx }) => {\n const { omegga } = getContextDeps();\n const { log, error } = ctx;\n\n if (!omegga.pluginLoader) {\n error('Omegga is not using plugins');\n return false;\n }\n\n log('Unloading current plugins');\n let success = await omegga.pluginLoader.unload();\n if (!success) {\n error('Could not unload all plugins');\n return false;\n }\n\n log('Scanning for new plugins');\n success = await omegga.pluginLoader.scan();\n if (!success) {\n error('Could not scan for plugins');\n return false;\n }\n\n log('Starting plugins');\n success = await omegga.pluginLoader.reload();\n if (success) {\n const plugins = omegga.pluginLoader.plugins\n .filter(p => p.isLoaded())\n .map(p => p.getName());\n log('Loaded', (plugins.length + '').yellow, 'plugins:', plugins);\n return true;\n } else {\n error('Could not load all plugins');\n return false;\n }\n },\n ),\n\n unload: protectedProcedure('plugin.unload')\n .input(z.object({ shortPath: z.string() }))\n .mutation(async ({ input, ctx }) => {\n const { omegga } = getContextDeps();\n const { log } = ctx;\n\n const plugin = omegga.pluginLoader.plugins.find(\n p => p.shortPath === input.shortPath,\n );\n if (!plugin) return false;\n if (!plugin.isLoaded()) return false;\n\n log('Unloading'.red, 'plugin', plugin.getName().yellow);\n return await plugin.unload();\n }),\n\n load: protectedProcedure('plugin.load')\n .input(z.object({ shortPath: z.string() }))\n .mutation(async ({ input, ctx }) => {\n const { omegga } = getContextDeps();\n const { log } = ctx;\n\n const plugin = omegga.pluginLoader.plugins.find(\n p => p.shortPath === input.shortPath,\n );\n if (!plugin) return false;\n if (plugin.isLoaded() || !plugin.isEnabled()) return false;\n\n log('Loading'.green, 'plugin', plugin.getName().yellow);\n return await plugin.load();\n }),\n\n toggle: protectedProcedure('plugin.toggle')\n .input(z.object({ shortPath: z.string(), enabled: z.boolean() }))\n .mutation(({ input, ctx }) => {\n const { omegga } = getContextDeps();\n const { log, error } = ctx;\n\n const plugin = omegga.pluginLoader.plugins.find(\n p => p.shortPath === input.shortPath,\n );\n if (!plugin) return false;\n\n try {\n plugin.setEnabled(input.enabled);\n log(\n input.enabled ? 'Enabled'.green : 'Disabled'.red,\n 'plugin',\n plugin.getName().yellow,\n );\n return true;\n } catch (e) {\n error(\n 'Error',\n input.enabled ? 'enabling'.green : 'disabling'.red,\n 'plugin',\n plugin.getName().yellow,\n );\n return false;\n }\n }),\n\n onStatus: protectedProcedure('plugin.onStatus').subscription(\n async function* () {\n for await (const [payload] of on(serverEvents, 'plugin')) {\n yield payload as {\n shortPath: string;\n name: string;\n isLoaded: boolean;\n isEnabled: boolean;\n };\n }\n },\n ),\n }),\n});\n"],"names":["router","protectedProcedure","getContextDeps","z","on","serverEvents"],"mappings":"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"}
1
+ {"version":3,"file":"plugin.js","sources":["../../../../src/webserver/backend/router/plugin.ts"],"sourcesContent":["import { z } from 'zod/v4';\nimport _ from 'lodash';\nimport { Plugin } from '@omegga/plugin/interface';\nimport { router, protectedProcedure, getContextDeps } from '../trpc';\nimport { ScopeName } from '../scopes';\nimport { serverEvents } from '../events';\nimport { on } from 'events';\n\nexport const pluginRouter = router({\n plugin: router({\n list: protectedProcedure(ScopeName.PluginList).query(() => {\n const { omegga } = getContextDeps();\n return _.sortBy(\n omegga.pluginLoader.plugins.map(p => ({\n name: p.getName(),\n documentation: p.getDocumentation(),\n path: p.shortPath,\n isLoaded: p.isLoaded(),\n isEnabled: p.isEnabled(),\n })),\n p => p.name.toLowerCase(),\n );\n }),\n\n get: protectedProcedure(ScopeName.PluginGet)\n .input(z.object({ shortPath: z.string() }))\n .query(async ({ input }) => {\n const { omegga } = getContextDeps();\n const plugin = omegga.pluginLoader.plugins.find(\n p => p.shortPath === input.shortPath,\n );\n if (!plugin) return null;\n\n const [defaultConfig, config, objCount] = await Promise.all([\n plugin.storage.getDefaultConfig(),\n plugin.storage.getConfig(),\n plugin.storage.count(),\n ]);\n\n return {\n name: plugin.getName(),\n format: (plugin.constructor as typeof Plugin).getFormat(),\n info: plugin.getInfo(),\n documentation: plugin.getDocumentation(),\n config,\n defaultConfig,\n objCount,\n path: plugin.shortPath,\n isLoaded: plugin.isLoaded(),\n isEnabled: plugin.isEnabled(),\n };\n }),\n\n config: protectedProcedure(ScopeName.PluginConfig)\n .input(\n z.object({\n shortPath: z.string(),\n config: z.record(z.string(), z.unknown()),\n }),\n )\n .mutation(async ({ input }) => {\n const { omegga } = getContextDeps();\n const plugin = omegga.pluginLoader.plugins.find(\n p => p.shortPath === input.shortPath,\n );\n if (!plugin) return null;\n\n await plugin.storage.setConfig(input.config);\n return true;\n }),\n\n reloadAll: protectedProcedure(ScopeName.PluginReloadAll).mutation(\n async ({ ctx }) => {\n const { omegga } = getContextDeps();\n const { log, error } = ctx;\n\n if (!omegga.pluginLoader) {\n error('Omegga is not using plugins');\n return false;\n }\n\n log('Unloading current plugins');\n let success = await omegga.pluginLoader.unload();\n if (!success) {\n error('Could not unload all plugins');\n return false;\n }\n\n log('Scanning for new plugins');\n success = await omegga.pluginLoader.scan();\n if (!success) {\n error('Could not scan for plugins');\n return false;\n }\n\n log('Starting plugins');\n success = await omegga.pluginLoader.reload();\n if (success) {\n const plugins = omegga.pluginLoader.plugins\n .filter(p => p.isLoaded())\n .map(p => p.getName());\n log('Loaded', (plugins.length + '').yellow, 'plugins:', plugins);\n return true;\n } else {\n error('Could not load all plugins');\n return false;\n }\n },\n ),\n\n unload: protectedProcedure(ScopeName.PluginUnload)\n .input(z.object({ shortPath: z.string() }))\n .mutation(async ({ input, ctx }) => {\n const { omegga } = getContextDeps();\n const { log } = ctx;\n\n const plugin = omegga.pluginLoader.plugins.find(\n p => p.shortPath === input.shortPath,\n );\n if (!plugin) return false;\n if (!plugin.isLoaded()) return false;\n\n log('Unloading'.red, 'plugin', plugin.getName().yellow);\n return await plugin.unload();\n }),\n\n load: protectedProcedure(ScopeName.PluginLoad)\n .input(z.object({ shortPath: z.string() }))\n .mutation(async ({ input, ctx }) => {\n const { omegga } = getContextDeps();\n const { log } = ctx;\n\n const plugin = omegga.pluginLoader.plugins.find(\n p => p.shortPath === input.shortPath,\n );\n if (!plugin) return false;\n if (plugin.isLoaded() || !plugin.isEnabled()) return false;\n\n log('Loading'.green, 'plugin', plugin.getName().yellow);\n return await plugin.load();\n }),\n\n toggle: protectedProcedure(ScopeName.PluginToggle)\n .input(z.object({ shortPath: z.string(), enabled: z.boolean() }))\n .mutation(({ input, ctx }) => {\n const { omegga } = getContextDeps();\n const { log, error } = ctx;\n\n const plugin = omegga.pluginLoader.plugins.find(\n p => p.shortPath === input.shortPath,\n );\n if (!plugin) return false;\n\n try {\n plugin.setEnabled(input.enabled);\n log(\n input.enabled ? 'Enabled'.green : 'Disabled'.red,\n 'plugin',\n plugin.getName().yellow,\n );\n return true;\n } catch (e) {\n error(\n 'Error',\n input.enabled ? 'enabling'.green : 'disabling'.red,\n 'plugin',\n plugin.getName().yellow,\n );\n return false;\n }\n }),\n\n onStatus: protectedProcedure(ScopeName.PluginList).subscription(\n async function* ({ signal, ctx }) {\n const combined = AbortSignal.any([signal!, ctx.userAbort.signal]);\n for await (const [payload] of on(serverEvents, 'plugin', {\n signal: combined,\n })) {\n yield payload as {\n shortPath: string;\n name: string;\n isLoaded: boolean;\n isEnabled: boolean;\n };\n }\n },\n ),\n }),\n});\n"],"names":["router","protectedProcedure","ScopeName","getContextDeps","z","on","serverEvents"],"mappings":"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"}
@@ -2,9 +2,10 @@
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const _ = require("lodash");
4
4
  const trpc = require("../trpc.js");
5
+ const scopes = require("../scopes.js");
5
6
  const roleRouter = trpc.router({
6
7
  role: trpc.router({
7
- list: trpc.protectedProcedure().query(() => {
8
+ list: trpc.protectedProcedure(scopes.ScopeName.RoleList).query(() => {
8
9
  const { omegga } = trpc.getContextDeps();
9
10
  return _.sortBy(
10
11
  omegga.getRoleSetup()?.roles ?? [],
@@ -1 +1 @@
1
- {"version":3,"file":"role.js","sources":["../../../../src/webserver/backend/router/role.ts"],"sourcesContent":["import _ from 'lodash';\nimport { router, protectedProcedure, getContextDeps } from '../trpc';\n\nexport const roleRouter = router({\n role: router({\n list: protectedProcedure('role.list').query(() => {\n const { omegga } = getContextDeps();\n return _.sortBy(omegga.getRoleSetup()?.roles ?? [], p =>\n p.name.toLowerCase(),\n );\n }),\n }),\n});\n"],"names":["router","protectedProcedure","getContextDeps"],"mappings":";;;;AAGO,MAAM,aAAaA,KAAAA,OAAO;AAAA,EAC/B,MAAMA,KAAAA,OAAO;AAAA,IACX,MAAMC,KAAAA,mBAA8B,EAAE,MAAM,MAAM;AAChD,YAAM,EAAE,OAAA,IAAWC,oBAAA;AACnB,aAAO,EAAE;AAAA,QAAO,OAAO,gBAAgB,SAAS,CAAA;AAAA,QAAI,CAAA,MAClD,EAAE,KAAK,YAAA;AAAA,MAAY;AAAA,IAEvB,CAAC;AAAA,EAAA,CACF;AACH,CAAC;;"}
1
+ {"version":3,"file":"role.js","sources":["../../../../src/webserver/backend/router/role.ts"],"sourcesContent":["import _ from 'lodash';\nimport { router, protectedProcedure, getContextDeps } from '../trpc';\nimport { ScopeName } from '../scopes';\n\nexport const roleRouter = router({\n role: router({\n list: protectedProcedure(ScopeName.RoleList).query(() => {\n const { omegga } = getContextDeps();\n return _.sortBy(omegga.getRoleSetup()?.roles ?? [], p =>\n p.name.toLowerCase(),\n );\n }),\n }),\n});\n"],"names":["router","protectedProcedure","ScopeName","getContextDeps"],"mappings":";;;;;AAIO,MAAM,aAAaA,KAAAA,OAAO;AAAA,EAC/B,MAAMA,KAAAA,OAAO;AAAA,IACX,MAAMC,KAAAA,mBAAmBC,OAAAA,UAAU,QAAQ,EAAE,MAAM,MAAM;AACvD,YAAM,EAAE,OAAA,IAAWC,oBAAA;AACnB,aAAO,EAAE;AAAA,QAAO,OAAO,gBAAgB,SAAS,CAAA;AAAA,QAAI,CAAA,MAClD,EAAE,KAAK,YAAA;AAAA,MAAY;AAAA,IAEvB,CAAC;AAAA,EAAA,CACF;AACH,CAAC;;"}
@@ -6,6 +6,7 @@ const EventEmitter = require("events");
6
6
  const v4 = require("zod/v4");
7
7
  const events = require("../events.js");
8
8
  const metrics = require("../metrics.js");
9
+ const scopes = require("../scopes.js");
9
10
  const trpc = require("../trpc.js");
10
11
  let _server = null;
11
12
  function setWebserver(s) {
@@ -29,11 +30,13 @@ const autoRestartConfigSchema = v4.z.object({
29
30
  const serverRouter = trpc.router({
30
31
  server: trpc.router({
31
32
  autoRestart: trpc.router({
32
- get: trpc.protectedProcedure().query(async () => {
33
- const { database } = trpc.getContextDeps();
34
- return await database.getAutoRestartConfig();
35
- }),
36
- set: trpc.protectedProcedure().input(autoRestartConfigSchema).mutation(async ({ input: config }) => {
33
+ get: trpc.protectedProcedure(scopes.ScopeName.ServerAutorestartGet).query(
34
+ async () => {
35
+ const { database } = trpc.getContextDeps();
36
+ return await database.getAutoRestartConfig();
37
+ }
38
+ ),
39
+ set: trpc.protectedProcedure(scopes.ScopeName.ServerAutorestartSet).input(autoRestartConfigSchema).mutation(async ({ input: config }) => {
37
40
  const { database } = trpc.getContextDeps();
38
41
  if (typeof config !== "object" || !Object.entries({
39
42
  type: "string",
@@ -57,13 +60,13 @@ const serverRouter = trpc.router({
57
60
  return true;
58
61
  })
59
62
  }),
60
- status: trpc.protectedProcedure().query(() => {
63
+ status: trpc.protectedProcedure(scopes.ScopeName.ServerStatus).query(() => {
61
64
  return _server?.lastReportedStatus ?? null;
62
65
  }),
63
- utilization: trpc.protectedProcedure().query(() => {
66
+ utilization: trpc.protectedProcedure(scopes.ScopeName.ServerUtilization).query(() => {
64
67
  return metrics.getLastUtilization();
65
68
  }),
66
- started: trpc.protectedProcedure().query(() => {
69
+ started: trpc.protectedProcedure(scopes.ScopeName.ServerStatus).query(() => {
67
70
  const { omegga } = trpc.getContextDeps();
68
71
  return {
69
72
  started: omegga.started,
@@ -71,41 +74,45 @@ const serverRouter = trpc.router({
71
74
  stopping: omegga.stopping
72
75
  };
73
76
  }),
74
- start: trpc.protectedProcedure().mutation(async ({ ctx }) => {
75
- const { omegga } = trpc.getContextDeps();
76
- if (omegga.starting || omegga.stopping || omegga.started) return;
77
- ctx.log("Starting server...");
78
- await omegga.start();
79
- }),
80
- stop: trpc.protectedProcedure().mutation(async ({ ctx }) => {
77
+ start: trpc.protectedProcedure(scopes.ScopeName.ServerStart).mutation(
78
+ async ({ ctx }) => {
79
+ const { omegga } = trpc.getContextDeps();
80
+ if (omegga.starting || omegga.stopping || omegga.started) return;
81
+ ctx.log("Starting server...");
82
+ await omegga.start();
83
+ }
84
+ ),
85
+ stop: trpc.protectedProcedure(scopes.ScopeName.ServerStop).mutation(async ({ ctx }) => {
81
86
  const { omegga } = trpc.getContextDeps();
82
87
  if (omegga.starting || omegga.stopping || !omegga.started) return;
83
88
  ctx.log("Stopping server...");
84
89
  await omegga.stop();
85
90
  }),
86
- restart: trpc.protectedProcedure().mutation(async ({ ctx }) => {
87
- const { database, omegga } = trpc.getContextDeps();
88
- if (omegga.starting || omegga.stopping) return;
89
- try {
90
- const config = await database.getAutoRestartConfig();
91
- await omegga.saveServer({
92
- players: config.playersEnabled,
93
- saveWorld: config.saveWorld ?? true,
94
- announcement: config.announcementEnabled
95
- });
96
- } catch (err) {
97
- ctx.error("Error while saving server setup", err);
91
+ restart: trpc.protectedProcedure(scopes.ScopeName.ServerRestart).mutation(
92
+ async ({ ctx }) => {
93
+ const { database, omegga } = trpc.getContextDeps();
94
+ if (omegga.starting || omegga.stopping) return;
95
+ try {
96
+ const config = await database.getAutoRestartConfig();
97
+ await omegga.saveServer({
98
+ players: config.playersEnabled,
99
+ saveWorld: config.saveWorld ?? true,
100
+ announcement: config.announcementEnabled
101
+ });
102
+ } catch (err) {
103
+ ctx.error("Error while saving server setup", err);
104
+ }
105
+ database.addChatLog("server", {}, "Restarting in 5 seconds...");
106
+ logger.default.logp("Restarting in 5 seconds...");
107
+ omegga.broadcast(
108
+ `<size="20">Server restart in <b><color="ffffbb">${5} seconds</></></>`
109
+ );
110
+ await new Promise((resolve) => setTimeout(resolve, 5e3));
111
+ await omegga.restartServer();
98
112
  }
99
- database.addChatLog("server", {}, "Restarting in 5 seconds...");
100
- logger.default.logp("Restarting in 5 seconds...");
101
- omegga.broadcast(
102
- `<size="20">Server restart in <b><color="ffffbb">${5} seconds</></></>`
103
- );
104
- await new Promise((resolve) => setTimeout(resolve, 5e3));
105
- await omegga.restartServer();
106
- }),
113
+ ),
107
114
  update: trpc.router({
108
- check: trpc.protectedProcedure().query(async () => {
115
+ check: trpc.protectedProcedure(scopes.ScopeName.ServerUpdateCheck).query(async () => {
109
116
  const { omegga } = trpc.getContextDeps();
110
117
  if (!omegga.config.__STEAM) return null;
111
118
  const lastUpdate = steam.getLastSteamUpdateCheck();
@@ -116,37 +123,42 @@ const serverRouter = trpc.router({
116
123
  logger.default.verbose("[rpc] Checking for steam update");
117
124
  return await steam.hasSteamUpdate(omegga.config.server?.steambeta);
118
125
  }),
119
- run: trpc.protectedProcedure().mutation(async ({ ctx }) => {
120
- const { omegga } = trpc.getContextDeps();
121
- if (!omegga.config.__STEAM) return false;
122
- if (omegga.stopping || omegga.starting) return false;
123
- const wasStarted = omegga.started;
124
- if (wasStarted) {
125
- ctx.log("Stopping server to update...");
126
- await omegga.stop();
127
- }
128
- ctx.log("Updating server...");
129
- let ok = false;
130
- try {
131
- steam.steamcmdDownloadGame({
132
- steambeta: omegga.config.server?.steambeta,
133
- steambetaPassword: omegga.config.server?.steambetaPassword
134
- });
135
- ok = true;
136
- ctx.log("Server updated successfully");
137
- } catch (err) {
138
- ctx.error("Error updating server", err);
139
- }
140
- if (wasStarted) {
141
- ctx.log("Starting server...");
142
- await omegga.start();
126
+ run: trpc.protectedProcedure(scopes.ScopeName.ServerUpdateRun).mutation(
127
+ async ({ ctx }) => {
128
+ const { omegga } = trpc.getContextDeps();
129
+ if (!omegga.config.__STEAM) return false;
130
+ if (omegga.stopping || omegga.starting) return false;
131
+ const wasStarted = omegga.started;
132
+ if (wasStarted) {
133
+ ctx.log("Stopping server to update...");
134
+ await omegga.stop();
135
+ }
136
+ ctx.log("Updating server...");
137
+ let ok = false;
138
+ try {
139
+ steam.steamcmdDownloadGame({
140
+ steambeta: omegga.config.server?.steambeta,
141
+ steambetaPassword: omegga.config.server?.steambetaPassword
142
+ });
143
+ ok = true;
144
+ ctx.log("Server updated successfully");
145
+ } catch (err) {
146
+ ctx.error("Error updating server", err);
147
+ }
148
+ if (wasStarted) {
149
+ ctx.log("Starting server...");
150
+ await omegga.start();
151
+ }
152
+ return ok;
143
153
  }
144
- return ok;
145
- })
154
+ )
146
155
  }),
147
- onStatus: trpc.protectedProcedure().subscription(
148
- async function* ({ signal }) {
149
- for await (const [_] of EventEmitter.on(events.serverEvents, "serverStatus", { signal })) {
156
+ onStatus: trpc.protectedProcedure(scopes.ScopeName.ServerStatus).subscription(
157
+ async function* ({ signal, ctx }) {
158
+ const combined = AbortSignal.any([signal, ctx.userAbort.signal]);
159
+ for await (const [_] of EventEmitter.on(events.serverEvents, "serverStatus", {
160
+ signal: combined
161
+ })) {
150
162
  const { omegga } = trpc.getContextDeps();
151
163
  yield {
152
164
  started: omegga.started,
@@ -156,19 +168,21 @@ const serverRouter = trpc.router({
156
168
  }
157
169
  }
158
170
  ),
159
- onHeartbeat: trpc.protectedProcedure().subscription(
160
- async function* ({ signal }) {
171
+ onHeartbeat: trpc.protectedProcedure(scopes.ScopeName.ServerStatus).subscription(
172
+ async function* ({ signal, ctx }) {
173
+ const combined = AbortSignal.any([signal, ctx.userAbort.signal]);
161
174
  for await (const [status] of EventEmitter.on(events.serverEvents, "heartbeat", {
162
- signal
175
+ signal: combined
163
176
  })) {
164
177
  yield status;
165
178
  }
166
179
  }
167
180
  ),
168
- onUtilization: trpc.protectedProcedure().subscription(
169
- async function* ({ signal }) {
181
+ onUtilization: trpc.protectedProcedure(scopes.ScopeName.ServerUtilization).subscription(
182
+ async function* ({ signal, ctx }) {
183
+ const combined = AbortSignal.any([signal, ctx.userAbort.signal]);
170
184
  for await (const [utilization] of EventEmitter.on(events.serverEvents, "utilization", {
171
- signal
185
+ signal: combined
172
186
  })) {
173
187
  yield utilization;
174
188
  }
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sources":["../../../../src/webserver/backend/router/server.ts"],"sourcesContent":["import Logger from '@/logger';\nimport { steamcmdDownloadGame } from '@/updater';\nimport { getLastSteamUpdateCheck, hasSteamUpdate } from '@/updater/steam';\nimport { on } from 'events';\nimport { z } from 'zod/v4';\nimport { serverEvents } from '../events';\nimport type Webserver from '../index';\nimport { getLastUtilization } from '../metrics';\nimport { getContextDeps, protectedProcedure, router } from '../trpc';\n\nlet _server: Webserver | null = null;\nexport function setWebserver(s: Webserver) {\n _server = s;\n}\n\nconst autoRestartConfigSchema = z.object({\n type: z.literal('autoRestartConfig'),\n maxUptime: z.number(),\n maxUptimeEnabled: z.boolean(),\n emptyUptime: z.number(),\n emptyUptimeEnabled: z.boolean(),\n dailyHour: z.number(),\n dailyHourEnabled: z.boolean(),\n announcementEnabled: z.boolean(),\n playersEnabled: z.boolean(),\n saveWorld: z.boolean(),\n autoUpdateEnabled: z.boolean(),\n autoUpdateIntervalMins: z.number(),\n crashRestartEnabled: z.boolean(),\n});\n\nexport const serverRouter = router({\n server: router({\n autoRestart: router({\n get: protectedProcedure('server.autorestart.get').query(async () => {\n const { database } = getContextDeps();\n return await database.getAutoRestartConfig();\n }),\n\n set: protectedProcedure('server.autorestart.set')\n .input(autoRestartConfigSchema)\n .mutation(async ({ input: config }) => {\n const { database } = getContextDeps();\n\n if (\n typeof config !== 'object' ||\n !Object.entries({\n type: 'string',\n maxUptime: 'number',\n maxUptimeEnabled: 'boolean',\n emptyUptime: 'number',\n emptyUptimeEnabled: 'boolean',\n dailyHour: 'number',\n dailyHourEnabled: 'boolean',\n announcementEnabled: 'boolean',\n playersEnabled: 'boolean',\n saveWorld: 'boolean',\n autoUpdateEnabled: 'boolean',\n autoUpdateIntervalMins: 'number',\n crashRestartEnabled: 'boolean',\n }).every(\n ([k, v]) =>\n k in config &&\n typeof config[k as keyof typeof config] === v &&\n !Number.isNaN(config[k as keyof typeof config]),\n ) ||\n config.type !== 'autoRestartConfig'\n )\n return false;\n\n await database.setAutoRestartConfig(config);\n return true;\n }),\n }),\n\n status: protectedProcedure('server.status').query(() => {\n return _server?.lastReportedStatus ?? null;\n }),\n\n utilization: protectedProcedure('server.utilization').query(() => {\n return getLastUtilization();\n }),\n\n started: protectedProcedure('server.started').query(() => {\n const { omegga } = getContextDeps();\n return {\n started: omegga.started,\n starting: omegga.starting,\n stopping: omegga.stopping,\n };\n }),\n\n start: protectedProcedure('server.start').mutation(async ({ ctx }) => {\n const { omegga } = getContextDeps();\n if (omegga.starting || omegga.stopping || omegga.started) return;\n ctx.log('Starting server...');\n await omegga.start();\n }),\n\n stop: protectedProcedure('server.stop').mutation(async ({ ctx }) => {\n const { omegga } = getContextDeps();\n if (omegga.starting || omegga.stopping || !omegga.started) return;\n ctx.log('Stopping server...');\n await omegga.stop();\n }),\n\n restart: protectedProcedure('server.restart').mutation(async ({ ctx }) => {\n const { database, omegga } = getContextDeps();\n if (omegga.starting || omegga.stopping) return;\n\n try {\n const config = await database.getAutoRestartConfig();\n await omegga.saveServer({\n players: config.playersEnabled,\n saveWorld: config.saveWorld ?? true,\n announcement: config.announcementEnabled,\n });\n } catch (err) {\n ctx.error('Error while saving server setup', err);\n }\n\n database.addChatLog('server', {}, 'Restarting in 5 seconds...');\n Logger.logp('Restarting in 5 seconds...');\n omegga.broadcast(\n `<size=\"20\">Server restart in <b><color=\"ffffbb\">${5} seconds</></></>`,\n );\n\n await new Promise(resolve => setTimeout(resolve, 5000));\n await omegga.restartServer();\n }),\n\n update: router({\n check: protectedProcedure('server.update.check').query(async () => {\n const { omegga } = getContextDeps();\n if (!omegga.config.__STEAM) return null;\n\n const lastUpdate = getLastSteamUpdateCheck();\n if (Date.now() - lastUpdate.attempt < 1000 * 5) {\n Logger.verbose('[rpc] Using cached steam update check');\n return lastUpdate.result;\n }\n\n Logger.verbose('[rpc] Checking for steam update');\n return await hasSteamUpdate(omegga.config.server?.steambeta);\n }),\n\n run: protectedProcedure('server.update.run').mutation(async ({ ctx }) => {\n const { omegga } = getContextDeps();\n if (!omegga.config.__STEAM) return false;\n if (omegga.stopping || omegga.starting) return false;\n\n const wasStarted = omegga.started;\n if (wasStarted) {\n ctx.log('Stopping server to update...');\n await omegga.stop();\n }\n\n ctx.log('Updating server...');\n let ok = false;\n try {\n steamcmdDownloadGame({\n steambeta: omegga.config.server?.steambeta,\n steambetaPassword: omegga.config.server?.steambetaPassword,\n });\n ok = true;\n ctx.log('Server updated successfully');\n } catch (err) {\n ctx.error('Error updating server', err);\n }\n\n if (wasStarted) {\n ctx.log('Starting server...');\n await omegga.start();\n }\n\n return ok;\n }),\n }),\n\n onStatus: protectedProcedure('server.onStatus').subscription(\n async function* ({ signal }) {\n for await (const [_] of on(serverEvents, 'serverStatus', { signal })) {\n const { omegga } = getContextDeps();\n yield {\n started: omegga.started,\n starting: omegga.starting,\n stopping: omegga.stopping,\n };\n }\n },\n ),\n\n onHeartbeat: protectedProcedure('server.onHeartbeat').subscription(\n async function* ({ signal }) {\n for await (const [status] of on(serverEvents, 'heartbeat', {\n signal,\n })) {\n yield status;\n }\n },\n ),\n\n onUtilization: protectedProcedure('server.onUtilization').subscription(\n async function* ({ signal }) {\n for await (const [utilization] of on(serverEvents, 'utilization', {\n signal,\n })) {\n yield utilization as import('../types').SystemUtilization;\n }\n },\n ),\n }),\n});\n"],"names":["z","router","protectedProcedure","getContextDeps","getLastUtilization","Logger","getLastSteamUpdateCheck","hasSteamUpdate","steamcmdDownloadGame","on","serverEvents"],"mappings":";;;;;;;;;AAUA,IAAI,UAA4B;AACzB,SAAS,aAAa,GAAc;AACzC,YAAU;AACZ;AAEA,MAAM,0BAA0BA,GAAAA,EAAE,OAAO;AAAA,EACvC,MAAMA,GAAAA,EAAE,QAAQ,mBAAmB;AAAA,EACnC,WAAWA,GAAAA,EAAE,OAAA;AAAA,EACb,kBAAkBA,GAAAA,EAAE,QAAA;AAAA,EACpB,aAAaA,GAAAA,EAAE,OAAA;AAAA,EACf,oBAAoBA,GAAAA,EAAE,QAAA;AAAA,EACtB,WAAWA,GAAAA,EAAE,OAAA;AAAA,EACb,kBAAkBA,GAAAA,EAAE,QAAA;AAAA,EACpB,qBAAqBA,GAAAA,EAAE,QAAA;AAAA,EACvB,gBAAgBA,GAAAA,EAAE,QAAA;AAAA,EAClB,WAAWA,GAAAA,EAAE,QAAA;AAAA,EACb,mBAAmBA,GAAAA,EAAE,QAAA;AAAA,EACrB,wBAAwBA,GAAAA,EAAE,OAAA;AAAA,EAC1B,qBAAqBA,GAAAA,EAAE,QAAA;AACzB,CAAC;AAEM,MAAM,eAAeC,KAAAA,OAAO;AAAA,EACjC,QAAQA,KAAAA,OAAO;AAAA,IACb,aAAaA,KAAAA,OAAO;AAAA,MAClB,KAAKC,KAAAA,mBAA2C,EAAE,MAAM,YAAY;AAClE,cAAM,EAAE,SAAA,IAAaC,oBAAA;AACrB,eAAO,MAAM,SAAS,qBAAA;AAAA,MACxB,CAAC;AAAA,MAED,KAAKD,KAAAA,mBAA2C,EAC7C,MAAM,uBAAuB,EAC7B,SAAS,OAAO,EAAE,OAAO,aAAa;AACrC,cAAM,EAAE,SAAA,IAAaC,oBAAA;AAErB,YACE,OAAO,WAAW,YAClB,CAAC,OAAO,QAAQ;AAAA,UACd,MAAM;AAAA,UACN,WAAW;AAAA,UACX,kBAAkB;AAAA,UAClB,aAAa;AAAA,UACb,oBAAoB;AAAA,UACpB,WAAW;AAAA,UACX,kBAAkB;AAAA,UAClB,qBAAqB;AAAA,UACrB,gBAAgB;AAAA,UAChB,WAAW;AAAA,UACX,mBAAmB;AAAA,UACnB,wBAAwB;AAAA,UACxB,qBAAqB;AAAA,QAAA,CACtB,EAAE;AAAA,UACD,CAAC,CAAC,GAAG,CAAC,MACJ,KAAK,UACL,OAAO,OAAO,CAAwB,MAAM,KAC5C,CAAC,OAAO,MAAM,OAAO,CAAwB,CAAC;AAAA,QAAA,KAElD,OAAO,SAAS;AAEhB,iBAAO;AAET,cAAM,SAAS,qBAAqB,MAAM;AAC1C,eAAO;AAAA,MACT,CAAC;AAAA,IAAA,CACJ;AAAA,IAED,QAAQD,KAAAA,mBAAkC,EAAE,MAAM,MAAM;AACtD,aAAO,SAAS,sBAAsB;AAAA,IACxC,CAAC;AAAA,IAED,aAAaA,KAAAA,mBAAuC,EAAE,MAAM,MAAM;AAChE,aAAOE,2BAAA;AAAA,IACT,CAAC;AAAA,IAED,SAASF,KAAAA,mBAAmC,EAAE,MAAM,MAAM;AACxD,YAAM,EAAE,OAAA,IAAWC,oBAAA;AACnB,aAAO;AAAA,QACL,SAAS,OAAO;AAAA,QAChB,UAAU,OAAO;AAAA,QACjB,UAAU,OAAO;AAAA,MAAA;AAAA,IAErB,CAAC;AAAA,IAED,OAAOD,KAAAA,mBAAiC,EAAE,SAAS,OAAO,EAAE,UAAU;AACpE,YAAM,EAAE,OAAA,IAAWC,oBAAA;AACnB,UAAI,OAAO,YAAY,OAAO,YAAY,OAAO,QAAS;AAC1D,UAAI,IAAI,oBAAoB;AAC5B,YAAM,OAAO,MAAA;AAAA,IACf,CAAC;AAAA,IAED,MAAMD,KAAAA,mBAAgC,EAAE,SAAS,OAAO,EAAE,UAAU;AAClE,YAAM,EAAE,OAAA,IAAWC,oBAAA;AACnB,UAAI,OAAO,YAAY,OAAO,YAAY,CAAC,OAAO,QAAS;AAC3D,UAAI,IAAI,oBAAoB;AAC5B,YAAM,OAAO,KAAA;AAAA,IACf,CAAC;AAAA,IAED,SAASD,KAAAA,mBAAmC,EAAE,SAAS,OAAO,EAAE,UAAU;AACxE,YAAM,EAAE,UAAU,OAAA,IAAWC,oBAAA;AAC7B,UAAI,OAAO,YAAY,OAAO,SAAU;AAExC,UAAI;AACF,cAAM,SAAS,MAAM,SAAS,qBAAA;AAC9B,cAAM,OAAO,WAAW;AAAA,UACtB,SAAS,OAAO;AAAA,UAChB,WAAW,OAAO,aAAa;AAAA,UAC/B,cAAc,OAAO;AAAA,QAAA,CACtB;AAAA,MACH,SAAS,KAAK;AACZ,YAAI,MAAM,mCAAmC,GAAG;AAAA,MAClD;AAEA,eAAS,WAAW,UAAU,CAAA,GAAI,4BAA4B;AAC9DE,aAAAA,QAAO,KAAK,4BAA4B;AACxC,aAAO;AAAA,QACL,mDAAmD,CAAC;AAAA,MAAA;AAGtD,YAAM,IAAI,QAAQ,CAAA,YAAW,WAAW,SAAS,GAAI,CAAC;AACtD,YAAM,OAAO,cAAA;AAAA,IACf,CAAC;AAAA,IAED,QAAQJ,KAAAA,OAAO;AAAA,MACb,OAAOC,KAAAA,mBAAwC,EAAE,MAAM,YAAY;AACjE,cAAM,EAAE,OAAA,IAAWC,oBAAA;AACnB,YAAI,CAAC,OAAO,OAAO,QAAS,QAAO;AAEnC,cAAM,aAAaG,MAAAA,wBAAA;AACnB,YAAI,KAAK,IAAA,IAAQ,WAAW,UAAU,MAAO,GAAG;AAC9CD,iBAAAA,QAAO,QAAQ,uCAAuC;AACtD,iBAAO,WAAW;AAAA,QACpB;AAEAA,eAAAA,QAAO,QAAQ,iCAAiC;AAChD,eAAO,MAAME,MAAAA,eAAe,OAAO,OAAO,QAAQ,SAAS;AAAA,MAC7D,CAAC;AAAA,MAED,KAAKL,KAAAA,mBAAsC,EAAE,SAAS,OAAO,EAAE,UAAU;AACvE,cAAM,EAAE,OAAA,IAAWC,oBAAA;AACnB,YAAI,CAAC,OAAO,OAAO,QAAS,QAAO;AACnC,YAAI,OAAO,YAAY,OAAO,SAAU,QAAO;AAE/C,cAAM,aAAa,OAAO;AAC1B,YAAI,YAAY;AACd,cAAI,IAAI,8BAA8B;AACtC,gBAAM,OAAO,KAAA;AAAA,QACf;AAEA,YAAI,IAAI,oBAAoB;AAC5B,YAAI,KAAK;AACT,YAAI;AACFK,qCAAqB;AAAA,YACnB,WAAW,OAAO,OAAO,QAAQ;AAAA,YACjC,mBAAmB,OAAO,OAAO,QAAQ;AAAA,UAAA,CAC1C;AACD,eAAK;AACL,cAAI,IAAI,6BAA6B;AAAA,QACvC,SAAS,KAAK;AACZ,cAAI,MAAM,yBAAyB,GAAG;AAAA,QACxC;AAEA,YAAI,YAAY;AACd,cAAI,IAAI,oBAAoB;AAC5B,gBAAM,OAAO,MAAA;AAAA,QACf;AAEA,eAAO;AAAA,MACT,CAAC;AAAA,IAAA,CACF;AAAA,IAED,UAAUN,KAAAA,mBAAoC,EAAE;AAAA,MAC9C,iBAAiB,EAAE,OAAA,GAAU;AAC3B,yBAAiB,CAAC,CAAC,KAAKO,aAAAA,GAAGC,OAAAA,cAAc,gBAAgB,EAAE,OAAA,CAAQ,GAAG;AACpE,gBAAM,EAAE,OAAA,IAAWP,oBAAA;AACnB,gBAAM;AAAA,YACJ,SAAS,OAAO;AAAA,YAChB,UAAU,OAAO;AAAA,YACjB,UAAU,OAAO;AAAA,UAAA;AAAA,QAErB;AAAA,MACF;AAAA,IAAA;AAAA,IAGF,aAAaD,KAAAA,mBAAuC,EAAE;AAAA,MACpD,iBAAiB,EAAE,OAAA,GAAU;AAC3B,yBAAiB,CAAC,MAAM,KAAKO,aAAAA,GAAGC,OAAAA,cAAc,aAAa;AAAA,UACzD;AAAA,QAAA,CACD,GAAG;AACF,gBAAM;AAAA,QACR;AAAA,MACF;AAAA,IAAA;AAAA,IAGF,eAAeR,KAAAA,mBAAyC,EAAE;AAAA,MACxD,iBAAiB,EAAE,OAAA,GAAU;AAC3B,yBAAiB,CAAC,WAAW,KAAKO,aAAAA,GAAGC,OAAAA,cAAc,eAAe;AAAA,UAChE;AAAA,QAAA,CACD,GAAG;AACF,gBAAM;AAAA,QACR;AAAA,MACF;AAAA,IAAA;AAAA,EACF,CACD;AACH,CAAC;;;"}
1
+ {"version":3,"file":"server.js","sources":["../../../../src/webserver/backend/router/server.ts"],"sourcesContent":["import Logger from '@/logger';\nimport { steamcmdDownloadGame } from '@/updater';\nimport { getLastSteamUpdateCheck, hasSteamUpdate } from '@/updater/steam';\nimport { on } from 'events';\nimport { z } from 'zod/v4';\nimport { serverEvents } from '../events';\nimport type Webserver from '../index';\nimport { getLastUtilization } from '../metrics';\nimport { ScopeName } from '../scopes';\nimport { getContextDeps, protectedProcedure, router } from '../trpc';\n\nlet _server: Webserver | null = null;\nexport function setWebserver(s: Webserver) {\n _server = s;\n}\n\nconst autoRestartConfigSchema = z.object({\n type: z.literal('autoRestartConfig'),\n maxUptime: z.number(),\n maxUptimeEnabled: z.boolean(),\n emptyUptime: z.number(),\n emptyUptimeEnabled: z.boolean(),\n dailyHour: z.number(),\n dailyHourEnabled: z.boolean(),\n announcementEnabled: z.boolean(),\n playersEnabled: z.boolean(),\n saveWorld: z.boolean(),\n autoUpdateEnabled: z.boolean(),\n autoUpdateIntervalMins: z.number(),\n crashRestartEnabled: z.boolean(),\n});\n\nexport const serverRouter = router({\n server: router({\n autoRestart: router({\n get: protectedProcedure(ScopeName.ServerAutorestartGet).query(\n async () => {\n const { database } = getContextDeps();\n return await database.getAutoRestartConfig();\n },\n ),\n\n set: protectedProcedure(ScopeName.ServerAutorestartSet)\n .input(autoRestartConfigSchema)\n .mutation(async ({ input: config }) => {\n const { database } = getContextDeps();\n\n if (\n typeof config !== 'object' ||\n !Object.entries({\n type: 'string',\n maxUptime: 'number',\n maxUptimeEnabled: 'boolean',\n emptyUptime: 'number',\n emptyUptimeEnabled: 'boolean',\n dailyHour: 'number',\n dailyHourEnabled: 'boolean',\n announcementEnabled: 'boolean',\n playersEnabled: 'boolean',\n saveWorld: 'boolean',\n autoUpdateEnabled: 'boolean',\n autoUpdateIntervalMins: 'number',\n crashRestartEnabled: 'boolean',\n }).every(\n ([k, v]) =>\n k in config &&\n typeof config[k as keyof typeof config] === v &&\n !Number.isNaN(config[k as keyof typeof config]),\n ) ||\n config.type !== 'autoRestartConfig'\n )\n return false;\n\n await database.setAutoRestartConfig(config);\n return true;\n }),\n }),\n\n status: protectedProcedure(ScopeName.ServerStatus).query(() => {\n return _server?.lastReportedStatus ?? null;\n }),\n\n utilization: protectedProcedure(ScopeName.ServerUtilization).query(() => {\n return getLastUtilization();\n }),\n\n started: protectedProcedure(ScopeName.ServerStatus).query(() => {\n const { omegga } = getContextDeps();\n return {\n started: omegga.started,\n starting: omegga.starting,\n stopping: omegga.stopping,\n };\n }),\n\n start: protectedProcedure(ScopeName.ServerStart).mutation(\n async ({ ctx }) => {\n const { omegga } = getContextDeps();\n if (omegga.starting || omegga.stopping || omegga.started) return;\n ctx.log('Starting server...');\n await omegga.start();\n },\n ),\n\n stop: protectedProcedure(ScopeName.ServerStop).mutation(async ({ ctx }) => {\n const { omegga } = getContextDeps();\n if (omegga.starting || omegga.stopping || !omegga.started) return;\n ctx.log('Stopping server...');\n await omegga.stop();\n }),\n\n restart: protectedProcedure(ScopeName.ServerRestart).mutation(\n async ({ ctx }) => {\n const { database, omegga } = getContextDeps();\n if (omegga.starting || omegga.stopping) return;\n\n try {\n const config = await database.getAutoRestartConfig();\n await omegga.saveServer({\n players: config.playersEnabled,\n saveWorld: config.saveWorld ?? true,\n announcement: config.announcementEnabled,\n });\n } catch (err) {\n ctx.error('Error while saving server setup', err);\n }\n\n database.addChatLog('server', {}, 'Restarting in 5 seconds...');\n Logger.logp('Restarting in 5 seconds...');\n omegga.broadcast(\n `<size=\"20\">Server restart in <b><color=\"ffffbb\">${5} seconds</></></>`,\n );\n\n await new Promise(resolve => setTimeout(resolve, 5000));\n await omegga.restartServer();\n },\n ),\n\n update: router({\n check: protectedProcedure(ScopeName.ServerUpdateCheck).query(async () => {\n const { omegga } = getContextDeps();\n if (!omegga.config.__STEAM) return null;\n\n const lastUpdate = getLastSteamUpdateCheck();\n if (Date.now() - lastUpdate.attempt < 1000 * 5) {\n Logger.verbose('[rpc] Using cached steam update check');\n return lastUpdate.result;\n }\n\n Logger.verbose('[rpc] Checking for steam update');\n return await hasSteamUpdate(omegga.config.server?.steambeta);\n }),\n\n run: protectedProcedure(ScopeName.ServerUpdateRun).mutation(\n async ({ ctx }) => {\n const { omegga } = getContextDeps();\n if (!omegga.config.__STEAM) return false;\n if (omegga.stopping || omegga.starting) return false;\n\n const wasStarted = omegga.started;\n if (wasStarted) {\n ctx.log('Stopping server to update...');\n await omegga.stop();\n }\n\n ctx.log('Updating server...');\n let ok = false;\n try {\n steamcmdDownloadGame({\n steambeta: omegga.config.server?.steambeta,\n steambetaPassword: omegga.config.server?.steambetaPassword,\n });\n ok = true;\n ctx.log('Server updated successfully');\n } catch (err) {\n ctx.error('Error updating server', err);\n }\n\n if (wasStarted) {\n ctx.log('Starting server...');\n await omegga.start();\n }\n\n return ok;\n },\n ),\n }),\n\n onStatus: protectedProcedure(ScopeName.ServerStatus).subscription(\n async function* ({ signal, ctx }) {\n const combined = AbortSignal.any([signal!, ctx.userAbort.signal]);\n for await (const [_] of on(serverEvents, 'serverStatus', {\n signal: combined,\n })) {\n const { omegga } = getContextDeps();\n yield {\n started: omegga.started,\n starting: omegga.starting,\n stopping: omegga.stopping,\n };\n }\n },\n ),\n\n onHeartbeat: protectedProcedure(ScopeName.ServerStatus).subscription(\n async function* ({ signal, ctx }) {\n const combined = AbortSignal.any([signal!, ctx.userAbort.signal]);\n for await (const [status] of on(serverEvents, 'heartbeat', {\n signal: combined,\n })) {\n yield status;\n }\n },\n ),\n\n onUtilization: protectedProcedure(ScopeName.ServerUtilization).subscription(\n async function* ({ signal, ctx }) {\n const combined = AbortSignal.any([signal!, ctx.userAbort.signal]);\n for await (const [utilization] of on(serverEvents, 'utilization', {\n signal: combined,\n })) {\n yield utilization as import('../types').SystemUtilization;\n }\n },\n ),\n }),\n});\n"],"names":["z","router","protectedProcedure","ScopeName","getContextDeps","getLastUtilization","Logger","getLastSteamUpdateCheck","hasSteamUpdate","steamcmdDownloadGame","on","serverEvents"],"mappings":"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"}
@@ -2,12 +2,16 @@
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const steam = require("../../../updater/steam.js");
4
4
  const version = require("../../../version.js");
5
+ const permissions = require("../permissions.js");
6
+ const scopes = require("../scopes.js");
5
7
  const trpc = require("../trpc.js");
6
8
  const sessionRouter = trpc.router({
7
9
  session: trpc.router({
8
- info: trpc.protectedProcedure().query(async ({ ctx }) => {
10
+ info: trpc.protectedProcedure(scopes.ScopeName.SessionInfo).query(async ({ ctx }) => {
9
11
  const { database, omegga } = trpc.getContextDeps();
10
12
  const roles = await database.getRoles();
13
+ const defaults = await database.getDefaultPermissions();
14
+ const userPerms = ctx.user.permissions ?? permissions.EMPTY_PERMISSIONS;
11
15
  return {
12
16
  roles,
13
17
  version: version.VERSION,
@@ -18,7 +22,12 @@ const sessionRouter = trpc.router({
18
22
  user: {
19
23
  username: ctx.user.username || "Admin",
20
24
  isOwner: ctx.user.isOwner,
21
- roles: ctx.user.roles
25
+ roles: ctx.user.roles,
26
+ permissions: userPerms,
27
+ resolvedScopes: ctx.user.isOwner ? permissions.resolveAllScopes(
28
+ { root: permissions.RootLevel.All, domains: {}, scopes: {} },
29
+ null
30
+ ) : permissions.resolveAllScopes(userPerms, defaults)
22
31
  },
23
32
  isSteam: Boolean(omegga.config.__STEAM),
24
33
  update: {
@@ -1 +1 @@
1
- {"version":3,"file":"session.js","sources":["../../../../src/webserver/backend/router/session.ts"],"sourcesContent":["import { getLastSteamUpdateCheck } from '@/updater/steam';\nimport { VERSION } from '@/version';\nimport { router, protectedProcedure, getContextDeps } from '../trpc';\n\nexport const sessionRouter = router({\n session: router({\n info: protectedProcedure('session.info').query(async ({ ctx }) => {\n const { database, omegga } = getContextDeps();\n const roles = await database.getRoles();\n\n return {\n roles,\n version: VERSION,\n brickadiaVersion: omegga.version ?? null,\n canLogOut: ctx.user.username !== '',\n now: Date.now(),\n userless: !ctx.user.username,\n user: {\n username: ctx.user.username || 'Admin',\n isOwner: ctx.user.isOwner,\n roles: ctx.user.roles,\n },\n isSteam: Boolean(omegga.config.__STEAM),\n update: {\n canCheck: Boolean(omegga.config.__STEAM),\n lastCheck: getLastSteamUpdateCheck()?.result ?? null,\n },\n };\n }),\n }),\n});\n"],"names":["router","protectedProcedure","getContextDeps","VERSION","getLastSteamUpdateCheck"],"mappings":";;;;;AAIO,MAAM,gBAAgBA,KAAAA,OAAO;AAAA,EAClC,SAASA,KAAAA,OAAO;AAAA,IACd,MAAMC,KAAAA,mBAAiC,EAAE,MAAM,OAAO,EAAE,UAAU;AAChE,YAAM,EAAE,UAAU,OAAA,IAAWC,oBAAA;AAC7B,YAAM,QAAQ,MAAM,SAAS,SAAA;AAE7B,aAAO;AAAA,QACL;AAAA,QACA,SAASC,QAAAA;AAAAA,QACT,kBAAkB,OAAO,WAAW;AAAA,QACpC,WAAW,IAAI,KAAK,aAAa;AAAA,QACjC,KAAK,KAAK,IAAA;AAAA,QACV,UAAU,CAAC,IAAI,KAAK;AAAA,QACpB,MAAM;AAAA,UACJ,UAAU,IAAI,KAAK,YAAY;AAAA,UAC/B,SAAS,IAAI,KAAK;AAAA,UAClB,OAAO,IAAI,KAAK;AAAA,QAAA;AAAA,QAElB,SAAS,QAAQ,OAAO,OAAO,OAAO;AAAA,QACtC,QAAQ;AAAA,UACN,UAAU,QAAQ,OAAO,OAAO,OAAO;AAAA,UACvC,WAAWC,MAAAA,wBAAA,GAA2B,UAAU;AAAA,QAAA;AAAA,MAClD;AAAA,IAEJ,CAAC;AAAA,EAAA,CACF;AACH,CAAC;;"}
1
+ {"version":3,"file":"session.js","sources":["../../../../src/webserver/backend/router/session.ts"],"sourcesContent":["import { getLastSteamUpdateCheck } from '@/updater/steam';\nimport { VERSION } from '@/version';\nimport { EMPTY_PERMISSIONS, RootLevel, resolveAllScopes } from '../permissions';\nimport { ScopeName } from '../scopes';\nimport { router, protectedProcedure, getContextDeps } from '../trpc';\n\nexport const sessionRouter = router({\n session: router({\n info: protectedProcedure(ScopeName.SessionInfo).query(async ({ ctx }) => {\n const { database, omegga } = getContextDeps();\n const roles = await database.getRoles();\n const defaults = await database.getDefaultPermissions();\n const userPerms = ctx.user.permissions ?? EMPTY_PERMISSIONS;\n\n return {\n roles,\n version: VERSION,\n brickadiaVersion: omegga.version ?? null,\n canLogOut: ctx.user.username !== '',\n now: Date.now(),\n userless: !ctx.user.username,\n user: {\n username: ctx.user.username || 'Admin',\n isOwner: ctx.user.isOwner,\n roles: ctx.user.roles,\n permissions: userPerms,\n resolvedScopes: ctx.user.isOwner\n ? resolveAllScopes(\n { root: RootLevel.All, domains: {}, scopes: {} },\n null,\n )\n : resolveAllScopes(userPerms, defaults),\n },\n isSteam: Boolean(omegga.config.__STEAM),\n update: {\n canCheck: Boolean(omegga.config.__STEAM),\n lastCheck: getLastSteamUpdateCheck()?.result ?? null,\n },\n };\n }),\n }),\n});\n"],"names":["router","protectedProcedure","ScopeName","getContextDeps","EMPTY_PERMISSIONS","VERSION","resolveAllScopes","RootLevel","getLastSteamUpdateCheck"],"mappings":";;;;;;;AAMO,MAAM,gBAAgBA,KAAAA,OAAO;AAAA,EAClC,SAASA,KAAAA,OAAO;AAAA,IACd,MAAMC,KAAAA,mBAAmBC,iBAAU,WAAW,EAAE,MAAM,OAAO,EAAE,UAAU;AACvE,YAAM,EAAE,UAAU,OAAA,IAAWC,oBAAA;AAC7B,YAAM,QAAQ,MAAM,SAAS,SAAA;AAC7B,YAAM,WAAW,MAAM,SAAS,sBAAA;AAChC,YAAM,YAAY,IAAI,KAAK,eAAeC,YAAAA;AAE1C,aAAO;AAAA,QACL;AAAA,QACA,SAASC,QAAAA;AAAAA,QACT,kBAAkB,OAAO,WAAW;AAAA,QACpC,WAAW,IAAI,KAAK,aAAa;AAAA,QACjC,KAAK,KAAK,IAAA;AAAA,QACV,UAAU,CAAC,IAAI,KAAK;AAAA,QACpB,MAAM;AAAA,UACJ,UAAU,IAAI,KAAK,YAAY;AAAA,UAC/B,SAAS,IAAI,KAAK;AAAA,UAClB,OAAO,IAAI,KAAK;AAAA,UAChB,aAAa;AAAA,UACb,gBAAgB,IAAI,KAAK,UACrBC,YAAAA;AAAAA,YACE,EAAE,MAAMC,YAAAA,UAAU,KAAK,SAAS,CAAA,GAAI,QAAQ,GAAC;AAAA,YAC7C;AAAA,UAAA,IAEFD,YAAAA,iBAAiB,WAAW,QAAQ;AAAA,QAAA;AAAA,QAE1C,SAAS,QAAQ,OAAO,OAAO,OAAO;AAAA,QACtC,QAAQ;AAAA,UACN,UAAU,QAAQ,OAAO,OAAO,OAAO;AAAA,UACvC,WAAWE,MAAAA,wBAAA,GAA2B,UAAU;AAAA,QAAA;AAAA,MAClD;AAAA,IAEJ,CAAC;AAAA,EAAA,CACF;AACH,CAAC;;"}