omegga 1.5.4 → 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 (89) hide show
  1. package/CHANGELOG.md +14 -1
  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/webserver/backend/database.js +219 -7
  6. package/dist/webserver/backend/database.js.map +1 -1
  7. package/dist/webserver/backend/events.js +1 -1
  8. package/dist/webserver/backend/events.js.map +1 -1
  9. package/dist/webserver/backend/index.js +120 -2
  10. package/dist/webserver/backend/index.js.map +1 -1
  11. package/dist/webserver/backend/permissions.js +74 -0
  12. package/dist/webserver/backend/permissions.js.map +1 -0
  13. package/dist/webserver/backend/router/chat.js +9 -7
  14. package/dist/webserver/backend/router/chat.js.map +1 -1
  15. package/dist/webserver/backend/router/index.js +3 -1
  16. package/dist/webserver/backend/router/index.js.map +1 -1
  17. package/dist/webserver/backend/router/mfa.js +162 -0
  18. package/dist/webserver/backend/router/mfa.js.map +1 -0
  19. package/dist/webserver/backend/router/player.js +7 -6
  20. package/dist/webserver/backend/router/player.js.map +1 -1
  21. package/dist/webserver/backend/router/plugin.js +14 -10
  22. package/dist/webserver/backend/router/plugin.js.map +1 -1
  23. package/dist/webserver/backend/router/role.js +2 -1
  24. package/dist/webserver/backend/router/role.js.map +1 -1
  25. package/dist/webserver/backend/router/server.js +85 -71
  26. package/dist/webserver/backend/router/server.js.map +1 -1
  27. package/dist/webserver/backend/router/session.js +11 -2
  28. package/dist/webserver/backend/router/session.js.map +1 -1
  29. package/dist/webserver/backend/router/user.js +175 -13
  30. package/dist/webserver/backend/router/user.js.map +1 -1
  31. package/dist/webserver/backend/router/world.js +10 -9
  32. package/dist/webserver/backend/router/world.js.map +1 -1
  33. package/dist/webserver/backend/scopes.js +303 -0
  34. package/dist/webserver/backend/scopes.js.map +1 -0
  35. package/dist/webserver/backend/totp.js +32 -0
  36. package/dist/webserver/backend/totp.js.map +1 -0
  37. package/dist/webserver/backend/trpc.js +47 -4
  38. package/dist/webserver/backend/trpc.js.map +1 -1
  39. package/doc/permissions.md +193 -0
  40. package/package.json +7 -2
  41. package/public/app.html +932 -526
  42. package/public/assets/IconShieldCheck-Bjlm8mX2.js +2 -0
  43. package/public/assets/IconShieldCheck-Bjlm8mX2.js.map +1 -0
  44. package/public/assets/IconWorld-XmQNg6JI.js +2 -0
  45. package/public/assets/IconWorld-XmQNg6JI.js.map +1 -0
  46. package/public/assets/IconWorldPlus-CxGGv2eD.js +2 -0
  47. package/public/assets/IconWorldPlus-CxGGv2eD.js.map +1 -0
  48. package/public/assets/app-DMr_-wik.js +7 -0
  49. package/public/assets/app-DMr_-wik.js.map +1 -0
  50. package/public/assets/auth-CEYiizOt.js +2 -0
  51. package/public/assets/auth-CEYiizOt.js.map +1 -0
  52. package/public/assets/index-BDkarAkX.js +3 -0
  53. package/public/assets/index-BDkarAkX.js.map +1 -0
  54. package/public/assets/{index-2cgXLhrt.js → index-DEL-PD_8.js} +2 -2
  55. package/public/assets/{index-2cgXLhrt.js.map → index-DEL-PD_8.js.map} +1 -1
  56. package/public/assets/index-D_STNela.js +2 -0
  57. package/public/assets/index-D_STNela.js.map +1 -0
  58. package/public/assets/index-Dkh3HiBz.js +4 -0
  59. package/public/assets/index-Dkh3HiBz.js.map +1 -0
  60. package/public/assets/shared/@components-CgsSYMe6.js +2 -0
  61. package/public/assets/shared/@components-CgsSYMe6.js.map +1 -0
  62. package/public/assets/shared/@hooks-DT93N7wd.js +2 -0
  63. package/public/assets/shared/{@hooks-Ch_hJYh0.js.map → @hooks-DT93N7wd.js.map} +1 -1
  64. package/public/assets/shared/@tabler_icons-react-DrVFX3uL.js +3 -0
  65. package/public/assets/shared/{@tabler_icons-react-iQk11eD_.js.map → @tabler_icons-react-DrVFX3uL.js.map} +1 -1
  66. package/public/assets/shared/{wouter-CUC1caxu.js → wouter-CNISJ5i6.js} +2 -2
  67. package/public/assets/shared/wouter-CNISJ5i6.js.map +1 -0
  68. package/public/assets/useHasScope-BOdFktko.js +2 -0
  69. package/public/assets/useHasScope-BOdFktko.js.map +1 -0
  70. package/public/auth.html +97 -33
  71. package/public/assets/IconArrowRight-BuVxhqKX.js +0 -2
  72. package/public/assets/IconArrowRight-BuVxhqKX.js.map +0 -1
  73. package/public/assets/IconWorld-B6GK5qpx.js +0 -2
  74. package/public/assets/IconWorld-B6GK5qpx.js.map +0 -1
  75. package/public/assets/IconWorldPlus-Dkos72Ws.js +0 -2
  76. package/public/assets/IconWorldPlus-Dkos72Ws.js.map +0 -1
  77. package/public/assets/app-CLZ-5FIi.js +0 -6
  78. package/public/assets/app-CLZ-5FIi.js.map +0 -1
  79. package/public/assets/auth-6N37o421.js +0 -2
  80. package/public/assets/auth-6N37o421.js.map +0 -1
  81. package/public/assets/index-DLZ8-XzO.js +0 -4
  82. package/public/assets/index-DLZ8-XzO.js.map +0 -1
  83. package/public/assets/index-DY750sgZ.js +0 -2
  84. package/public/assets/index-DY750sgZ.js.map +0 -1
  85. package/public/assets/shared/@components-DPHARroA.js +0 -2
  86. package/public/assets/shared/@components-DPHARroA.js.map +0 -1
  87. package/public/assets/shared/@hooks-Ch_hJYh0.js +0 -2
  88. package/public/assets/shared/@tabler_icons-react-iQk11eD_.js +0 -3
  89. package/public/assets/shared/wouter-CUC1caxu.js.map +0 -1
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const trpc = require("../trpc.js");
4
4
  const chat = require("./chat.js");
