From 941c8400c083a6e1191abeec3202263c9fdfa0af Mon Sep 17 00:00:00 2001 From: zombieb Date: Sun, 27 Jul 2025 19:49:35 -0400 Subject: [PATCH] b --- src/main.ts | 7 +- src/routes/accounts/routes/account.ts | 3 - src/routes/api/routes/PlayerReporting.ts | 18 +++++ src/routes/api/routes/avatar.ts | 22 +++++- src/routes/api/routes/players.ts | 7 ++ src/routes/api/routes/relationships.ts | 7 ++ src/routes/api/routes/settings.ts | 13 ++-- src/routes/auth/routes/cachedlogin.ts | 15 ++++ src/routes/auth/routes/connect.ts | 1 + src/routes/match/root.ts | 7 ++ src/routes/match/routes/player.ts | 10 +++ src/server/avatars/base.ts | 69 ++++++++++++++++++- src/server/commands/command.ts | 5 -- src/server/gameconfigs/base.ts | 18 ++--- src/server/presence/base.ts | 16 +++++ src/server/profiles/content/Avatar.ts | 35 ++++++++++ src/server/profiles/content/Matchmaking.ts | 34 +++++++++ src/server/profiles/profile.ts | 3 + src/server/server.ts | 2 + src/server/socket/signalr/socket.ts | 7 +- .../signalr/targets/SubscribeToPlayers.ts | 18 +++++ .../socket/signalr/targets/targetbase.ts | 23 ++----- src/util/path.ts | 3 + 23 files changed, 293 insertions(+), 50 deletions(-) create mode 100644 src/routes/api/routes/PlayerReporting.ts create mode 100644 src/routes/api/routes/players.ts create mode 100644 src/routes/api/routes/relationships.ts create mode 100644 src/routes/match/root.ts create mode 100644 src/routes/match/routes/player.ts create mode 100644 src/server/presence/base.ts create mode 100644 src/server/profiles/content/Avatar.ts create mode 100644 src/server/profiles/content/Matchmaking.ts create mode 100644 src/server/socket/signalr/targets/SubscribeToPlayers.ts create mode 100644 src/util/path.ts diff --git a/src/main.ts b/src/main.ts index aad330c..83813c0 100644 --- a/src/main.ts +++ b/src/main.ts @@ -36,7 +36,8 @@ await routeImporter(AppRoot.app, 'src/', [ 'routes/root', 'routes/api', 'routes/auth', - 'routes/accounts' + 'routes/accounts', + 'routes/match' ]); // deno-lint-ignore require-await @@ -71,8 +72,8 @@ const server = Deno.serve({ hostname: "10.0.1.39", port: 13370, onListen: addr = availableTransports: [{transport:"WebSockets",transferFormats:["Text"]}] }), { headers: { 'Content-Type': 'application/json' }}); } - if (req.headers.get('Connection')?.includes('Upgrade') && req.headers.get('Upgrade') === 'websocket') { - const isSignalR = req.headers.has('id'); + if (req.headers.get('Connection')?.includes('Upgrade') && req.headers.get('Upgrade')?.includes('websocket')) { + const isSignalR = url.searchParams.has('id'); if (isSignalR) { try { const authHeader = req.headers.get('Authorization'); diff --git a/src/routes/accounts/routes/account.ts b/src/routes/accounts/routes/account.ts index 1dd69b9..370cd98 100644 --- a/src/routes/accounts/routes/account.ts +++ b/src/routes/accounts/routes/account.ts @@ -3,9 +3,6 @@ import { authenticate } from "../../../util/api.ts"; import Server from "../../../server/server.ts"; import z from "zod"; import { typedZValidator } from "../../../util/validators.ts"; -import Logging from "@proxnet/undead-logging"; - -const log = new Logging("AccountDebug"); export const route = createHonoRoute('/account'); diff --git a/src/routes/api/routes/PlayerReporting.ts b/src/routes/api/routes/PlayerReporting.ts new file mode 100644 index 0000000..1dc71a9 --- /dev/null +++ b/src/routes/api/routes/PlayerReporting.ts @@ -0,0 +1,18 @@ +import { authenticate } from "../../../util/api.ts"; +import { createHonoRoute } from "../../../util/import.ts"; + +export const route = createHonoRoute('/PlayerReporting'); + +route.app.use(authenticate); + +route.app.get('/v1/moderationBlockDetails', c => { + return c.json({ + ReportCategory: 0, + Duration: 0, + GameSessionId: 0, + IsHostKick: false, + VoteKickReason: "", + Message: "", + IsBan: false + }); +}); \ No newline at end of file diff --git a/src/routes/api/routes/avatar.ts b/src/routes/api/routes/avatar.ts index 864d095..97a8ee5 100644 --- a/src/routes/api/routes/avatar.ts +++ b/src/routes/api/routes/avatar.ts @@ -1,7 +1,27 @@ +import { profileAvatarSchema } from "../../../server/profiles/content/Avatar.ts"; +import Server from "../../../server/server.ts"; +import { authenticate } from "../../../util/api.ts"; import { createHonoRoute } from "../../../util/import.ts"; +import { typedZValidator } from "../../../util/validators.ts"; export const route = createHonoRoute("/avatar"); route.app.get('/v1/defaultunlocked', c => { - return c.json([]); + return c.json(Server.Avatars.getAllPossibleCombinations()); +}); + +route.app.get('/v4/items', c => { + return c.json(Server.Avatars.getAllPossibleCombinations()); +}); + +route.app.use(authenticate); + +route.app.get('/v2', async c => { + const outfit = await c.get('profile').Avatar.getAvatar(); + return c.json(outfit); +}); +route.app.post('/v2/set', typedZValidator('json', profileAvatarSchema), async c => { + const outfit = c.req.valid('json'); + await c.get('profile').Avatar.setAvatar(outfit); + return c.status(200); }); \ No newline at end of file diff --git a/src/routes/api/routes/players.ts b/src/routes/api/routes/players.ts new file mode 100644 index 0000000..d4a7f2a --- /dev/null +++ b/src/routes/api/routes/players.ts @@ -0,0 +1,7 @@ +import { createHonoRoute } from "../../../util/import.ts"; + +export const route = createHonoRoute("/players"); + +route.app.get('/v2/progression/bulk', c => { + return c.json([]); // todo: progression +}); \ No newline at end of file diff --git a/src/routes/api/routes/relationships.ts b/src/routes/api/routes/relationships.ts new file mode 100644 index 0000000..cd0bcfd --- /dev/null +++ b/src/routes/api/routes/relationships.ts @@ -0,0 +1,7 @@ +import { createHonoRoute } from "../../../util/import.ts"; + +export const route = createHonoRoute('/relationships'); + +route.app.get('/v2/get', c => { + return c.json([]); +}); \ No newline at end of file diff --git a/src/routes/api/routes/settings.ts b/src/routes/api/routes/settings.ts index be2f710..504d6c7 100644 --- a/src/routes/api/routes/settings.ts +++ b/src/routes/api/routes/settings.ts @@ -3,17 +3,20 @@ import { authenticate, genericResponse } from "../../../util/api.ts"; import { createHonoRoute } from "../../../util/import.ts"; import { transformStringToEnum, typedZValidator } from "../../../util/validators.ts"; import { ProfileSetting } from "../../../server/profiles/content/Settings.ts"; -import { trimTrailingSlash } from "@hono/hono/trailing-slash"; +import { HonoEnv } from "../../../util/types.ts"; +import { Context } from "@hono/hono"; export const route = createHonoRoute('/settings'); -route.app.use(authenticate, trimTrailingSlash()); +route.app.use(authenticate); -route.app.get('/v2', async c => { +const getSettingsMiddleware = async (c: Context) => { const profile = c.get('profile'); const settings = await profile.Settings.getAllSettings(); - c.json(settings); -}); + return c.json(settings); +}; +route.app.get('/v2/', getSettingsMiddleware); +route.app.get('/v2', getSettingsMiddleware); const settingsSetSchema = z.object({ Key: z.string().transform(transformStringToEnum(ProfileSetting, true)), diff --git a/src/routes/auth/routes/cachedlogin.ts b/src/routes/auth/routes/cachedlogin.ts index 113fe5c..c8cb211 100644 --- a/src/routes/auth/routes/cachedlogin.ts +++ b/src/routes/auth/routes/cachedlogin.ts @@ -3,6 +3,10 @@ import { createHonoRoute } from "../../../util/import.ts"; import { transformStringToEnum, typedZValidator } from "../../../util/validators.ts"; import { PlatformType } from "../../../server/platforms/base.ts"; import Server from "../../../server/server.ts"; +import { authenticate } from "../../../util/api.ts"; +import Logging from "@proxnet/undead-logging"; + +const log = new Logging("CachedLoginDebug"); export const route = createHonoRoute("/cachedlogin"); @@ -15,4 +19,15 @@ route.app.get('/forplatformid/:platformType/:platformId', typedZValidator('param const { platformType, platformId } = c.req.valid('param'); return c.json((await Server.Platforms.getCachedLogins(platformType || PlatformType.Steam, platformId, true)) || []); +}); + +route.app.use(authenticate); + +const forPlatformIdsReqSchema = z.object({ + id: z.string() +}); +route.app.post('/forplatformids', typedZValidator('form', forPlatformIdsReqSchema), async c => { + const { id } = c.req.valid('form'); + const ids = await Server.Platforms.getCachedLogins(PlatformType.Steam, id, true); + return c.json(ids || []); }); \ No newline at end of file diff --git a/src/routes/auth/routes/connect.ts b/src/routes/auth/routes/connect.ts index 5279ead..5408a64 100644 --- a/src/routes/auth/routes/connect.ts +++ b/src/routes/auth/routes/connect.ts @@ -117,6 +117,7 @@ route.app.post('/token', typedZValidator('form', tokenGrantSchema), async c => { if (logins && logins.find(login => login.accountId === form.account_id)) { const profile = await Server.Profiles.get(form.account_id); if (!profile) return error(TokenRequestError.InvalidRequest, "No such profile"); + await Server.Platforms.updateLastLoginTime(form.platform, form.platform_id, form.account_id); const token = await Server.Platforms.getToken(profile.getId(), await profile.getRole() || 'user'); return c.json({ diff --git a/src/routes/match/root.ts b/src/routes/match/root.ts new file mode 100644 index 0000000..5cf5964 --- /dev/null +++ b/src/routes/match/root.ts @@ -0,0 +1,7 @@ +import { createHonoRoute, routeImporter } from "../../util/import.ts"; + +export const route = createHonoRoute('/match'); + +await routeImporter(route.app, 'src/routes/match/', [ + 'routes' +]); \ No newline at end of file diff --git a/src/routes/match/routes/player.ts b/src/routes/match/routes/player.ts new file mode 100644 index 0000000..aa5bed4 --- /dev/null +++ b/src/routes/match/routes/player.ts @@ -0,0 +1,10 @@ +import { authenticate } from "../../../util/api.ts"; +import { createHonoRoute } from "../../../util/import.ts"; + +export const route = createHonoRoute("/player"); + +route.app.use(authenticate); + +route.app.post('/login', async c => { + return c.status(200); +}); \ No newline at end of file diff --git a/src/server/avatars/base.ts b/src/server/avatars/base.ts index d881035..28b4948 100644 --- a/src/server/avatars/base.ts +++ b/src/server/avatars/base.ts @@ -1,5 +1,72 @@ +import path from "node:path"; import { ServerContentBase } from "../ContentBase.ts"; +import { RootPath } from "../../util/path.ts"; + +interface AvatarImport { + allPossibleCombinations: { + _avatarItemData: { + Name: string + }, + _avatarItemVisualData: { + prefabGuid: string, + maskGuid: string, + swatchGuid: string, + decalGuid: string + } + }[] +} + +interface AvatarItemExport { + AvatarItemType: AvatarItemType, + AvatarItemDesc: string, + FriendlyName: string, + Tooltip: string, + Rarity: ItemRarity +} +export enum AvatarItemType { + Outfit, + HairDye +} +export enum ItemRarity { + None = -1, + Common, + Uncommon = 10, + Rare = 20, + Epic = 30, + Legendary = 50 +} export class AvatarContentBase extends ServerContentBase { - + #rawImport: AvatarItemExport[] = []; + + getAllPossibleCombinations() { + return this.#rawImport; + } + + formatAllPossibleCombinations() { + const parsed = JSON.parse(Deno.readTextFileSync(path.join(RootPath, '/res/avatar.json'))) as AvatarImport; + function formatVisualData(data: { + prefabGuid: string, + maskGuid: string, + swatchGuid: string, + decalGuid: string + }) { + const p = data.prefabGuid ? data.prefabGuid : ''; + const m = data.maskGuid ? data.maskGuid : ''; + const s = data.swatchGuid ? data.swatchGuid : ''; + const d = data.decalGuid ? data.decalGuid : ''; + return `${p},${s},${m},${d},` + } + this.#rawImport = parsed.allPossibleCombinations.map(data => ({ + AvatarItemType: AvatarItemType.Outfit, + AvatarItemDesc: formatVisualData(data._avatarItemVisualData), + FriendlyName: data._avatarItemData.Name, + Tooltip: "pre-avatar update item", + Rarity: ItemRarity.None + })); + } + + override start() { + this.formatAllPossibleCombinations(); + } } \ No newline at end of file diff --git a/src/server/commands/command.ts b/src/server/commands/command.ts index ba70987..0d161c6 100644 --- a/src/server/commands/command.ts +++ b/src/server/commands/command.ts @@ -1,6 +1,5 @@ import z from "zod"; import { CommandExec } from "./cmdtypes.ts"; - export interface CommandOptions { key: string[], subcommands?: Command[], @@ -16,7 +15,6 @@ export default class Command { exec: CommandExec | null; validate: z.ZodTuple | null; help: string | null; - #argsLength: number; constructor(options: CommandOptions) { this.subCmds = options.subcommands || []; @@ -24,7 +22,6 @@ export default class Command { this.exec = options.exec || null; this.validate = options.zod || null; this.help = options.help || null; - this.#argsLength = options.zod ? options.zod.def.items.length : 0; } getKey() { @@ -40,12 +37,10 @@ export default class Command { const cmd = this.subCmds.find(cmd => cmd.getKey().includes(root)); if (cmd) { const newArgs = args.slice(1); - if (cmd.#argsLength && newArgs.length !== cmd.#argsLength && cmd.help) return new Error(cmd.help); if (cmd.validate) { const res = cmd.validate.safeParse(newArgs); if (res.success) return cmd.dispatch(...res.data); else if (cmd.help) return new Error(cmd.help); - else if (cmd.#argsLength) return new Error(`'${root}' validation error: expected ${cmd.#argsLength} args, got ${newArgs.length}`); else return new Error(`'${root}' validation error`); } } diff --git a/src/server/gameconfigs/base.ts b/src/server/gameconfigs/base.ts index 947d15e..76e8c11 100644 --- a/src/server/gameconfigs/base.ts +++ b/src/server/gameconfigs/base.ts @@ -6,8 +6,6 @@ export default class GameConfigsBase extends ServerContentBase { #kvKey = 'gameconfigs'; - #usageError = new Error("Usage: []"); - async getGameConfig(key: string) { return (await this.kv.getKv().get([this.#kvKey, key])).value; } @@ -25,17 +23,16 @@ export default class GameConfigsBase extends ServerContentBase { this.kv.getKv().list({ prefix: [this.#kvKey] }) )).map(val => ({ Key: val.key[1] as string, Value: val.value }) - ).filter(gc => gc.Key && gc.Value); // ensure both the key and value exist + ).filter(gc => gc.Key && typeof gc.Value == 'string'); } - override start(): void { + override start() { this.server.Commands.addRootCommand(new Command({ key: ['gameconfigs', 'gameconfig', 'gc'], subcommands: [ new Command({ key: ['get', 'g'], exec: async (key: string) => { - if (!key) return this.#usageError; return await this.getGameConfig(key); }, zod: z.tuple([ @@ -45,20 +42,18 @@ export default class GameConfigsBase extends ServerContentBase { }), new Command({ key: ['set', 's'], - exec: async (key: string, value: string) => { - if (!key || !value) return this.#usageError; + exec: async (key: string, ...values: string[]) => { + const value = values.join(' '); return await this.setGameConfig(key, value); }, zod: z.tuple([ z.string(), - z.string() - ]), - help: 'Set a new GameConfig: , ' + ]).rest(z.string().optional()), + help: 'Set a new GameConfig: , ...' }), new Command({ key: ['del', 'rem', 'd', 'remove'], exec: async (key: string) => { - if (!key) return this.#usageError; return await this.delGameConfig(key); }, zod: z.tuple([ @@ -72,6 +67,7 @@ export default class GameConfigsBase extends ServerContentBase { const configs = await this.getAllGameConfigs(); return configs; }, + zod: z.tuple([]), help: 'List all saved GameConfigs' }), ] diff --git a/src/server/presence/base.ts b/src/server/presence/base.ts new file mode 100644 index 0000000..1b04f2c --- /dev/null +++ b/src/server/presence/base.ts @@ -0,0 +1,16 @@ +import { ServerContentBase } from "../ContentBase.ts"; +import type Profile from "../profiles/profile.ts"; + +class Presence { + +} + +export class PresenceBase extends ServerContentBase { + + #presenceMap: Map = new Map(); + + getPresence() { + + } + +} \ No newline at end of file diff --git a/src/server/profiles/content/Avatar.ts b/src/server/profiles/content/Avatar.ts new file mode 100644 index 0000000..af96166 --- /dev/null +++ b/src/server/profiles/content/Avatar.ts @@ -0,0 +1,35 @@ +import z from "zod"; +import ProfileContentManager from "./base.ts"; + +export const profileAvatarSchema = z.object({ + OutfitSelections: z.string(), + HairColor: z.string(), + SkinColor: z.string(), + FaceFeatures: z.string(), +}); +export type ProfileAvatar = z.infer; + +export class ProfileAvatarManager extends ProfileContentManager { + + #key = this.profile.constructProfilePropertyKey('avatar'); + #noAvatar: ProfileAvatar = { + OutfitSelections: "", + HairColor: "", + SkinColor: "", + FaceFeatures: "" + } + + async getAvatar(): Promise { + const item = await this.kv.getKv().get(this.#key); + if (item.value) { + const parsed = profileAvatarSchema.safeParse(item.value); + if (parsed.success) return parsed.data; + else return this.#noAvatar; + } else return this.#noAvatar; + } + + async setAvatar(outfit: ProfileAvatar) { + await this.kv.getKv().set(this.#key, outfit); + } + +} \ No newline at end of file diff --git a/src/server/profiles/content/Matchmaking.ts b/src/server/profiles/content/Matchmaking.ts new file mode 100644 index 0000000..fff7065 --- /dev/null +++ b/src/server/profiles/content/Matchmaking.ts @@ -0,0 +1,34 @@ +import ProfileContentManager from "./base.ts"; + +export enum DeviceClass { + Unknown, + VR, + Screen, + Mobile, + VRLow, + Quest2 +} + + +export class ProfileMatchmakingManager extends ProfileContentManager { + + #deviceClassKey = this.profile.constructProfilePropertyKey('deviceclass'); + async setLastDeviceClass(dc: DeviceClass) { + await this.kv.getKv().set(this.#deviceClassKey, dc); + } + async getLastDeviceClass(): Promise { + return (await this.kv.getKv().get(this.#deviceClassKey)).value || null; + } + + #loginLockKey = this.profile.constructProfilePropertyKey('loginlock'); + async setLoginLock(lock: string) { + await this.kv.getKv().set(this.#deviceClassKey, lock); + } + async getLoginLock(): Promise { + return (await this.kv.getKv().get(this.#loginLockKey)).value || ""; + } + async hasLoginLock() { + return (await this.kv.getKv().get(this.#loginLockKey)).value ? true : false; + } + +} \ No newline at end of file diff --git a/src/server/profiles/profile.ts b/src/server/profiles/profile.ts index 68822d9..ea92282 100644 --- a/src/server/profiles/profile.ts +++ b/src/server/profiles/profile.ts @@ -2,6 +2,7 @@ import KV from "../persistence/kv.ts"; import { ProfileRole } from "../platforms/base.ts"; import { type ServerBase } from "../server.ts"; import { type SignalRSocketHandler } from "../socket/signalr/socket.ts"; +import { ProfileAvatarManager } from "./content/Avatar.ts"; import { ProfileSettingsManager } from "./content/Settings.ts"; import ProfileManagerBase from "./manager.ts"; import { recNetAccountSchema, SelfAccount, type RecNetAccount } from "./types/profile.ts"; @@ -17,6 +18,7 @@ class Profile { #selfAcc: SelfAccount; Settings: ProfileSettingsManager; + Avatar: ProfileAvatarManager; constructor(acc: SelfAccount, kv: KV, server: ServerBase) { this.#id = acc.accountId; @@ -25,6 +27,7 @@ class Profile { this.#server = server; this.Settings = new ProfileSettingsManager(this, this.#kv); + this.Avatar = new ProfileAvatarManager(this, this.#kv); } async #saveSelfAcc() { diff --git a/src/server/server.ts b/src/server/server.ts index f6069bb..8b484ca 100644 --- a/src/server/server.ts +++ b/src/server/server.ts @@ -1,3 +1,4 @@ +import { AvatarContentBase } from "./avatars/base.ts"; import { EventManager } from "./baseevent.ts"; import { CommandsBase } from "./commands/commands.ts"; import GameConfigsBase from "./gameconfigs/base.ts"; @@ -16,6 +17,7 @@ class ServerBase extends EventManager { GameConfigs = new GameConfigsBase(this, 'gameconfigs', true); Commands = new CommandsBase(this, 'commands'); Platforms = new PlatformsManager(this, 'platforms', true); + Avatars = new AvatarContentBase(this, 'avatars'); } const Server = new ServerBase(); diff --git a/src/server/socket/signalr/socket.ts b/src/server/socket/signalr/socket.ts index 531bcb1..495c15c 100644 --- a/src/server/socket/signalr/socket.ts +++ b/src/server/socket/signalr/socket.ts @@ -16,6 +16,7 @@ import { import { SocketTarget } from "./targets/targetbase.ts"; import type Profile from "../../profiles/profile.ts"; import { detailedLog } from "../../../main.ts"; +import { PlayerSocketSubscriptionTarget } from "./targets/SubscribeToPlayers.ts"; const logmessages = true; @@ -39,7 +40,7 @@ export class SignalRSocketHandler { player.setSocketHandler(this); - //this.#Targets.set('SubscribeToPlayers', new PlayerSocketSubscriptionTarget(this)); + this.#Targets.set('SubscribeToPlayers', new PlayerSocketSubscriptionTarget(this)); for (const target of this.#Targets.values()) target.onInit(); @@ -55,7 +56,9 @@ export class SignalRSocketHandler { if (!targetExec) return { type: TargetResultType.NotATarget } as TargetResultNotATarget; else { try { - return { type: TargetResultType.Success, data: await targetExec.exec(args) } as TargetResultSuccess; + const parsed = targetExec.zod.safeParse(args); + if (parsed.success) return { type: TargetResultType.Success, data: await targetExec.exec(args) } as TargetResultSuccess; + else return { type: TargetResultType.Failure, err: "Argument parse failure" } as TargetResultFailure; } catch (err) { this.#log.w(`Target '${target}' function error: ${err}`); if (err instanceof Error) return { type: TargetResultType.Failure, err: err } as TargetResultFailure; diff --git a/src/server/socket/signalr/targets/SubscribeToPlayers.ts b/src/server/socket/signalr/targets/SubscribeToPlayers.ts new file mode 100644 index 0000000..7fea806 --- /dev/null +++ b/src/server/socket/signalr/targets/SubscribeToPlayers.ts @@ -0,0 +1,18 @@ +import z from "zod"; +import { SocketTarget } from "./targetbase.ts"; + +export class PlayerSocketSubscriptionTarget extends SocketTarget { + + #ids: number[] = []; + + override zod = z.tuple([]).rest(z.number()); + + override exec(...ids: number[]) { + this.#ids = ids; + } + + getIds() { + return this.#ids; + } + +} \ No newline at end of file diff --git a/src/server/socket/signalr/targets/targetbase.ts b/src/server/socket/signalr/targets/targetbase.ts index e4949c8..8514b52 100644 --- a/src/server/socket/signalr/targets/targetbase.ts +++ b/src/server/socket/signalr/targets/targetbase.ts @@ -1,26 +1,12 @@ -/* Galvanic Corrosion - Rec Room custom server for communities. - -Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published -by the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . */ - +import z from "zod"; import type { SignalRSocketHandler } from "../socket.ts"; export class SocketTarget { socket: SignalRSocketHandler; + zod: z.ZodTuple = z.tuple([]); + constructor(socket: SignalRSocketHandler) { this.socket = socket; } @@ -33,8 +19,7 @@ export class SocketTarget { return; } - // deno-lint-ignore require-await - async exec(_args: unknown) { + exec(_args: unknown): Promise | unknown { throw new Error("Execution for this target is not set."); } diff --git a/src/util/path.ts b/src/util/path.ts new file mode 100644 index 0000000..b265cef --- /dev/null +++ b/src/util/path.ts @@ -0,0 +1,3 @@ +import { platform } from "node:process"; + +export const RootPath = Deno.mainModule.substring(platform == 'win32' ? 8 : 7, Deno.mainModule.length - 11); \ No newline at end of file