diff --git a/apps/server/eslint-rules/prefer-relative-for-local-server-path.mjs b/apps/server/eslint-rules/prefer-relative-for-local-server-path.mjs
new file mode 100644
index 0000000..c73da95
--- /dev/null
+++ b/apps/server/eslint-rules/prefer-relative-for-local-server-path.mjs
@@ -0,0 +1,77 @@
+import path from 'node:path';
+
+const SERVER_ALIAS_PREFIX = '@server/';
+
+const toPosixPath = (value) => value.split(path.sep).join('/');
+
+const toRelativeImportPath = (fromDir, targetPath) => {
+ const relativePath = path.relative(fromDir, targetPath);
+ const posixRelativePath = toPosixPath(relativePath);
+
+ if (!posixRelativePath || posixRelativePath.startsWith('..')) {
+ return null;
+ }
+
+ return posixRelativePath.startsWith('.') ? posixRelativePath : `./${posixRelativePath}`;
+};
+
+export default {
+ meta: {
+ type: 'suggestion',
+ docs: {
+ description:
+ 'Warn when @server alias is used even though the import can be written as a same-level relative path.',
+ },
+ schema: [],
+ messages: {
+ preferRelative:
+ 'この import は相対参照で書けます。{{suggestion}} を使ってください(@server は遡りが必要な場合のみ使用)。',
+ },
+ },
+ create(context) {
+ const filename = context.filename;
+ if (!filename || filename === '') {
+ return {};
+ }
+
+ const srcRoot = path.resolve(process.cwd(), 'src');
+ const absoluteFilename = path.resolve(filename);
+
+ if (!absoluteFilename.startsWith(`${srcRoot}${path.sep}`)) {
+ return {};
+ }
+
+ const fromDirectory = path.dirname(absoluteFilename);
+
+ return {
+ ImportDeclaration(node) {
+ const rawImportPath = node.source?.value;
+ if (typeof rawImportPath !== 'string') {
+ return;
+ }
+
+ if (!rawImportPath.startsWith(SERVER_ALIAS_PREFIX)) {
+ return;
+ }
+
+ const aliasedSubPath = rawImportPath.slice(SERVER_ALIAS_PREFIX.length);
+ if (!aliasedSubPath) {
+ return;
+ }
+
+ const targetPath = path.resolve(srcRoot, aliasedSubPath);
+ const suggestion = toRelativeImportPath(fromDirectory, targetPath);
+
+ if (!suggestion) {
+ return;
+ }
+
+ context.report({
+ node: node.source,
+ messageId: 'preferRelative',
+ data: { suggestion },
+ });
+ },
+ };
+ },
+};
diff --git a/apps/server/eslint.config.mjs b/apps/server/eslint.config.mjs
new file mode 100644
index 0000000..f2adfcd
--- /dev/null
+++ b/apps/server/eslint.config.mjs
@@ -0,0 +1,26 @@
+import tsParser from '@typescript-eslint/parser';
+import preferRelativeForLocalServerPath from './eslint-rules/prefer-relative-for-local-server-path.mjs';
+
+export default [
+ {
+ ignores: ['dist/**', 'node_modules/**'],
+ },
+ {
+ files: ['src/**/*.ts'],
+ languageOptions: {
+ parser: tsParser,
+ ecmaVersion: 'latest',
+ sourceType: 'module',
+ },
+ plugins: {
+ local: {
+ rules: {
+ 'prefer-relative-for-local-server-path': preferRelativeForLocalServerPath,
+ },
+ },
+ },
+ rules: {
+ 'local/prefer-relative-for-local-server-path': 'warn',
+ },
+ },
+];
\ No newline at end of file
diff --git a/apps/server/package.json b/apps/server/package.json
index 632e620..903089c 100644
--- a/apps/server/package.json
+++ b/apps/server/package.json
@@ -5,7 +5,8 @@
"main": "dist/index.js",
"scripts": {
"dev": "tsx watch src/index.ts",
- "build": "tsc",
+ "build": "tsc && tsc-alias",
+ "lint": "eslint src --ext .ts",
"start": "node dist/index.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
@@ -20,6 +21,9 @@
"devDependencies": {
"@types/node": "^24.10.11",
"@types/socket.io": "^3.0.2",
+ "@typescript-eslint/parser": "^8.56.1",
+ "eslint": "^10.0.2",
+ "tsc-alias": "^1.8.16",
"tsx": "^4.21.0",
"typescript": "^5.9.3"
}
diff --git a/apps/server/src/domains/game/GameHandler.ts b/apps/server/src/domains/game/GameHandler.ts
index 2a45b4e..d1409db 100644
--- a/apps/server/src/domains/game/GameHandler.ts
+++ b/apps/server/src/domains/game/GameHandler.ts
@@ -1,99 +1,34 @@
import { Server, Socket } from "socket.io";
import { GameManager } from "./GameManager";
-import { RoomManager } from "../room/RoomManager";
-import { protocol, roomConsts } from "@repo/shared";
+import { RoomManager } from "@server/domains/room/RoomManager";
+import { protocol } from "@repo/shared";
import type { playerTypes } from "@repo/shared";
+import { onPing } from "./handlers/onPing";
+import { onStartGame } from "./handlers/onStartGame";
+import { onReadyForGame } from "./handlers/onReadyForGame";
+import { onMove } from "./handlers/onMove";
+import { onDisconnect } from "./handlers/onDisconnect";
export const registerGameHandlers = (io: Server, socket: Socket, gameManager: GameManager, roomManager: RoomManager) => {
// クライアントから送られてきた時刻をそのまま返しつつ、サーバーの現在時刻も添える
socket.on(protocol.SocketEvents.PING, (clientTime: number) => {
- socket.emit(protocol.SocketEvents.PONG, { clientTime, serverTime: Date.now() });
+ onPing(socket, clientTime);
});
// ゲーム開始要求処理
socket.on(protocol.SocketEvents.START_GAME, () => {
- const room = roomManager.getRoomByOwnerId(socket.id);
- if (!room) {
- console.log("[GameHandler] START_GAME ignored (no room)", { socketId: socket.id });
- return;
- }
-
- if (room.status === roomConsts.RoomPhase.PLAYING) {
- console.log("[GameHandler] START_GAME ignored (already playing)", { roomId: room.roomId });
- return;
- }
-
- console.log("[GameHandler] START_GAME accepted", {
- roomId: room.roomId,
- ownerId: socket.id,
- totalPlayers: room.players.length
- });
-
- if (room) {
- room.status = roomConsts.RoomPhase.PLAYING;
-
- const playerIds = room.players.map((p: { id: string }) => p.id);
-
- // 同ルーム全プレイヤーのゲーム管理登録
- room.players.forEach((p: { id: string }) => {
- gameManager.addPlayer(p.id);
- });
-
- // 20Hzのゲームループを開始し、毎フレームの送信処理を定義
- gameManager.startGameLoop(
- room.roomId,
- playerIds,
- (tickData) => {
- // 1. 各プレイヤーの最新座標をクライアントに送信
- tickData.players.forEach((playerData) => {
- io.to(room.roomId).emit(protocol.SocketEvents.UPDATE_PLAYER, playerData);
- });
-
- // 2. 差分があれば、ルーム内の全員に一斉送信
- if (tickData.cellUpdates.length > 0) {
- io.to(room.roomId).emit(protocol.SocketEvents.UPDATE_MAP_CELLS, tickData.cellUpdates);
- }
- },
-
- () => {
- // 3分経過時に GameLoop から呼ばれる処理
- console.log(`[GameHandler] ルーム ${room.roomId} のゲームが終了しました (3分経過)`);
- io.to(room.roomId).emit(protocol.SocketEvents.GAME_END); // クライアントへ終了通知
- room.status = roomConsts.RoomPhase.WAITING; // ルーム状態を待機に戻す
- }
- );
-
- // GameManagerから開始時刻を取得し、GAME_STARTイベントにデータを乗せて送る
- const startTime = gameManager.getRoomStartTime(room.roomId) || Date.now();
- io.to(room.roomId).emit(protocol.SocketEvents.GAME_START, { startTime });
- }
+ onStartGame(io, gameManager, roomManager, socket.id);
});
// 画面準備完了通知受信時初期データ返却
socket.on(protocol.SocketEvents.READY_FOR_GAME, () => {
- const allPlayers = gameManager.getAllPlayers();
- socket.emit(protocol.SocketEvents.CURRENT_PLAYERS, allPlayers);
- console.log("[GameHandler] READY_FOR_GAME received", { socketId: socket.id, totalPlayers: allPlayers.length });
-
- // 準備が完了したクライアントに対して、改めて開始時刻を個別に教える
- // Socket.ioの仕様上、socket.roomsには自身のIDと参加中のルームIDが含まれるため、そこからルームIDを特定する
- const roomId = Array.from(socket.rooms).find(room => room !== socket.id);
- if (roomId) {
- const startTime = gameManager.getRoomStartTime(roomId);
- if (startTime) {
- // io.to() による全員への一斉送信ではなく、socket.emit() でこの本人にだけ送る
- socket.emit(protocol.SocketEvents.GAME_START, { startTime });
- console.log("[GameHandler] GAME_START sent to ready client", { socketId: socket.id, roomId, startTime });
- }
- } else {
- console.log("[GameHandler] READY_FOR_GAME missing roomId", { socketId: socket.id });
- }
+ onReadyForGame(socket, gameManager);
});
// ゲームプレイ中イベント群
socket.on(protocol.SocketEvents.MOVE, (data: playerTypes.MovePayload) => {
- gameManager.movePlayer(socket.id, data.x, data.y);
+ onMove(gameManager, socket.id, data);
});
};
@@ -102,9 +37,5 @@
* 切断時のゲームクリーンアップ処理
*/
export const handleGameDisconnect = (io: Server, gameManager: GameManager, playerId: string) => {
- // ゲームからの除外処理
- gameManager.removePlayer(playerId);
- // 全体にプレイヤー削除を通知
- io.emit(protocol.SocketEvents.REMOVE_PLAYER, playerId);
- console.log("[GameHandler] player removed", { playerId });
+ onDisconnect(io, gameManager, playerId);
};
\ No newline at end of file
diff --git a/apps/server/src/domains/game/GameManager.ts b/apps/server/src/domains/game/GameManager.ts
index 332ef67..97ef4cf 100644
--- a/apps/server/src/domains/game/GameManager.ts
+++ b/apps/server/src/domains/game/GameManager.ts
@@ -1,68 +1,42 @@
-import { Player } from "./entities/Player.js";
-import { config } from "@repo/shared";
-import { MapStore } from "./states/MapStore";
-import { gridMapLogic } from "@repo/shared";
-import type { gridMapTypes } from "@repo/shared";
import { GameLoop, type TickData } from "./GameLoop";
+import type { gridMapTypes } from "@repo/shared";
+import { Player } from "./entities/Player.js";
+import { PlayerRegistry } from "./application/services/PlayerRegistry";
+import { GameSessionService } from "./application/services/GameSessionService";
// プレイヤー集合の生成・更新・参照管理クラス
export class GameManager {
- private players: Map;
- private mapStore: MapStore;
- private gameLoops: Map; // NodeJS.Timeout から変更
- private roomStartTimes: Map; // ルームごとのゲーム開始時間を保持する
+ private playerRegistry: PlayerRegistry;
+ private gameSessionService: GameSessionService;
constructor() {
- this.players = new Map();
- this.mapStore = new MapStore();
- this.gameLoops = new Map();
- this.roomStartTimes = new Map();
+ this.playerRegistry = new PlayerRegistry();
+ this.gameSessionService = new GameSessionService(this.playerRegistry.getPlayersRef());
}
// 外部(GameHandlerなど)から開始時刻を取得できるようにする
getRoomStartTime(roomId: string): number | undefined {
- return this.roomStartTimes.get(roomId);
+ return this.gameSessionService.getRoomStartTime(roomId);
}
// 新規プレイヤー登録と初期位置設定処理
addPlayer(id: string): Player {
- const player = new Player(id);
- player.x = config.GAME_CONFIG.GRID_COLS / 2;
- player.y = config.GAME_CONFIG.GRID_ROWS / 2;
- this.players.set(id, player);
- console.log("[GameManager] player added", { playerId: id, totalPlayers: this.players.size });
- return player;
+ return this.playerRegistry.addPlayer(id);
}
// プレイヤー登録解除処理
removePlayer(id: string) {
- const existed = this.players.delete(id);
- if (existed) {
- console.log("[GameManager] player removed", { playerId: id, totalPlayers: this.players.size });
- } else {
- console.log("[GameManager] player remove ignored (not found)", { playerId: id });
- }
+ this.playerRegistry.removePlayer(id);
}
// 指定IDプレイヤー参照取得
getPlayer(id: string) {
- return this.players.get(id);
+ return this.playerRegistry.getPlayer(id);
}
// 指定プレイヤー座標更新処理
movePlayer(id: string, x: number, y: number) {
- const player = this.players.get(id);
- if (player) {
- console.log(`Move Request -> ID:${id.slice(0,4)} x:${Math.round(x)} y:${Math.round(y)}`);
- if (typeof x !== "number" || typeof y !== "number" || isNaN(x) || isNaN(y)) {
- console.log("⚠️ 無効なデータなので無視しました");
- return;
- }
- player.x = x;
- player.y = y;
- } else {
- console.log("[GameManager] move ignored (player not found)", { playerId: id });
- }
+ this.playerRegistry.movePlayer(id, x, y);
}
/**
@@ -77,67 +51,23 @@
onTick: (data: TickData) => void,
onGameEnd: () => void
) {
- if (this.gameLoops.has(roomId)) {
- console.log("[GameManager] startGameLoop ignored (already running)", { roomId });
- return;
- }
-
- const tickRate = config.GAME_CONFIG.PLAYER_POSITION_UPDATE_MS;
-
- // ループ開始時に、このルームの開始時刻を記憶する
- this.roomStartTimes.set(roomId, Date.now());
-
- // GameLoopインスタンスを生成し、参照を渡す
- const loop = new GameLoop(
- roomId,
- tickRate,
- playerIds,
- this.players,
- this.mapStore,
- onTick,
- () => {
- // GameLoopが終了した時の処理
- this.roomStartTimes.delete(roomId);
- this.gameLoops.delete(roomId);
- onGameEnd(); // GameHandlerへ終了を伝える
- }
- );
-
- loop.start();
- this.gameLoops.set(roomId, loop);
- console.log("[GameManager] game loop started", { roomId, playerCount: playerIds.length });
+ this.gameSessionService.startGameLoop(roomId, playerIds, onTick, onGameEnd);
}
/**
* ゲームループを停止する
*/
stopGameLoop(roomId: string) {
- const loop = this.gameLoops.get(roomId);
- if (loop) {
- loop.stop();
- this.gameLoops.delete(roomId);
- this.roomStartTimes.delete(roomId); // 停止時も忘れずクリア
- console.log("[GameManager] game loop stopped", { roomId });
- } else {
- console.log("[GameManager] stopGameLoop ignored (not running)", { roomId });
- }
+ this.gameSessionService.stopGameLoop(roomId);
}
// 登録中全プレイヤー配列取得
getAllPlayers() {
- return Array.from(this.players.values());
+ return this.playerRegistry.getAllPlayers();
}
// 【一時的】移動したプレイヤーの足元を塗り、差分を返すメソッド
public paintAndGetUpdates(playerId: string): gridMapTypes.CellUpdate[] {
- const player = this.players.get(playerId);
- if (!player) return [];
-
- const gridIndex = gridMapLogic.getGridIndexFromPosition(player.x, player.y);
- if (gridIndex !== null) {
- this.mapStore.paintCell(gridIndex, player.teamId);
- }
-
- return this.mapStore.getAndClearUpdates();
+ return this.gameSessionService.paintAndGetUpdates(playerId);
}
}
\ No newline at end of file
diff --git a/apps/server/src/domains/game/application/ports/gameUseCasePorts.ts b/apps/server/src/domains/game/application/ports/gameUseCasePorts.ts
new file mode 100644
index 0000000..56ae47e
--- /dev/null
+++ b/apps/server/src/domains/game/application/ports/gameUseCasePorts.ts
@@ -0,0 +1,25 @@
+import type { TickData } from "../../GameLoop";
+
+export interface StartGamePort {
+ addPlayer(id: string): void;
+ startGameLoop(
+ roomId: string,
+ playerIds: string[],
+ onTick: (data: TickData) => void,
+ onGameEnd: () => void
+ ): void;
+ getRoomStartTime(roomId: string): number | undefined;
+}
+
+export interface ReadyForGamePort {
+ getAllPlayers(): unknown[];
+ getRoomStartTime(roomId: string): number | undefined;
+}
+
+export interface MovePlayerPort {
+ movePlayer(id: string, x: number, y: number): void;
+}
+
+export interface DisconnectPlayerPort {
+ removePlayer(id: string): void;
+}
diff --git a/apps/server/src/domains/game/application/services/GameSessionService.ts b/apps/server/src/domains/game/application/services/GameSessionService.ts
new file mode 100644
index 0000000..ab33e56
--- /dev/null
+++ b/apps/server/src/domains/game/application/services/GameSessionService.ts
@@ -0,0 +1,78 @@
+import { config, gridMapLogic } from "@repo/shared";
+import type { gridMapTypes } from "@repo/shared";
+import { GameLoop, type TickData } from "../../GameLoop";
+import { Player } from "../../entities/Player.js";
+import { MapStore } from "../../states/MapStore";
+
+export class GameSessionService {
+ private mapStore: MapStore;
+ private gameLoops: Map;
+ private roomStartTimes: Map;
+
+ constructor(private players: Map) {
+ this.mapStore = new MapStore();
+ this.gameLoops = new Map();
+ this.roomStartTimes = new Map();
+ }
+
+ public getRoomStartTime(roomId: string): number | undefined {
+ return this.roomStartTimes.get(roomId);
+ }
+
+ public startGameLoop(
+ roomId: string,
+ playerIds: string[],
+ onTick: (data: TickData) => void,
+ onGameEnd: () => void
+ ) {
+ if (this.gameLoops.has(roomId)) {
+ console.log("[GameManager] startGameLoop ignored (already running)", { roomId });
+ return;
+ }
+
+ const tickRate = config.GAME_CONFIG.PLAYER_POSITION_UPDATE_MS;
+ this.roomStartTimes.set(roomId, Date.now());
+
+ const loop = new GameLoop(
+ roomId,
+ tickRate,
+ playerIds,
+ this.players,
+ this.mapStore,
+ onTick,
+ () => {
+ this.roomStartTimes.delete(roomId);
+ this.gameLoops.delete(roomId);
+ onGameEnd();
+ }
+ );
+
+ loop.start();
+ this.gameLoops.set(roomId, loop);
+ console.log("[GameManager] game loop started", { roomId, playerCount: playerIds.length });
+ }
+
+ public stopGameLoop(roomId: string) {
+ const loop = this.gameLoops.get(roomId);
+ if (loop) {
+ loop.stop();
+ this.gameLoops.delete(roomId);
+ this.roomStartTimes.delete(roomId);
+ console.log("[GameManager] game loop stopped", { roomId });
+ } else {
+ console.log("[GameManager] stopGameLoop ignored (not running)", { roomId });
+ }
+ }
+
+ public paintAndGetUpdates(playerId: string): gridMapTypes.CellUpdate[] {
+ const player = this.players.get(playerId);
+ if (!player) return [];
+
+ const gridIndex = gridMapLogic.getGridIndexFromPosition(player.x, player.y);
+ if (gridIndex !== null) {
+ this.mapStore.paintCell(gridIndex, player.teamId);
+ }
+
+ return this.mapStore.getAndClearUpdates();
+ }
+}
diff --git a/apps/server/src/domains/game/application/services/PlayerRegistry.ts b/apps/server/src/domains/game/application/services/PlayerRegistry.ts
new file mode 100644
index 0000000..5233ce4
--- /dev/null
+++ b/apps/server/src/domains/game/application/services/PlayerRegistry.ts
@@ -0,0 +1,55 @@
+import { config } from "@repo/shared";
+import { Player } from "../../entities/Player.js";
+
+export class PlayerRegistry {
+ private players: Map;
+
+ constructor() {
+ this.players = new Map();
+ }
+
+ public addPlayer(id: string): Player {
+ const player = new Player(id);
+ player.x = config.GAME_CONFIG.GRID_COLS / 2;
+ player.y = config.GAME_CONFIG.GRID_ROWS / 2;
+ this.players.set(id, player);
+ console.log("[GameManager] player added", { playerId: id, totalPlayers: this.players.size });
+ return player;
+ }
+
+ public removePlayer(id: string) {
+ const existed = this.players.delete(id);
+ if (existed) {
+ console.log("[GameManager] player removed", { playerId: id, totalPlayers: this.players.size });
+ } else {
+ console.log("[GameManager] player remove ignored (not found)", { playerId: id });
+ }
+ }
+
+ public getPlayer(id: string): Player | undefined {
+ return this.players.get(id);
+ }
+
+ public movePlayer(id: string, x: number, y: number) {
+ const player = this.players.get(id);
+ if (player) {
+ console.log(`Move Request -> ID:${id.slice(0, 4)} x:${Math.round(x)} y:${Math.round(y)}`);
+ if (typeof x !== "number" || typeof y !== "number" || isNaN(x) || isNaN(y)) {
+ console.log("⚠️ 無効なデータなので無視しました");
+ return;
+ }
+ player.x = x;
+ player.y = y;
+ } else {
+ console.log("[GameManager] move ignored (player not found)", { playerId: id });
+ }
+ }
+
+ public getAllPlayers(): Player[] {
+ return Array.from(this.players.values());
+ }
+
+ public getPlayersRef(): Map {
+ return this.players;
+ }
+}
diff --git a/apps/server/src/domains/game/application/useCases/disconnectUseCase.ts b/apps/server/src/domains/game/application/useCases/disconnectUseCase.ts
new file mode 100644
index 0000000..1db69d0
--- /dev/null
+++ b/apps/server/src/domains/game/application/useCases/disconnectUseCase.ts
@@ -0,0 +1,20 @@
+import { protocol } from "@repo/shared";
+import type { DisconnectPlayerPort } from "../ports/gameUseCasePorts";
+
+type EmitToAll = (event: string, payload?: unknown) => void;
+
+type DisconnectUseCaseParams = {
+ gameManager: DisconnectPlayerPort;
+ playerId: string;
+ emitToAll: EmitToAll;
+};
+
+export const disconnectUseCase = ({
+ gameManager,
+ playerId,
+ emitToAll,
+}: DisconnectUseCaseParams) => {
+ gameManager.removePlayer(playerId);
+ emitToAll(protocol.SocketEvents.REMOVE_PLAYER, playerId);
+ console.log("[GameHandler] player removed", { playerId });
+};
diff --git a/apps/server/src/domains/game/application/useCases/movePlayerUseCase.ts b/apps/server/src/domains/game/application/useCases/movePlayerUseCase.ts
new file mode 100644
index 0000000..9bcece1
--- /dev/null
+++ b/apps/server/src/domains/game/application/useCases/movePlayerUseCase.ts
@@ -0,0 +1,16 @@
+import type { playerTypes } from "@repo/shared";
+import type { MovePlayerPort } from "../ports/gameUseCasePorts";
+
+type MovePlayerUseCaseParams = {
+ gameManager: MovePlayerPort;
+ playerId: string;
+ move: playerTypes.MovePayload;
+};
+
+export const movePlayerUseCase = ({
+ gameManager,
+ playerId,
+ move,
+}: MovePlayerUseCaseParams) => {
+ gameManager.movePlayer(playerId, move.x, move.y);
+};
diff --git a/apps/server/src/domains/game/application/useCases/pingUseCase.ts b/apps/server/src/domains/game/application/useCases/pingUseCase.ts
new file mode 100644
index 0000000..0ef9f54
--- /dev/null
+++ b/apps/server/src/domains/game/application/useCases/pingUseCase.ts
@@ -0,0 +1,18 @@
+import { protocol } from "@repo/shared";
+
+type EmitToSocket = (event: string, payload?: unknown) => void;
+
+type PingUseCaseParams = {
+ clientTime: number;
+ emitToSocket: EmitToSocket;
+};
+
+export const pingUseCase = ({
+ clientTime,
+ emitToSocket,
+}: PingUseCaseParams) => {
+ emitToSocket(protocol.SocketEvents.PONG, {
+ clientTime,
+ serverTime: Date.now(),
+ });
+};
diff --git a/apps/server/src/domains/game/application/useCases/readyForGameUseCase.ts b/apps/server/src/domains/game/application/useCases/readyForGameUseCase.ts
new file mode 100644
index 0000000..92ab796
--- /dev/null
+++ b/apps/server/src/domains/game/application/useCases/readyForGameUseCase.ts
@@ -0,0 +1,43 @@
+import { protocol } from "@repo/shared";
+import type { ReadyForGamePort } from "../ports/gameUseCasePorts";
+
+type EmitToSocket = (event: string, payload?: unknown) => void;
+
+type ReadyForGameUseCaseParams = {
+ socketId: string;
+ roomId?: string;
+ gameManager: ReadyForGamePort;
+ emitToSocket: EmitToSocket;
+};
+
+export const readyForGameUseCase = ({
+ socketId,
+ roomId,
+ gameManager,
+ emitToSocket,
+}: ReadyForGameUseCaseParams) => {
+ const allPlayers = gameManager.getAllPlayers();
+ emitToSocket(protocol.SocketEvents.CURRENT_PLAYERS, allPlayers);
+
+ console.log("[GameHandler] READY_FOR_GAME received", {
+ socketId,
+ totalPlayers: allPlayers.length,
+ });
+
+ if (!roomId) {
+ console.log("[GameHandler] READY_FOR_GAME missing roomId", { socketId });
+ return;
+ }
+
+ const startTime = gameManager.getRoomStartTime(roomId);
+ if (!startTime) {
+ return;
+ }
+
+ emitToSocket(protocol.SocketEvents.GAME_START, { startTime });
+ console.log("[GameHandler] GAME_START sent to ready client", {
+ socketId,
+ roomId,
+ startTime,
+ });
+};
diff --git a/apps/server/src/domains/game/application/useCases/startGameUseCase.ts b/apps/server/src/domains/game/application/useCases/startGameUseCase.ts
new file mode 100644
index 0000000..41b2772
--- /dev/null
+++ b/apps/server/src/domains/game/application/useCases/startGameUseCase.ts
@@ -0,0 +1,66 @@
+import { protocol, roomConsts } from "@repo/shared";
+import { RoomManager } from "@server/domains/room/RoomManager";
+import type { StartGamePort } from "../ports/gameUseCasePorts";
+
+type EmitToRoom = (roomId: string, event: string, payload?: unknown) => void;
+
+type StartGameUseCaseParams = {
+ ownerId: string;
+ gameManager: StartGamePort;
+ roomManager: RoomManager;
+ emitToRoom: EmitToRoom;
+};
+
+export const startGameUseCase = ({
+ ownerId,
+ gameManager,
+ roomManager,
+ emitToRoom,
+}: StartGameUseCaseParams) => {
+ const room = roomManager.getRoomByOwnerId(ownerId);
+ if (!room) {
+ console.log("[GameHandler] START_GAME ignored (no room)", { socketId: ownerId });
+ return;
+ }
+
+ if (room.status === roomConsts.RoomPhase.PLAYING) {
+ console.log("[GameHandler] START_GAME ignored (already playing)", { roomId: room.roomId });
+ return;
+ }
+
+ console.log("[GameHandler] START_GAME accepted", {
+ roomId: room.roomId,
+ ownerId,
+ totalPlayers: room.players.length,
+ });
+
+ room.status = roomConsts.RoomPhase.PLAYING;
+
+ const playerIds = room.players.map((p: { id: string }) => p.id);
+
+ room.players.forEach((p: { id: string }) => {
+ gameManager.addPlayer(p.id);
+ });
+
+ gameManager.startGameLoop(
+ room.roomId,
+ playerIds,
+ (tickData) => {
+ tickData.players.forEach((playerData) => {
+ emitToRoom(room.roomId, protocol.SocketEvents.UPDATE_PLAYER, playerData);
+ });
+
+ if (tickData.cellUpdates.length > 0) {
+ emitToRoom(room.roomId, protocol.SocketEvents.UPDATE_MAP_CELLS, tickData.cellUpdates);
+ }
+ },
+ () => {
+ console.log(`[GameHandler] ルーム ${room.roomId} のゲームが終了しました (3分経過)`);
+ emitToRoom(room.roomId, protocol.SocketEvents.GAME_END);
+ room.status = roomConsts.RoomPhase.WAITING;
+ }
+ );
+
+ const startTime = gameManager.getRoomStartTime(room.roomId) || Date.now();
+ emitToRoom(room.roomId, protocol.SocketEvents.GAME_START, { startTime });
+};
diff --git a/apps/server/src/domains/game/handlers/onDisconnect.ts b/apps/server/src/domains/game/handlers/onDisconnect.ts
new file mode 100644
index 0000000..5555397
--- /dev/null
+++ b/apps/server/src/domains/game/handlers/onDisconnect.ts
@@ -0,0 +1,22 @@
+import { Server } from "socket.io";
+import { GameManager } from "@server/domains/game/GameManager";
+import { disconnectUseCase } from "@server/domains/game/application/useCases/disconnectUseCase";
+
+export const onDisconnect = (
+ io: Server,
+ gameManager: GameManager,
+ playerId: string
+) => {
+ disconnectUseCase({
+ gameManager,
+ playerId,
+ emitToAll: (event, payload) => {
+ if (payload === undefined) {
+ io.emit(event);
+ return;
+ }
+
+ io.emit(event, payload);
+ },
+ });
+};
diff --git a/apps/server/src/domains/game/handlers/onMove.ts b/apps/server/src/domains/game/handlers/onMove.ts
new file mode 100644
index 0000000..b07d713
--- /dev/null
+++ b/apps/server/src/domains/game/handlers/onMove.ts
@@ -0,0 +1,15 @@
+import { GameManager } from "@server/domains/game/GameManager";
+import type { playerTypes } from "@repo/shared";
+import { movePlayerUseCase } from "@server/domains/game/application/useCases/movePlayerUseCase";
+
+export const onMove = (
+ gameManager: GameManager,
+ playerId: string,
+ data: playerTypes.MovePayload
+) => {
+ movePlayerUseCase({
+ gameManager,
+ playerId,
+ move: data,
+ });
+};
diff --git a/apps/server/src/domains/game/handlers/onPing.ts b/apps/server/src/domains/game/handlers/onPing.ts
new file mode 100644
index 0000000..99c8f88
--- /dev/null
+++ b/apps/server/src/domains/game/handlers/onPing.ts
@@ -0,0 +1,16 @@
+import { Socket } from "socket.io";
+import { pingUseCase } from "@server/domains/game/application/useCases/pingUseCase";
+
+export const onPing = (socket: Socket, clientTime: number) => {
+ pingUseCase({
+ clientTime,
+ emitToSocket: (event, payload) => {
+ if (payload === undefined) {
+ socket.emit(event);
+ return;
+ }
+
+ socket.emit(event, payload);
+ },
+ });
+};
diff --git a/apps/server/src/domains/game/handlers/onReadyForGame.ts b/apps/server/src/domains/game/handlers/onReadyForGame.ts
new file mode 100644
index 0000000..6bece4f
--- /dev/null
+++ b/apps/server/src/domains/game/handlers/onReadyForGame.ts
@@ -0,0 +1,24 @@
+import { Socket } from "socket.io";
+import { GameManager } from "@server/domains/game/GameManager";
+import { readyForGameUseCase } from "@server/domains/game/application/useCases/readyForGameUseCase";
+
+export const onReadyForGame = (
+ socket: Socket,
+ gameManager: GameManager
+) => {
+ const roomId = Array.from(socket.rooms).find((room) => room !== socket.id);
+
+ readyForGameUseCase({
+ socketId: socket.id,
+ roomId,
+ gameManager,
+ emitToSocket: (event, payload) => {
+ if (payload === undefined) {
+ socket.emit(event);
+ return;
+ }
+
+ socket.emit(event, payload);
+ },
+ });
+};
diff --git a/apps/server/src/domains/game/handlers/onStartGame.ts b/apps/server/src/domains/game/handlers/onStartGame.ts
new file mode 100644
index 0000000..528caaa
--- /dev/null
+++ b/apps/server/src/domains/game/handlers/onStartGame.ts
@@ -0,0 +1,25 @@
+import { Server } from "socket.io";
+import { GameManager } from "@server/domains/game/GameManager";
+import { RoomManager } from "@server/domains/room/RoomManager";
+import { startGameUseCase } from "@server/domains/game/application/useCases/startGameUseCase";
+
+export const onStartGame = (
+ io: Server,
+ gameManager: GameManager,
+ roomManager: RoomManager,
+ ownerId: string
+) => {
+ startGameUseCase({
+ ownerId,
+ gameManager,
+ roomManager,
+ emitToRoom: (roomId, event, payload) => {
+ if (payload === undefined) {
+ io.to(roomId).emit(event);
+ return;
+ }
+
+ io.to(roomId).emit(event, payload);
+ },
+ });
+};
diff --git a/apps/server/src/domains/room/RoomHandler.ts b/apps/server/src/domains/room/RoomHandler.ts
index 91f4dec..756cb63 100644
--- a/apps/server/src/domains/room/RoomHandler.ts
+++ b/apps/server/src/domains/room/RoomHandler.ts
@@ -2,24 +2,28 @@
import { RoomManager } from "./RoomManager";
import { protocol } from "@repo/shared";
import type { roomTypes } from "@repo/shared";
+import { joinRoomUseCase } from "./application/useCases/joinRoomUseCase";
+import { roomDisconnectUseCase } from "./application/useCases/roomDisconnectUseCase";
export const registerRoomHandlers = (io: Server, socket: Socket, roomManager: RoomManager) => {
socket.on(protocol.SocketEvents.JOIN_ROOM, (data: roomTypes.JoinRoomPayload) => {
- const { roomId, playerName } = data;
- console.log("[RoomHandler] JOIN_ROOM received", { roomId, socketId: socket.id, playerName });
+ const { roomId } = data;
socket.join(roomId);
- // RoomManagerにデータ操作を依頼
- const room = roomManager.addPlayerToRoom(roomId, socket.id, playerName);
+ joinRoomUseCase({
+ roomManager,
+ socketId: socket.id,
+ data,
+ emitToRoom: (targetRoomId, event, payload) => {
+ if (payload === undefined) {
+ io.to(targetRoomId).emit(event);
+ return;
+ }
- // ルーム内全員向け最新状態配信
- io.to(roomId).emit(protocol.SocketEvents.ROOM_UPDATE, room);
- console.log("[RoomHandler] ROOM_UPDATE emitted", {
- roomId,
- ownerId: room.ownerId,
- totalPlayers: room.players.length
+ io.to(targetRoomId).emit(event, payload);
+ },
});
});
@@ -29,20 +33,16 @@
* 切断時のルームクリーンアップ処理
*/
export const handleRoomDisconnect = (io: Server, socket: Socket, roomManager: RoomManager) => {
- // ルームからの除外処理
- const updatedRooms = roomManager.removePlayer(socket.id);
- console.log("[RoomHandler] disconnect cleanup", {
+ roomDisconnectUseCase({
+ roomManager,
socketId: socket.id,
- updatedRoomCount: updatedRooms.length
- });
-
- // 更新があったルーム(オーナー変更など)にのみ通知を飛ばす
- updatedRooms.forEach(room => {
- io.to(room.roomId).emit(protocol.SocketEvents.ROOM_UPDATE, room);
- console.log("[RoomHandler] ROOM_UPDATE emitted", {
- roomId: room.roomId,
- ownerId: room.ownerId,
- totalPlayers: room.players.length
- });
+ emitToRoom: (roomId, event, payload) => {
+ if (payload === undefined) {
+ io.to(roomId).emit(event);
+ return;
+ }
+
+ io.to(roomId).emit(event, payload);
+ },
});
};
\ No newline at end of file
diff --git a/apps/server/src/domains/room/application/ports/roomUseCasePorts.ts b/apps/server/src/domains/room/application/ports/roomUseCasePorts.ts
new file mode 100644
index 0000000..37d7416
--- /dev/null
+++ b/apps/server/src/domains/room/application/ports/roomUseCasePorts.ts
@@ -0,0 +1,9 @@
+import type { roomTypes } from "@repo/shared";
+
+export interface JoinRoomPort {
+ addPlayerToRoom(roomId: string, socketId: string, playerName: string): roomTypes.Room;
+}
+
+export interface DisconnectRoomPort {
+ removePlayer(socketId: string): roomTypes.Room[];
+}
diff --git a/apps/server/src/domains/room/application/useCases/joinRoomUseCase.ts b/apps/server/src/domains/room/application/useCases/joinRoomUseCase.ts
new file mode 100644
index 0000000..2123b35
--- /dev/null
+++ b/apps/server/src/domains/room/application/useCases/joinRoomUseCase.ts
@@ -0,0 +1,31 @@
+import { protocol } from "@repo/shared";
+import type { roomTypes } from "@repo/shared";
+import type { JoinRoomPort } from "../ports/roomUseCasePorts";
+
+type EmitToRoom = (roomId: string, event: string, payload?: unknown) => void;
+
+type JoinRoomUseCaseParams = {
+ roomManager: JoinRoomPort;
+ socketId: string;
+ data: roomTypes.JoinRoomPayload;
+ emitToRoom: EmitToRoom;
+};
+
+export const joinRoomUseCase = ({
+ roomManager,
+ socketId,
+ data,
+ emitToRoom,
+}: JoinRoomUseCaseParams) => {
+ const { roomId, playerName } = data;
+ console.log("[RoomHandler] JOIN_ROOM received", { roomId, socketId, playerName });
+
+ const room = roomManager.addPlayerToRoom(roomId, socketId, playerName);
+
+ emitToRoom(roomId, protocol.SocketEvents.ROOM_UPDATE, room);
+ console.log("[RoomHandler] ROOM_UPDATE emitted", {
+ roomId,
+ ownerId: room.ownerId,
+ totalPlayers: room.players.length,
+ });
+};
diff --git a/apps/server/src/domains/room/application/useCases/roomDisconnectUseCase.ts b/apps/server/src/domains/room/application/useCases/roomDisconnectUseCase.ts
new file mode 100644
index 0000000..be33326
--- /dev/null
+++ b/apps/server/src/domains/room/application/useCases/roomDisconnectUseCase.ts
@@ -0,0 +1,31 @@
+import { protocol } from "@repo/shared";
+import type { DisconnectRoomPort } from "../ports/roomUseCasePorts";
+
+type EmitToRoom = (roomId: string, event: string, payload?: unknown) => void;
+
+type RoomDisconnectUseCaseParams = {
+ roomManager: DisconnectRoomPort;
+ socketId: string;
+ emitToRoom: EmitToRoom;
+};
+
+export const roomDisconnectUseCase = ({
+ roomManager,
+ socketId,
+ emitToRoom,
+}: RoomDisconnectUseCaseParams) => {
+ const updatedRooms = roomManager.removePlayer(socketId);
+ console.log("[RoomHandler] disconnect cleanup", {
+ socketId,
+ updatedRoomCount: updatedRooms.length,
+ });
+
+ updatedRooms.forEach((room) => {
+ emitToRoom(room.roomId, protocol.SocketEvents.ROOM_UPDATE, room);
+ console.log("[RoomHandler] ROOM_UPDATE emitted", {
+ roomId: room.roomId,
+ ownerId: room.ownerId,
+ totalPlayers: room.players.length,
+ });
+ });
+};
diff --git a/apps/server/src/network/SocketManager.ts b/apps/server/src/network/SocketManager.ts
index 0aa661c..01bff7d 100644
--- a/apps/server/src/network/SocketManager.ts
+++ b/apps/server/src/network/SocketManager.ts
@@ -1,9 +1,9 @@
import { Server, Socket } from "socket.io";
-import { GameManager } from "../domains/game/GameManager";
-import { RoomManager } from "../domains/room/RoomManager";
+import { GameManager } from "@server/domains/game/GameManager";
+import { RoomManager } from "@server/domains/room/RoomManager";
import { protocol } from "@repo/shared";
-import { registerRoomHandlers, handleRoomDisconnect } from "../domains/room/RoomHandler";
-import { registerGameHandlers, handleGameDisconnect } from "../domains/game/GameHandler";
+import { registerRoomHandlers, handleRoomDisconnect } from "@server/domains/room/RoomHandler";
+import { registerGameHandlers, handleGameDisconnect } from "@server/domains/game/GameHandler";
export class SocketManager {
private io: Server;
diff --git a/apps/server/tsconfig.json b/apps/server/tsconfig.json
index 26213dc..0ecadc8 100644
--- a/apps/server/tsconfig.json
+++ b/apps/server/tsconfig.json
@@ -10,8 +10,10 @@
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
- "baseUrl": "."
- /* "paths" は削除します(pnpm のワークスペース解決を使用するため) */
+ "baseUrl": ".",
+ "paths": {
+ "@server/*": ["src/*"]
+ }
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 94b00f1..37621b8 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -72,6 +72,15 @@
'@types/socket.io':
specifier: ^3.0.2
version: 3.0.2
+ '@typescript-eslint/parser':
+ specifier: ^8.56.1
+ version: 8.56.1(eslint@10.0.2)(typescript@5.9.3)
+ eslint:
+ specifier: ^10.0.2
+ version: 10.0.2
+ tsc-alias:
+ specifier: ^1.8.16
+ version: 1.8.16
tsx:
specifier: ^4.21.0
version: 4.21.0
@@ -421,6 +430,18 @@
'@jridgewell/trace-mapping@0.3.9':
resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==}
+ '@nodelib/fs.scandir@2.1.5':
+ resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
+ engines: {node: '>= 8'}
+
+ '@nodelib/fs.stat@2.0.5':
+ resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
+ engines: {node: '>= 8'}
+
+ '@nodelib/fs.walk@1.2.8':
+ resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
+ engines: {node: '>= 8'}
+
'@pixi/app@7.4.3':
resolution: {integrity: sha512-opyWMuO0Ir8pf1DYUR++wAA6ZfNU+nIX2z95R2OD172HbcdhB4/HD7leLIIAny/LciEdMqlWEBhXK7N93YWbdg==}
peerDependencies:
@@ -840,9 +861,17 @@
any-promise@1.3.0:
resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==}
+ anymatch@3.1.3:
+ resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
+ engines: {node: '>= 8'}
+
arg@4.1.3:
resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==}
+ array-union@2.1.0:
+ resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
+ engines: {node: '>=8'}
+
balanced-match@4.0.4:
resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==}
engines: {node: 18 || 20 || >=22}
@@ -855,10 +884,18 @@
resolution: {integrity: sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==}
hasBin: true
+ binary-extensions@2.3.0:
+ resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
+ engines: {node: '>=8'}
+
brace-expansion@5.0.3:
resolution: {integrity: sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==}
engines: {node: 18 || 20 || >=22}
+ braces@3.0.3:
+ resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
+ engines: {node: '>=8'}
+
browserslist@4.28.1:
resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==}
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
@@ -885,6 +922,10 @@
caniuse-lite@1.0.30001769:
resolution: {integrity: sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg==}
+ chokidar@3.6.0:
+ resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
+ engines: {node: '>= 8.10.0'}
+
chokidar@4.0.3:
resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==}
engines: {node: '>= 14.16.0'}
@@ -893,6 +934,10 @@
resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==}
engines: {node: '>= 6'}
+ commander@9.5.0:
+ resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==}
+ engines: {node: ^12.20.0 || >=14}
+
confbox@0.1.8:
resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==}
@@ -937,6 +982,10 @@
resolution: {integrity: sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==}
engines: {node: '>=0.3.1'}
+ dir-glob@3.0.1:
+ resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
+ engines: {node: '>=8'}
+
dunder-proto@1.0.1:
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
engines: {node: '>= 0.4'}
@@ -1037,12 +1086,19 @@
fast-deep-equal@3.1.3:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
+ fast-glob@3.3.3:
+ resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==}
+ engines: {node: '>=8.6.0'}
+
fast-json-stable-stringify@2.1.0:
resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
fast-levenshtein@2.0.6:
resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
+ fastq@1.20.1:
+ resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==}
+
fdir@6.5.0:
resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
engines: {node: '>=12.0.0'}
@@ -1056,6 +1112,10 @@
resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==}
engines: {node: '>=16.0.0'}
+ fill-range@7.1.1:
+ resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
+ engines: {node: '>=8'}
+
find-up@5.0.0:
resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
engines: {node: '>=10'}
@@ -1096,10 +1156,18 @@
gifuct-js@2.1.2:
resolution: {integrity: sha512-rI2asw77u0mGgwhV3qA+OEgYqaDn5UNqgs+Bx0FGwSpuqfYn+Ir6RQY5ENNQ8SbIiG/m5gVa7CD5RriO4f4Lsg==}
+ glob-parent@5.1.2:
+ resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
+ engines: {node: '>= 6'}
+
glob-parent@6.0.2:
resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
engines: {node: '>=10.13.0'}
+ globby@11.1.0:
+ resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==}
+ engines: {node: '>=10'}
+
gopd@1.2.0:
resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
engines: {node: '>= 0.4'}
@@ -1120,6 +1188,10 @@
resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
engines: {node: '>=0.8.19'}
+ is-binary-path@2.1.0:
+ resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
+ engines: {node: '>=8'}
+
is-extglob@2.1.1:
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
engines: {node: '>=0.10.0'}
@@ -1128,6 +1200,10 @@
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
engines: {node: '>=0.10.0'}
+ is-number@7.0.0:
+ resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
+ engines: {node: '>=0.12.0'}
+
isexe@2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
@@ -1208,6 +1284,14 @@
resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
engines: {node: '>= 0.4'}
+ merge2@1.4.1:
+ resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
+ engines: {node: '>= 8'}
+
+ micromatch@4.0.8:
+ resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
+ engines: {node: '>=8.6'}
+
mime-db@1.52.0:
resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
engines: {node: '>= 0.6'}
@@ -1226,6 +1310,10 @@
ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
+ mylas@2.1.14:
+ resolution: {integrity: sha512-BzQguy9W9NJgoVn2mRWzbFrFWWztGCcng2QI9+41frfk+Athwgx3qhqhvStz7ExeUUu7Kzw427sNzHpEZNINog==}
+ engines: {node: '>=16.0.0'}
+
mz@2.7.0:
resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
@@ -1244,6 +1332,10 @@
node-releases@2.0.27:
resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==}
+ normalize-path@3.0.0:
+ resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
+ engines: {node: '>=0.10.0'}
+
object-assign@4.1.1:
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
engines: {node: '>=0.10.0'}
@@ -1275,6 +1367,10 @@
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
engines: {node: '>=8'}
+ path-type@4.0.0:
+ resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
+ engines: {node: '>=8'}
+
pathe@2.0.3:
resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
@@ -1284,6 +1380,10 @@
picocolors@1.1.1:
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
+ picomatch@2.3.1:
+ resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
+ engines: {node: '>=8.6'}
+
picomatch@4.0.3:
resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==}
engines: {node: '>=12'}
@@ -1298,6 +1398,10 @@
pkg-types@1.3.1:
resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==}
+ plimit-lit@1.6.1:
+ resolution: {integrity: sha512-B7+VDyb8Tl6oMJT9oSO2CW8XC/T4UcJGrwOVoNGwOQsQYhlpfajmrMj5xeejqaASq3V/EqThyOeATEOMuSEXiA==}
+ engines: {node: '>=12'}
+
postcss-load-config@6.0.1:
resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==}
engines: {node: '>= 18'}
@@ -1338,6 +1442,13 @@
resolution: {integrity: sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==}
engines: {node: '>=0.6'}
+ queue-lit@1.5.2:
+ resolution: {integrity: sha512-tLc36IOPeMAubu8BkW8YDBV+WyIgKlYU7zUNs0J5Vk9skSZ4JfGlPOqplP0aHdfv7HL0B2Pg6nwiq60Qc6M2Hw==}
+ engines: {node: '>=12'}
+
+ queue-microtask@1.2.3:
+ resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
+
react-dom@18.3.1:
resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==}
peerDependencies:
@@ -1360,6 +1471,10 @@
resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==}
engines: {node: '>=0.10.0'}
+ readdirp@3.6.0:
+ resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
+ engines: {node: '>=8.10.0'}
+
readdirp@4.1.2:
resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==}
engines: {node: '>= 14.18.0'}
@@ -1371,11 +1486,18 @@
resolve-pkg-maps@1.0.0:
resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
+ reusify@1.1.0:
+ resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==}
+ engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
+
rollup@4.57.1:
resolution: {integrity: sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==}
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
hasBin: true
+ run-parallel@1.2.0:
+ resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
+
scheduler@0.23.2:
resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==}
@@ -1412,6 +1534,10 @@
resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==}
engines: {node: '>= 0.4'}
+ slash@3.0.0:
+ resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
+ engines: {node: '>=8'}
+
socket.io-adapter@2.5.6:
resolution: {integrity: sha512-DkkO/dz7MGln0dHn5bmN3pPy+JmywNICWrJqVWiVOyvXjWQFIv9c2h24JrQLLFJ2aQVQf/Cvl1vblnd4r2apLQ==}
@@ -1458,6 +1584,10 @@
resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==}
engines: {node: '>=12.0.0'}
+ to-regex-range@5.0.1:
+ resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
+ engines: {node: '>=8.0'}
+
tree-kill@1.2.2:
resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==}
hasBin: true
@@ -1485,6 +1615,11 @@
'@swc/wasm':
optional: true
+ tsc-alias@1.8.16:
+ resolution: {integrity: sha512-QjCyu55NFyRSBAl6+MTFwplpFcnm2Pq01rR/uxfqJoLMm6X3O14KEGtaSDZpJYaE1bJBGDjD0eSuiIWPe2T58g==}
+ engines: {node: '>=16.20.2'}
+ hasBin: true
+
tsup@8.5.1:
resolution: {integrity: sha512-xtgkqwdhpKWr3tKPmCkvYmS9xnQK3m3XgxZHwSUjvfTjp7YfXe5tT3GgWi0F2N+ZSMsOeWeZFh7ZZFg5iPhing==}
engines: {node: '>=18'}
@@ -1886,6 +2021,18 @@
'@jridgewell/resolve-uri': 3.1.2
'@jridgewell/sourcemap-codec': 1.5.5
+ '@nodelib/fs.scandir@2.1.5':
+ dependencies:
+ '@nodelib/fs.stat': 2.0.5
+ run-parallel: 1.2.0
+
+ '@nodelib/fs.stat@2.0.5': {}
+
+ '@nodelib/fs.walk@1.2.8':
+ dependencies:
+ '@nodelib/fs.scandir': 2.1.5
+ fastq: 1.20.1
+
'@pixi/app@7.4.3(@pixi/core@7.4.3)(@pixi/display@7.4.3(@pixi/core@7.4.3))':
dependencies:
'@pixi/core': 7.4.3
@@ -2269,18 +2416,31 @@
any-promise@1.3.0: {}
+ anymatch@3.1.3:
+ dependencies:
+ normalize-path: 3.0.0
+ picomatch: 2.3.1
+
arg@4.1.3: {}
+ array-union@2.1.0: {}
+
balanced-match@4.0.4: {}
base64id@2.0.0: {}
baseline-browser-mapping@2.9.19: {}
+ binary-extensions@2.3.0: {}
+
brace-expansion@5.0.3:
dependencies:
balanced-match: 4.0.4
+ braces@3.0.3:
+ dependencies:
+ fill-range: 7.1.1
+
browserslist@4.28.1:
dependencies:
baseline-browser-mapping: 2.9.19
@@ -2308,12 +2468,26 @@
caniuse-lite@1.0.30001769: {}
+ chokidar@3.6.0:
+ dependencies:
+ anymatch: 3.1.3
+ braces: 3.0.3
+ glob-parent: 5.1.2
+ is-binary-path: 2.1.0
+ is-glob: 4.0.3
+ normalize-path: 3.0.0
+ readdirp: 3.6.0
+ optionalDependencies:
+ fsevents: 2.3.3
+
chokidar@4.0.3:
dependencies:
readdirp: 4.1.2
commander@4.1.1: {}
+ commander@9.5.0: {}
+
confbox@0.1.8: {}
consola@3.4.2: {}
@@ -2345,6 +2519,10 @@
diff@4.0.4: {}
+ dir-glob@3.0.1:
+ dependencies:
+ path-type: 4.0.0
+
dunder-proto@1.0.1:
dependencies:
call-bind-apply-helpers: 1.0.2
@@ -2498,10 +2676,22 @@
fast-deep-equal@3.1.3: {}
+ fast-glob@3.3.3:
+ dependencies:
+ '@nodelib/fs.stat': 2.0.5
+ '@nodelib/fs.walk': 1.2.8
+ glob-parent: 5.1.2
+ merge2: 1.4.1
+ micromatch: 4.0.8
+
fast-json-stable-stringify@2.1.0: {}
fast-levenshtein@2.0.6: {}
+ fastq@1.20.1:
+ dependencies:
+ reusify: 1.1.0
+
fdir@6.5.0(picomatch@4.0.3):
optionalDependencies:
picomatch: 4.0.3
@@ -2510,6 +2700,10 @@
dependencies:
flat-cache: 4.0.1
+ fill-range@7.1.1:
+ dependencies:
+ to-regex-range: 5.0.1
+
find-up@5.0.0:
dependencies:
locate-path: 6.0.0
@@ -2561,10 +2755,23 @@
dependencies:
js-binary-schema-parser: 2.0.3
+ glob-parent@5.1.2:
+ dependencies:
+ is-glob: 4.0.3
+
glob-parent@6.0.2:
dependencies:
is-glob: 4.0.3
+ globby@11.1.0:
+ dependencies:
+ array-union: 2.1.0
+ dir-glob: 3.0.1
+ fast-glob: 3.3.3
+ ignore: 5.3.2
+ merge2: 1.4.1
+ slash: 3.0.0
+
gopd@1.2.0: {}
has-symbols@1.1.0: {}
@@ -2577,12 +2784,18 @@
imurmurhash@0.1.4: {}
+ is-binary-path@2.1.0:
+ dependencies:
+ binary-extensions: 2.3.0
+
is-extglob@2.1.1: {}
is-glob@4.0.3:
dependencies:
is-extglob: 2.1.1
+ is-number@7.0.0: {}
+
isexe@2.0.0: {}
ismobilejs@1.1.1: {}
@@ -2642,6 +2855,13 @@
math-intrinsics@1.1.0: {}
+ merge2@1.4.1: {}
+
+ micromatch@4.0.8:
+ dependencies:
+ braces: 3.0.3
+ picomatch: 2.3.1
+
mime-db@1.52.0: {}
mime-types@2.1.35:
@@ -2661,6 +2881,8 @@
ms@2.1.3: {}
+ mylas@2.1.14: {}
+
mz@2.7.0:
dependencies:
any-promise: 1.3.0
@@ -2675,6 +2897,8 @@
node-releases@2.0.27: {}
+ normalize-path@3.0.0: {}
+
object-assign@4.1.1: {}
object-inspect@1.13.4: {}
@@ -2702,12 +2926,16 @@
path-key@3.1.1: {}
+ path-type@4.0.0: {}
+
pathe@2.0.3: {}
performance-now@2.1.0: {}
picocolors@1.1.1: {}
+ picomatch@2.3.1: {}
+
picomatch@4.0.3: {}
pirates@4.0.7: {}
@@ -2731,6 +2959,10 @@
mlly: 1.8.0
pathe: 2.0.3
+ plimit-lit@1.6.1:
+ dependencies:
+ queue-lit: 1.5.2
+
postcss-load-config@6.0.1(postcss@8.5.6)(tsx@4.21.0):
dependencies:
lilconfig: 3.1.3
@@ -2760,6 +2992,10 @@
dependencies:
side-channel: 1.1.0
+ queue-lit@1.5.2: {}
+
+ queue-microtask@1.2.3: {}
+
react-dom@18.3.1(react@18.3.1):
dependencies:
loose-envify: 1.4.0
@@ -2779,12 +3015,18 @@
dependencies:
loose-envify: 1.4.0
+ readdirp@3.6.0:
+ dependencies:
+ picomatch: 2.3.1
+
readdirp@4.1.2: {}
resolve-from@5.0.0: {}
resolve-pkg-maps@1.0.0: {}
+ reusify@1.1.0: {}
+
rollup@4.57.1:
dependencies:
'@types/estree': 1.0.8
@@ -2816,6 +3058,10 @@
'@rollup/rollup-win32-x64-msvc': 4.57.1
fsevents: 2.3.3
+ run-parallel@1.2.0:
+ dependencies:
+ queue-microtask: 1.2.3
+
scheduler@0.23.2:
dependencies:
loose-envify: 1.4.0
@@ -2858,6 +3104,8 @@
side-channel-map: 1.0.1
side-channel-weakmap: 1.0.2
+ slash@3.0.0: {}
+
socket.io-adapter@2.5.6:
dependencies:
debug: 4.4.3
@@ -2930,6 +3178,10 @@
fdir: 6.5.0(picomatch@4.0.3)
picomatch: 4.0.3
+ to-regex-range@5.0.1:
+ dependencies:
+ is-number: 7.0.0
+
tree-kill@1.2.2: {}
ts-api-utils@2.4.0(typescript@5.9.3):
@@ -2956,6 +3208,16 @@
v8-compile-cache-lib: 3.0.1
yn: 3.1.1
+ tsc-alias@1.8.16:
+ dependencies:
+ chokidar: 3.6.0
+ commander: 9.5.0
+ get-tsconfig: 4.13.6
+ globby: 11.1.0
+ mylas: 2.1.14
+ normalize-path: 3.0.0
+ plimit-lit: 1.6.1
+
tsup@8.5.1(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3):
dependencies:
bundle-require: 5.1.0(esbuild@0.27.3)