5
+ const mfa = require("./mfa.js");
5
6
  const player = require("./player.js");
6
7
  const plugin = require("./plugin.js");
7
8
  const role = require("./role.js");
@@ -17,7 +18,8 @@ const appRouter = trpc.mergeRouters(
17
18
  server.serverRouter,
18
19
  user.userRouter,
19
20
  world.worldRouter,
20
- role.roleRouter
21
+ role.roleRouter,
22
+ mfa.mfaRouter
21
23
  );
22
24
  exports.appRouter = appRouter;
23
25
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../../src/webserver/backend/router/index.ts"],"sourcesContent":["import { mergeRouters } from '../trpc';\nimport { chatRouter } from './chat';\nimport { playerRouter } from './player';\nimport { pluginRouter } from './plugin';\nimport { roleRouter } from './role';\nimport { serverRouter } from './server';\nimport { sessionRouter } from './session';\nimport { userRouter } from './user';\nimport { worldRouter } from './world';\n\nexport const appRouter = mergeRouters(\n sessionRouter,\n chatRouter,\n playerRouter,\n pluginRouter,\n serverRouter,\n userRouter,\n worldRouter,\n roleRouter,\n);\n\nexport type AppRouter = typeof appRouter;\n"],"names":["mergeRouters","sessionRouter","chatRouter","playerRouter","pluginRouter","serverRouter","userRouter","worldRouter","roleRouter"],"mappings":";;;;;;;;;;;AAUO,MAAM,YAAYA,KAAAA;AAAAA,EACvBC,QAAAA;AAAAA,EACAC,KAAAA;AAAAA,EACAC,OAAAA;AAAAA,EACAC,OAAAA;AAAAA,EACAC,OAAAA;AAAAA,EACAC,KAAAA;AAAAA,EACAC,MAAAA;AAAAA,EACAC,KAAAA;AACF;;"}
1
+ {"version":3,"file":"index.js","sources":["../../../../src/webserver/backend/router/index.ts"],"sourcesContent":["import { mergeRouters } from '../trpc';\nimport { chatRouter } from './chat';\nimport { mfaRouter } from './mfa';\nimport { playerRouter } from './player';\nimport { pluginRouter } from './plugin';\nimport { roleRouter } from './role';\nimport { serverRouter } from './server';\nimport { sessionRouter } from './session';\nimport { userRouter } from './user';\nimport { worldRouter } from './world';\n\nexport const appRouter = mergeRouters(\n sessionRouter,\n chatRouter,\n playerRouter,\n pluginRouter,\n serverRouter,\n userRouter,\n worldRouter,\n roleRouter,\n mfaRouter,\n);\n\nexport type AppRouter = typeof appRouter;\n"],"names":["mergeRouters","sessionRouter","chatRouter","playerRouter","pluginRouter","serverRouter","userRouter","worldRouter","roleRouter","mfaRouter"],"mappings":";;;;;;;;;;;;AAWO,MAAM,YAAYA,KAAAA;AAAAA,EACvBC,QAAAA;AAAAA,EACAC,KAAAA;AAAAA,EACAC,OAAAA;AAAAA,EACAC,OAAAA;AAAAA,EACAC,OAAAA;AAAAA,EACAC,KAAAA;AAAAA,EACAC,MAAAA;AAAAA,EACAC,KAAAA;AAAAA,EACAC,IAAAA;AACF;;"}
@@ -0,0 +1,162 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const bcrypt = require("bcryptjs");
4
+ const crypto = require("crypto");
5
+ const QRCode = require("qrcode");
6
+ const server = require("@simplewebauthn/server");
7
+ const v4 = require("zod/v4");
8
+ const scopes = require("../scopes.js");
9
+ const totp = require("../totp.js");
10
+ const trpc = require("../trpc.js");
11
+ function getRpID(req) {
12
+ const origin = req.headers.origin;
13
+ if (origin) {
14
+ try {
15
+ return new URL(origin).hostname;
16
+ } catch {
17
+ }
18
+ }
19
+ return req.hostname;
20
+ }
21
+ async function requirePassword(ctx, password) {
22
+ return bcrypt.compare(password, ctx.user.hash);
23
+ }
24
+ const mfaRouter = trpc.router({
25
+ mfa: trpc.router({
26
+ status: trpc.protectedProcedure(scopes.ScopeName.SessionInfo).query(({ ctx }) => {
27
+ const user = ctx.user;
28
+ return {
29
+ totpEnabled: user.totpEnabled ?? false,
30
+ passkeys: (user.passkeys ?? []).map((p) => ({
31
+ id: p.id,
32
+ name: p.name,
33
+ created: p.created,
34
+ lastUsed: p.lastUsed
35
+ })),
36
+ hasRecoveryCodes: (user.recoveryCodes?.length ?? 0) > 0
37
+ };
38
+ }),
39
+ totp: trpc.router({
40
+ setup: trpc.protectedProcedure(scopes.ScopeName.SessionInfo).input(v4.z.object({ password: v4.z.string() })).mutation(async ({ input, ctx }) => {
41
+ if (!await requirePassword(ctx, input.password)) {
42
+ return { error: "incorrect password" };
43
+ }
44
+ const secret = totp.generateSecret();
45
+ const uri = totp.generateURI(secret, ctx.user.username || "Admin");
46
+ const qrCode = await QRCode.toDataURL(uri);
47
+ ctx.req.session.pendingTotpSecret = secret;
48
+ ctx.req.session.save();
49
+ return { secret, uri, qrCode };
50
+ }),
51
+ enable: trpc.protectedProcedure(scopes.ScopeName.SessionInfo).input(v4.z.object({ code: v4.z.string() })).mutation(async ({ input, ctx }) => {
52
+ const { database } = trpc.getContextDeps();
53
+ const secret = ctx.req.session.pendingTotpSecret;
54
+ if (!secret) return "no pending TOTP setup";
55
+ if (!totp.verifyToken(input.code, secret)) {
56
+ return "invalid code";
57
+ }
58
+ await database.setUserTotp(ctx.user.username, secret, true);
59
+ delete ctx.req.session.pendingTotpSecret;
60
+ ctx.req.session.save();
61
+ return "";
62
+ }),
63
+ disable: trpc.protectedProcedure(scopes.ScopeName.SessionInfo).input(v4.z.object({ password: v4.z.string() })).mutation(async ({ input, ctx }) => {
64
+ const { database } = trpc.getContextDeps();
65
+ if (!await requirePassword(ctx, input.password)) {
66
+ return "incorrect password";
67
+ }
68
+ await database.disableUserTotp(ctx.user.username);
69
+ return "";
70
+ })
71
+ }),
72
+ passkey: trpc.router({
73
+ registerOptions: trpc.protectedProcedure(scopes.ScopeName.SessionInfo).mutation(
74
+ async ({ ctx }) => {
75
+ const rpID = getRpID(ctx.req);
76
+ const options = await server.generateRegistrationOptions({
77
+ rpName: "Omegga",
78
+ rpID,
79
+ userName: ctx.user.username || "Admin",
80
+ excludeCredentials: (ctx.user.passkeys ?? []).map((p) => ({
81
+ id: p.id,
82
+ transports: p.transports
83
+ })),
84
+ authenticatorSelection: {
85
+ residentKey: "preferred",
86
+ userVerification: "preferred"
87
+ }
88
+ });
89
+ ctx.req.session.mfaChallenge = options.challenge;
90
+ ctx.req.session.save();
91
+ return options;
92
+ }
93
+ ),
94
+ register: trpc.protectedProcedure(scopes.ScopeName.SessionInfo).input(
95
+ v4.z.object({
96
+ credential: v4.z.any(),
97
+ name: v4.z.string().max(64).default("Passkey")
98
+ })
99
+ ).mutation(async ({ input, ctx }) => {
100
+ const { database } = trpc.getContextDeps();
101
+ const challenge = ctx.req.session.mfaChallenge;
102
+ if (!challenge) return "no pending challenge";
103
+ delete ctx.req.session.mfaChallenge;
104
+ ctx.req.session.save();
105
+ try {
106
+ const verification = await server.verifyRegistrationResponse({
107
+ response: input.credential,
108
+ expectedChallenge: challenge,
109
+ expectedOrigin: ctx.req.headers.origin ?? `${ctx.req.protocol}://${ctx.req.get("host")}`,
110
+ expectedRPID: getRpID(ctx.req)
111
+ });
112
+ if (!verification.verified || !verification.registrationInfo) {
113
+ return "verification failed";
114
+ }
115
+ const { credential } = verification.registrationInfo;
116
+ await database.addPasskey(ctx.user.username, {
117
+ id: credential.id,
118
+ publicKey: Buffer.from(credential.publicKey).toString(
119
+ "base64url"
120
+ ),
121
+ counter: credential.counter,
122
+ name: input.name,
123
+ created: Date.now(),
124
+ lastUsed: 0,
125
+ transports: input.credential.response?.transports
126
+ });
127
+ return "";
128
+ } catch (e) {
129
+ console.error("Passkey registration error:", e);
130
+ return "registration failed";
131
+ }
132
+ }),
133
+ remove: trpc.protectedProcedure(scopes.ScopeName.SessionInfo).input(v4.z.object({ id: v4.z.string(), password: v4.z.string() })).mutation(async ({ input, ctx }) => {
134
+ const { database } = trpc.getContextDeps();
135
+ if (!await requirePassword(ctx, input.password)) {
136
+ return "incorrect password";
137
+ }
138
+ await database.removePasskey(ctx.user.username, input.id);
139
+ return "";
140
+ })
141
+ }),
142
+ recoveryCodes: trpc.router({
143
+ generate: trpc.protectedProcedure(scopes.ScopeName.SessionInfo).input(v4.z.object({ password: v4.z.string() })).mutation(async ({ input, ctx }) => {
144
+ const { database } = trpc.getContextDeps();
145
+ if (!await requirePassword(ctx, input.password)) {
146
+ return { error: "incorrect password" };
147
+ }
148
+ const codes = [];
149
+ const hashes = [];
150
+ for (let i = 0; i < 10; i++) {
151
+ const code = crypto.randomBytes(5).toString("hex");
152
+ codes.push(code);
153
+ hashes.push(await bcrypt.hash(code, 10));
154
+ }
155
+ await database.setRecoveryCodes(ctx.user.username, hashes);
156
+ return { codes };
157
+ })
158
+ })
159
+ })
160
+ });
161
+ exports.mfaRouter = mfaRouter;
162
+ //# sourceMappingURL=mfa.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mfa.js","sources":["../../../../src/webserver/backend/router/mfa.ts"],"sourcesContent":["import bcrypt from 'bcryptjs';\nimport crypto from 'crypto';\nimport QRCode from 'qrcode';\nimport {\n generateRegistrationOptions,\n verifyRegistrationResponse,\n} from '@simplewebauthn/server';\nimport { z } from 'zod/v4';\nimport { ScopeName } from '../scopes';\nimport { generateSecret, generateURI, verifyToken } from '../totp';\nimport { getContextDeps, protectedProcedure, router } from '../trpc';\n\nfunction getRpID(req: import('express').Request): string {\n const origin = req.headers.origin;\n if (origin) {\n try {\n return new URL(origin).hostname;\n } catch {}\n }\n return req.hostname;\n}\n\nasync function requirePassword(ctx: any, password: string): Promise<boolean> {\n return bcrypt.compare(password, ctx.user.hash);\n}\n\nexport const mfaRouter = router({\n mfa: router({\n status: protectedProcedure(ScopeName.SessionInfo).query(({ ctx }) => {\n const user = ctx.user;\n return {\n totpEnabled: user.totpEnabled ?? false,\n passkeys: (user.passkeys ?? []).map(p => ({\n id: p.id,\n name: p.name,\n created: p.created,\n lastUsed: p.lastUsed,\n })),\n hasRecoveryCodes: (user.recoveryCodes?.length ?? 0) > 0,\n };\n }),\n\n totp: router({\n setup: protectedProcedure(ScopeName.SessionInfo)\n .input(z.object({ password: z.string() }))\n .mutation(async ({ input, ctx }) => {\n if (!(await requirePassword(ctx, input.password))) {\n return { error: 'incorrect password' };\n }\n const secret = generateSecret();\n const uri = generateURI(secret, ctx.user.username || 'Admin');\n const qrCode = await QRCode.toDataURL(uri);\n // store secret in session so enable can't accept arbitrary secrets\n (ctx.req as any).session.pendingTotpSecret = secret;\n (ctx.req as any).session.save();\n return { secret, uri, qrCode };\n }),\n\n enable: protectedProcedure(ScopeName.SessionInfo)\n .input(z.object({ code: z.string() }))\n .mutation(async ({ input, ctx }) => {\n const { database } = getContextDeps();\n const secret = (ctx.req as any).session.pendingTotpSecret;\n if (!secret) return 'no pending TOTP setup';\n if (!verifyToken(input.code, secret)) {\n return 'invalid code';\n }\n await database.setUserTotp(ctx.user.username, secret, true);\n delete (ctx.req as any).session.pendingTotpSecret;\n (ctx.req as any).session.save();\n return '';\n }),\n\n disable: protectedProcedure(ScopeName.SessionInfo)\n .input(z.object({ password: z.string() }))\n .mutation(async ({ input, ctx }) => {\n const { database } = getContextDeps();\n if (!(await requirePassword(ctx, input.password))) {\n return 'incorrect password';\n }\n await database.disableUserTotp(ctx.user.username);\n return '';\n }),\n }),\n\n passkey: router({\n registerOptions: protectedProcedure(ScopeName.SessionInfo).mutation(\n async ({ ctx }) => {\n const rpID = getRpID(ctx.req);\n const options = await generateRegistrationOptions({\n rpName: 'Omegga',\n rpID,\n userName: ctx.user.username || 'Admin',\n excludeCredentials: (ctx.user.passkeys ?? []).map(p => ({\n id: p.id,\n transports: p.transports as any,\n })),\n authenticatorSelection: {\n residentKey: 'preferred',\n userVerification: 'preferred',\n },\n });\n (ctx.req as any).session.mfaChallenge = options.challenge;\n (ctx.req as any).session.save();\n return options;\n },\n ),\n\n register: protectedProcedure(ScopeName.SessionInfo)\n .input(\n z.object({\n credential: z.any(),\n name: z.string().max(64).default('Passkey'),\n }),\n )\n .mutation(async ({ input, ctx }) => {\n const { database } = getContextDeps();\n const challenge = (ctx.req as any).session.mfaChallenge;\n if (!challenge) return 'no pending challenge';\n // clear challenge immediately to prevent replay\n delete (ctx.req as any).session.mfaChallenge;\n (ctx.req as any).session.save();\n try {\n const verification = await verifyRegistrationResponse({\n response: input.credential,\n expectedChallenge: challenge,\n expectedOrigin:\n ctx.req.headers.origin ??\n `${ctx.req.protocol}://${ctx.req.get('host')}`,\n expectedRPID: getRpID(ctx.req),\n });\n if (!verification.verified || !verification.registrationInfo) {\n return 'verification failed';\n }\n const { credential } = verification.registrationInfo;\n await database.addPasskey(ctx.user.username, {\n id: credential.id,\n publicKey: Buffer.from(credential.publicKey).toString(\n 'base64url',\n ),\n counter: credential.counter,\n name: input.name,\n created: Date.now(),\n lastUsed: 0,\n transports: input.credential.response?.transports,\n });\n return '';\n } catch (e) {\n console.error('Passkey registration error:', e);\n return 'registration failed';\n }\n }),\n\n remove: protectedProcedure(ScopeName.SessionInfo)\n .input(z.object({ id: z.string(), password: z.string() }))\n .mutation(async ({ input, ctx }) => {\n const { database } = getContextDeps();\n if (!(await requirePassword(ctx, input.password))) {\n return 'incorrect password';\n }\n await database.removePasskey(ctx.user.username, input.id);\n return '';\n }),\n }),\n\n recoveryCodes: router({\n generate: protectedProcedure(ScopeName.SessionInfo)\n .input(z.object({ password: z.string() }))\n .mutation(async ({ input, ctx }) => {\n const { database } = getContextDeps();\n if (!(await requirePassword(ctx, input.password))) {\n return { error: 'incorrect password' };\n }\n const codes: string[] = [];\n const hashes: string[] = [];\n for (let i = 0; i < 10; i++) {\n const code = crypto.randomBytes(5).toString('hex');\n codes.push(code);\n hashes.push(await bcrypt.hash(code, 10));\n }\n await database.setRecoveryCodes(ctx.user.username, hashes);\n return { codes };\n }),\n }),\n }),\n});\n"],"names":["router","protectedProcedure","ScopeName","z","generateSecret","generateURI","getContextDeps","verifyToken","generateRegistrationOptions","verifyRegistrationResponse"],"mappings":"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"}
@@ -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;;"}