├── metaverse ├── .gitignore ├── .npmrc ├── .vscode │ └── settings.json ├── README.md ├── apps │ ├── frontend │ │ ├── .gitignore │ │ ├── README.md │ │ ├── eslint.config.js │ │ ├── index.html │ │ ├── package-lock.json │ │ ├── package.json │ │ ├── public │ │ │ └── vite.svg │ │ ├── src │ │ │ ├── App.css │ │ │ ├── App.tsx │ │ │ ├── Game.tsx │ │ │ ├── assets │ │ │ │ └── react.svg │ │ │ ├── index.css │ │ │ ├── main.tsx │ │ │ └── vite-env.d.ts │ │ ├── tsconfig.app.json │ │ ├── tsconfig.json │ │ ├── tsconfig.node.json │ │ └── vite.config.ts │ ├── http │ │ ├── package-lock.json │ │ ├── package.json │ │ ├── src │ │ │ ├── config.ts │ │ │ ├── index.ts │ │ │ ├── middleware │ │ │ │ ├── admin.ts │ │ │ │ └── user.ts │ │ │ ├── routes │ │ │ │ └── v1 │ │ │ │ │ ├── admin.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── space.ts │ │ │ │ │ └── user.ts │ │ │ ├── scrypt.ts │ │ │ └── types │ │ │ │ └── index.ts │ │ ├── tsconfig.json │ │ └── tsconfig.tsbuildinfo │ └── ws │ │ ├── package.json │ │ ├── src │ │ ├── RoomManager.ts │ │ ├── User.ts │ │ ├── config.ts │ │ ├── index.ts │ │ └── types.ts │ │ └── tsconfig.json ├── package.json ├── packages │ ├── db │ │ ├── .gitignore │ │ ├── package-lock.json │ │ ├── package.json │ │ ├── prisma │ │ │ ├── migrations │ │ │ │ ├── 20241030155258_init │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20241030164544_made_password_non_unique │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20241030164722_made_avatar_optional │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20241031112104_add_static │ │ │ │ │ └── migration.sql │ │ │ │ ├── 20241031112726_add_thumbnail │ │ │ │ │ └── migration.sql │ │ │ │ └── migration_lock.toml │ │ │ └── schema.prisma │ │ ├── src │ │ │ └── index.ts │ │ ├── tsconfig.json │ │ └── tsconfig.tsbuildinfo │ ├── eslint-config │ │ ├── README.md │ │ ├── library.js │ │ ├── next.js │ │ ├── package.json │ │ └── react-internal.js │ ├── typescript-config │ │ ├── base.json │ │ ├── nextjs.json │ │ ├── package.json │ │ └── react-library.json │ └── ui │ │ ├── .eslintrc.js │ │ ├── package.json │ │ ├── src │ │ ├── button.tsx │ │ ├── card.tsx │ │ └── code.tsx │ │ ├── tsconfig.json │ │ ├── tsconfig.lint.json │ │ └── turbo │ │ └── generators │ │ ├── config.ts │ │ └── templates │ │ └── component.hbs ├── pnpm-lock.yaml ├── pnpm-workspace.yaml └── turbo.json └── tests ├── .gitignore ├── index.test.js ├── package-lock.json └── package.json /metaverse/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # Dependencies 4 | node_modules 5 | .pnp 6 | .pnp.js 7 | 8 | # Local env files 9 | .env 10 | .env.local 11 | .env.development.local 12 | .env.test.local 13 | .env.production.local 14 | 15 | # Testing 16 | coverage 17 | 18 | # Turbo 19 | .turbo 20 | 21 | # Vercel 22 | .vercel 23 | 24 | # Build Outputs 25 | .next/ 26 | out/ 27 | build 28 | dist 29 | 30 | 31 | # Debug 32 | npm-debug.log* 33 | yarn-debug.log* 34 | yarn-error.log* 35 | 36 | # Misc 37 | .DS_Store 38 | *.pem 39 | -------------------------------------------------------------------------------- /metaverse/.npmrc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkirat/2d-metaverse/16c7ab9d40609071d979d75db02e8a2497658273/metaverse/.npmrc -------------------------------------------------------------------------------- /metaverse/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "eslint.workingDirectories": [ 3 | { 4 | "mode": "auto" 5 | } 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /metaverse/README.md: -------------------------------------------------------------------------------- 1 | # Turborepo starter 2 | 3 | This is an official starter Turborepo. 4 | 5 | ## Using this example 6 | 7 | Run the following command: 8 | 9 | ```sh 10 | npx create-turbo@latest 11 | ``` 12 | 13 | ## What's inside? 14 | 15 | This Turborepo includes the following packages/apps: 16 | 17 | ### Apps and Packages 18 | 19 | - `docs`: a [Next.js](https://nextjs.org/) app 20 | - `web`: another [Next.js](https://nextjs.org/) app 21 | - `@repo/ui`: a stub React component library shared by both `web` and `docs` applications 22 | - `@repo/eslint-config`: `eslint` configurations (includes `eslint-config-next` and `eslint-config-prettier`) 23 | - `@repo/typescript-config`: `tsconfig.json`s used throughout the monorepo 24 | 25 | Each package/app is 100% [TypeScript](https://www.typescriptlang.org/). 26 | 27 | ### Utilities 28 | 29 | This Turborepo has some additional tools already setup for you: 30 | 31 | - [TypeScript](https://www.typescriptlang.org/) for static type checking 32 | - [ESLint](https://eslint.org/) for code linting 33 | - [Prettier](https://prettier.io) for code formatting 34 | 35 | ### Build 36 | 37 | To build all apps and packages, run the following command: 38 | 39 | ``` 40 | cd my-turborepo 41 | pnpm build 42 | ``` 43 | 44 | ### Develop 45 | 46 | To develop all apps and packages, run the following command: 47 | 48 | ``` 49 | cd my-turborepo 50 | pnpm dev 51 | ``` 52 | 53 | ### Remote Caching 54 | 55 | Turborepo can use a technique known as [Remote Caching](https://turbo.build/repo/docs/core-concepts/remote-caching) to share cache artifacts across machines, enabling you to share build caches with your team and CI/CD pipelines. 56 | 57 | By default, Turborepo will cache locally. To enable Remote Caching you will need an account with Vercel. If you don't have an account you can [create one](https://vercel.com/signup), then enter the following commands: 58 | 59 | ``` 60 | cd my-turborepo 61 | npx turbo login 62 | ``` 63 | 64 | This will authenticate the Turborepo CLI with your [Vercel account](https://vercel.com/docs/concepts/personal-accounts/overview). 65 | 66 | Next, you can link your Turborepo to your Remote Cache by running the following command from the root of your Turborepo: 67 | 68 | ``` 69 | npx turbo link 70 | ``` 71 | 72 | ## Useful Links 73 | 74 | Learn more about the power of Turborepo: 75 | 76 | - [Tasks](https://turbo.build/repo/docs/core-concepts/monorepos/running-tasks) 77 | - [Caching](https://turbo.build/repo/docs/core-concepts/caching) 78 | - [Remote Caching](https://turbo.build/repo/docs/core-concepts/remote-caching) 79 | - [Filtering](https://turbo.build/repo/docs/core-concepts/monorepos/filtering) 80 | - [Configuration Options](https://turbo.build/repo/docs/reference/configuration) 81 | - [CLI Usage](https://turbo.build/repo/docs/reference/command-line-reference) 82 | -------------------------------------------------------------------------------- /metaverse/apps/frontend/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /metaverse/apps/frontend/README.md: -------------------------------------------------------------------------------- 1 | # React + TypeScript + Vite 2 | 3 | This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. 4 | 5 | Currently, two official plugins are available: 6 | 7 | - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh 8 | - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh 9 | 10 | ## Expanding the ESLint configuration 11 | 12 | If you are developing a production application, we recommend updating the configuration to enable type aware lint rules: 13 | 14 | - Configure the top-level `parserOptions` property like this: 15 | 16 | ```js 17 | export default tseslint.config({ 18 | languageOptions: { 19 | // other options... 20 | parserOptions: { 21 | project: ['./tsconfig.node.json', './tsconfig.app.json'], 22 | tsconfigRootDir: import.meta.dirname, 23 | }, 24 | }, 25 | }) 26 | ``` 27 | 28 | - Replace `tseslint.configs.recommended` to `tseslint.configs.recommendedTypeChecked` or `tseslint.configs.strictTypeChecked` 29 | - Optionally add `...tseslint.configs.stylisticTypeChecked` 30 | - Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and update the config: 31 | 32 | ```js 33 | // eslint.config.js 34 | import react from 'eslint-plugin-react' 35 | 36 | export default tseslint.config({ 37 | // Set the react version 38 | settings: { react: { version: '18.3' } }, 39 | plugins: { 40 | // Add the react plugin 41 | react, 42 | }, 43 | rules: { 44 | // other rules... 45 | // Enable its recommended rules 46 | ...react.configs.recommended.rules, 47 | ...react.configs['jsx-runtime'].rules, 48 | }, 49 | }) 50 | ``` 51 | -------------------------------------------------------------------------------- /metaverse/apps/frontend/eslint.config.js: -------------------------------------------------------------------------------- 1 | import js from '@eslint/js' 2 | import globals from 'globals' 3 | import reactHooks from 'eslint-plugin-react-hooks' 4 | import reactRefresh from 'eslint-plugin-react-refresh' 5 | import tseslint from 'typescript-eslint' 6 | 7 | export default tseslint.config( 8 | { ignores: ['dist'] }, 9 | { 10 | extends: [js.configs.recommended, ...tseslint.configs.recommended], 11 | files: ['**/*.{ts,tsx}'], 12 | languageOptions: { 13 | ecmaVersion: 2020, 14 | globals: globals.browser, 15 | }, 16 | plugins: { 17 | 'react-hooks': reactHooks, 18 | 'react-refresh': reactRefresh, 19 | }, 20 | rules: { 21 | ...reactHooks.configs.recommended.rules, 22 | 'react-refresh/only-export-components': [ 23 | 'warn', 24 | { allowConstantExport: true }, 25 | ], 26 | }, 27 | }, 28 | ) 29 | -------------------------------------------------------------------------------- /metaverse/apps/frontend/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + React + TS 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /metaverse/apps/frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frontend", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc -b && vite build", 9 | "lint": "eslint .", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "react": "^18.3.1", 14 | "react-dom": "^18.3.1" 15 | }, 16 | "devDependencies": { 17 | "@eslint/js": "^9.13.0", 18 | "@types/react": "^18.3.12", 19 | "@types/react-dom": "^18.3.1", 20 | "@vitejs/plugin-react": "^4.3.3", 21 | "eslint": "^9.13.0", 22 | "eslint-plugin-react-hooks": "^5.0.0", 23 | "eslint-plugin-react-refresh": "^0.4.14", 24 | "globals": "^15.11.0", 25 | "typescript": "~5.6.2", 26 | "typescript-eslint": "^8.11.0", 27 | "vite": "^5.4.10" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /metaverse/apps/frontend/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /metaverse/apps/frontend/src/App.css: -------------------------------------------------------------------------------- 1 | #root { 2 | max-width: 1280px; 3 | margin: 0 auto; 4 | padding: 2rem; 5 | text-align: center; 6 | } 7 | 8 | .logo { 9 | height: 6em; 10 | padding: 1.5em; 11 | will-change: filter; 12 | transition: filter 300ms; 13 | } 14 | .logo:hover { 15 | filter: drop-shadow(0 0 2em #646cffaa); 16 | } 17 | .logo.react:hover { 18 | filter: drop-shadow(0 0 2em #61dafbaa); 19 | } 20 | 21 | @keyframes logo-spin { 22 | from { 23 | transform: rotate(0deg); 24 | } 25 | to { 26 | transform: rotate(360deg); 27 | } 28 | } 29 | 30 | @media (prefers-reduced-motion: no-preference) { 31 | a:nth-of-type(2) .logo { 32 | animation: logo-spin infinite 20s linear; 33 | } 34 | } 35 | 36 | .card { 37 | padding: 2em; 38 | } 39 | 40 | .read-the-docs { 41 | color: #888; 42 | } 43 | -------------------------------------------------------------------------------- /metaverse/apps/frontend/src/App.tsx: -------------------------------------------------------------------------------- 1 | import Arena from "./Game"; 2 | 3 | function App() { 4 | 5 | return ( 6 | <> 7 | 8 | 9 | ) 10 | } 11 | 12 | export default App 13 | -------------------------------------------------------------------------------- /metaverse/apps/frontend/src/Game.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useRef, useState } from 'react'; 2 | 3 | const Arena = () => { 4 | const canvasRef = useRef(null); 5 | const wsRef = useRef(null); 6 | const [currentUser, setCurrentUser] = useState({}); 7 | const [users, setUsers] = useState(new Map()); 8 | const [params, setParams] = useState({ token: '', spaceId: '' }); 9 | 10 | // Initialize WebSocket connection and handle URL params 11 | useEffect(() => { 12 | const urlParams = new URLSearchParams(window.location.search); 13 | const token = urlParams.get('token') || ''; 14 | const spaceId = urlParams.get('spaceId') || ''; 15 | setParams({ token, spaceId }); 16 | 17 | // Initialize WebSocket 18 | wsRef.current = new WebSocket('ws://localhost:3001'); // Replace with your WS_URL 19 | 20 | wsRef.current.onopen = () => { 21 | // Join the space once connected 22 | wsRef.current.send(JSON.stringify({ 23 | type: 'join', 24 | payload: { 25 | spaceId, 26 | token 27 | } 28 | })); 29 | }; 30 | 31 | wsRef.current.onmessage = (event: any) => { 32 | const message = JSON.parse(event.data); 33 | handleWebSocketMessage(message); 34 | }; 35 | 36 | return () => { 37 | if (wsRef.current) { 38 | wsRef.current.close(); 39 | } 40 | }; 41 | }, []); 42 | 43 | const handleWebSocketMessage = (message: any) => { 44 | switch (message.type) { 45 | case 'space-joined': 46 | // Initialize current user position and other users 47 | console.log("set") 48 | console.log({ 49 | x: message.payload.spawn.x, 50 | y: message.payload.spawn.y, 51 | userId: message.payload.userId 52 | }) 53 | setCurrentUser({ 54 | x: message.payload.spawn.x, 55 | y: message.payload.spawn.y, 56 | userId: message.payload.userId 57 | }); 58 | 59 | // Initialize other users from the payload 60 | const userMap = new Map(); 61 | message.payload.users.forEach((user: any) => { 62 | userMap.set(user.userId, user); 63 | }); 64 | setUsers(userMap); 65 | break; 66 | 67 | case 'user-joined': 68 | setUsers(prev => { 69 | const newUsers = new Map(prev); 70 | newUsers.set(message.payload.userId, { 71 | x: message.payload.x, 72 | y: message.payload.y, 73 | userId: message.payload.userId 74 | }); 75 | return newUsers; 76 | }); 77 | break; 78 | 79 | case 'movement': 80 | setUsers(prev => { 81 | const newUsers = new Map(prev); 82 | const user = newUsers.get(message.payload.userId); 83 | if (user) { 84 | user.x = message.payload.x; 85 | user.y = message.payload.y; 86 | newUsers.set(message.payload.userId, user); 87 | } 88 | return newUsers; 89 | }); 90 | break; 91 | 92 | case 'movement-rejected': 93 | // Reset current user position if movement was rejected 94 | setCurrentUser((prev: any) => ({ 95 | ...prev, 96 | x: message.payload.x, 97 | y: message.payload.y 98 | })); 99 | break; 100 | 101 | case 'user-left': 102 | setUsers(prev => { 103 | const newUsers = new Map(prev); 104 | newUsers.delete(message.payload.userId); 105 | return newUsers; 106 | }); 107 | break; 108 | } 109 | }; 110 | 111 | // Handle user movement 112 | const handleMove = (newX: any, newY: any) => { 113 | if (!currentUser) return; 114 | 115 | // Send movement request 116 | wsRef.current.send(JSON.stringify({ 117 | type: 'move', 118 | payload: { 119 | x: newX, 120 | y: newY, 121 | userId: currentUser.userId 122 | } 123 | })); 124 | }; 125 | 126 | // Draw the arena 127 | useEffect(() => { 128 | console.log("render") 129 | const canvas = canvasRef.current; 130 | if (!canvas) return; 131 | console.log("below render") 132 | 133 | const ctx = canvas.getContext('2d'); 134 | ctx.clearRect(0, 0, canvas.width, canvas.height); 135 | 136 | // Draw grid 137 | ctx.strokeStyle = '#eee'; 138 | for (let i = 0; i < canvas.width; i += 50) { 139 | ctx.beginPath(); 140 | ctx.moveTo(i, 0); 141 | ctx.lineTo(i, canvas.height); 142 | ctx.stroke(); 143 | } 144 | for (let i = 0; i < canvas.height; i += 50) { 145 | ctx.beginPath(); 146 | ctx.moveTo(0, i); 147 | ctx.lineTo(canvas.width, i); 148 | ctx.stroke(); 149 | } 150 | 151 | console.log("before curerntusert") 152 | console.log(currentUser) 153 | // Draw current user 154 | if (currentUser && currentUser.x) { 155 | console.log("drawing myself") 156 | console.log(currentUser) 157 | ctx.beginPath(); 158 | ctx.fillStyle = '#FF6B6B'; 159 | ctx.arc(currentUser.x * 50, currentUser.y * 50, 20, 0, Math.PI * 2); 160 | ctx.fill(); 161 | ctx.fillStyle = '#000'; 162 | ctx.font = '14px Arial'; 163 | ctx.textAlign = 'center'; 164 | ctx.fillText('You', currentUser.x * 50, currentUser.y * 50 + 40); 165 | } 166 | 167 | // Draw other users 168 | users.forEach(user => { 169 | if (!user.x) { 170 | return 171 | } 172 | console.log("drawing other user") 173 | console.log(user) 174 | ctx.beginPath(); 175 | ctx.fillStyle = '#4ECDC4'; 176 | ctx.arc(user.x * 50, user.y * 50, 20, 0, Math.PI * 2); 177 | ctx.fill(); 178 | ctx.fillStyle = '#000'; 179 | ctx.font = '14px Arial'; 180 | ctx.textAlign = 'center'; 181 | ctx.fillText(`User ${user.userId}`, user.x * 50, user.y * 50 + 40); 182 | }); 183 | }, [currentUser, users]); 184 | 185 | const handleKeyDown = (e: any) => { 186 | if (!currentUser) return; 187 | 188 | const { x, y } = currentUser; 189 | switch (e.key) { 190 | case 'ArrowUp': 191 | handleMove(x, y - 1); 192 | break; 193 | case 'ArrowDown': 194 | handleMove(x, y + 1); 195 | break; 196 | case 'ArrowLeft': 197 | handleMove(x - 1, y); 198 | break; 199 | case 'ArrowRight': 200 | handleMove(x + 1, y); 201 | break; 202 | } 203 | }; 204 | 205 | return ( 206 |
207 |

Arena

208 |
209 |

Token: {params.token}

210 |

Space ID: {params.spaceId}

211 |

Connected Users: {users.size + (currentUser ? 1 : 0)}

212 |
213 |
214 | 220 |
221 |

Use arrow keys to move your avatar

222 |
223 | ); 224 | }; 225 | 226 | export default Arena; -------------------------------------------------------------------------------- /metaverse/apps/frontend/src/assets/react.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /metaverse/apps/frontend/src/index.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hkirat/2d-metaverse/16c7ab9d40609071d979d75db02e8a2497658273/metaverse/apps/frontend/src/index.css -------------------------------------------------------------------------------- /metaverse/apps/frontend/src/main.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react' 2 | import { createRoot } from 'react-dom/client' 3 | import './index.css' 4 | import App from './App.tsx' 5 | 6 | createRoot(document.getElementById('root')!).render( 7 | 8 | 9 | , 10 | ) 11 | -------------------------------------------------------------------------------- /metaverse/apps/frontend/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /metaverse/apps/frontend/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", 4 | "target": "ES2020", 5 | "useDefineForClassFields": true, 6 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 7 | "module": "ESNext", 8 | "skipLibCheck": true, 9 | 10 | /* Bundler mode */ 11 | "moduleResolution": "Bundler", 12 | "allowImportingTsExtensions": true, 13 | "isolatedModules": true, 14 | "moduleDetection": "force", 15 | "noEmit": true, 16 | "jsx": "react-jsx", 17 | 18 | /* Linting */ 19 | "strict": true, 20 | "noUnusedLocals": true, 21 | "noUnusedParameters": true, 22 | "noFallthroughCasesInSwitch": true, 23 | "noUncheckedSideEffectImports": true 24 | }, 25 | "include": ["src"] 26 | } 27 | -------------------------------------------------------------------------------- /metaverse/apps/frontend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [ 4 | { "path": "./tsconfig.app.json" }, 5 | { "path": "./tsconfig.node.json" } 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /metaverse/apps/frontend/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", 4 | "target": "ES2022", 5 | "lib": ["ES2023"], 6 | "module": "ESNext", 7 | "skipLibCheck": true, 8 | 9 | /* Bundler mode */ 10 | "moduleResolution": "Bundler", 11 | "allowImportingTsExtensions": true, 12 | "isolatedModules": true, 13 | "moduleDetection": "force", 14 | "noEmit": true, 15 | 16 | /* Linting */ 17 | "strict": true, 18 | "noUnusedLocals": true, 19 | "noUnusedParameters": true, 20 | "noFallthroughCasesInSwitch": true, 21 | "noUncheckedSideEffectImports": true 22 | }, 23 | "include": ["vite.config.ts"] 24 | } 25 | -------------------------------------------------------------------------------- /metaverse/apps/frontend/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vite.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /metaverse/apps/http/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "http", 3 | "version": "1.0.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "http", 9 | "version": "1.0.0", 10 | "license": "ISC", 11 | "dependencies": { 12 | "@types/express": "^5.0.0", 13 | "express": "^4.21.1", 14 | "typescript": "^5.6.3" 15 | } 16 | }, 17 | "node_modules/@types/body-parser": { 18 | "version": "1.19.5", 19 | "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", 20 | "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", 21 | "license": "MIT", 22 | "dependencies": { 23 | "@types/connect": "*", 24 | "@types/node": "*" 25 | } 26 | }, 27 | "node_modules/@types/connect": { 28 | "version": "3.4.38", 29 | "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", 30 | "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", 31 | "license": "MIT", 32 | "dependencies": { 33 | "@types/node": "*" 34 | } 35 | }, 36 | "node_modules/@types/express": { 37 | "version": "5.0.0", 38 | "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.0.tgz", 39 | "integrity": "sha512-DvZriSMehGHL1ZNLzi6MidnsDhUZM/x2pRdDIKdwbUNqqwHxMlRdkxtn6/EPKyqKpHqTl/4nRZsRNLpZxZRpPQ==", 40 | "license": "MIT", 41 | "dependencies": { 42 | "@types/body-parser": "*", 43 | "@types/express-serve-static-core": "^5.0.0", 44 | "@types/qs": "*", 45 | "@types/serve-static": "*" 46 | } 47 | }, 48 | "node_modules/@types/express-serve-static-core": { 49 | "version": "5.0.1", 50 | "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.1.tgz", 51 | "integrity": "sha512-CRICJIl0N5cXDONAdlTv5ShATZ4HEwk6kDDIW2/w9qOWKg+NU/5F8wYRWCrONad0/UKkloNSmmyN/wX4rtpbVA==", 52 | "license": "MIT", 53 | "dependencies": { 54 | "@types/node": "*", 55 | "@types/qs": "*", 56 | "@types/range-parser": "*", 57 | "@types/send": "*" 58 | } 59 | }, 60 | "node_modules/@types/http-errors": { 61 | "version": "2.0.4", 62 | "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", 63 | "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", 64 | "license": "MIT" 65 | }, 66 | "node_modules/@types/mime": { 67 | "version": "1.3.5", 68 | "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", 69 | "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", 70 | "license": "MIT" 71 | }, 72 | "node_modules/@types/node": { 73 | "version": "22.8.4", 74 | "resolved": "https://registry.npmjs.org/@types/node/-/node-22.8.4.tgz", 75 | "integrity": "sha512-SpNNxkftTJOPk0oN+y2bIqurEXHTA2AOZ3EJDDKeJ5VzkvvORSvmQXGQarcOzWV1ac7DCaPBEdMDxBsM+d8jWw==", 76 | "license": "MIT", 77 | "dependencies": { 78 | "undici-types": "~6.19.8" 79 | } 80 | }, 81 | "node_modules/@types/qs": { 82 | "version": "6.9.16", 83 | "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.16.tgz", 84 | "integrity": "sha512-7i+zxXdPD0T4cKDuxCUXJ4wHcsJLwENa6Z3dCu8cfCK743OGy5Nu1RmAGqDPsoTDINVEcdXKRvR/zre+P2Ku1A==", 85 | "license": "MIT" 86 | }, 87 | "node_modules/@types/range-parser": { 88 | "version": "1.2.7", 89 | "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", 90 | "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", 91 | "license": "MIT" 92 | }, 93 | "node_modules/@types/send": { 94 | "version": "0.17.4", 95 | "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", 96 | "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", 97 | "license": "MIT", 98 | "dependencies": { 99 | "@types/mime": "^1", 100 | "@types/node": "*" 101 | } 102 | }, 103 | "node_modules/@types/serve-static": { 104 | "version": "1.15.7", 105 | "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", 106 | "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", 107 | "license": "MIT", 108 | "dependencies": { 109 | "@types/http-errors": "*", 110 | "@types/node": "*", 111 | "@types/send": "*" 112 | } 113 | }, 114 | "node_modules/accepts": { 115 | "version": "1.3.8", 116 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", 117 | "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", 118 | "license": "MIT", 119 | "dependencies": { 120 | "mime-types": "~2.1.34", 121 | "negotiator": "0.6.3" 122 | }, 123 | "engines": { 124 | "node": ">= 0.6" 125 | } 126 | }, 127 | "node_modules/array-flatten": { 128 | "version": "1.1.1", 129 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 130 | "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", 131 | "license": "MIT" 132 | }, 133 | "node_modules/body-parser": { 134 | "version": "1.20.3", 135 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", 136 | "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", 137 | "license": "MIT", 138 | "dependencies": { 139 | "bytes": "3.1.2", 140 | "content-type": "~1.0.5", 141 | "debug": "2.6.9", 142 | "depd": "2.0.0", 143 | "destroy": "1.2.0", 144 | "http-errors": "2.0.0", 145 | "iconv-lite": "0.4.24", 146 | "on-finished": "2.4.1", 147 | "qs": "6.13.0", 148 | "raw-body": "2.5.2", 149 | "type-is": "~1.6.18", 150 | "unpipe": "1.0.0" 151 | }, 152 | "engines": { 153 | "node": ">= 0.8", 154 | "npm": "1.2.8000 || >= 1.4.16" 155 | } 156 | }, 157 | "node_modules/bytes": { 158 | "version": "3.1.2", 159 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", 160 | "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", 161 | "license": "MIT", 162 | "engines": { 163 | "node": ">= 0.8" 164 | } 165 | }, 166 | "node_modules/call-bind": { 167 | "version": "1.0.7", 168 | "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", 169 | "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", 170 | "license": "MIT", 171 | "dependencies": { 172 | "es-define-property": "^1.0.0", 173 | "es-errors": "^1.3.0", 174 | "function-bind": "^1.1.2", 175 | "get-intrinsic": "^1.2.4", 176 | "set-function-length": "^1.2.1" 177 | }, 178 | "engines": { 179 | "node": ">= 0.4" 180 | }, 181 | "funding": { 182 | "url": "https://github.com/sponsors/ljharb" 183 | } 184 | }, 185 | "node_modules/content-disposition": { 186 | "version": "0.5.4", 187 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", 188 | "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", 189 | "license": "MIT", 190 | "dependencies": { 191 | "safe-buffer": "5.2.1" 192 | }, 193 | "engines": { 194 | "node": ">= 0.6" 195 | } 196 | }, 197 | "node_modules/content-type": { 198 | "version": "1.0.5", 199 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", 200 | "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", 201 | "license": "MIT", 202 | "engines": { 203 | "node": ">= 0.6" 204 | } 205 | }, 206 | "node_modules/cookie": { 207 | "version": "0.7.1", 208 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", 209 | "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", 210 | "license": "MIT", 211 | "engines": { 212 | "node": ">= 0.6" 213 | } 214 | }, 215 | "node_modules/cookie-signature": { 216 | "version": "1.0.6", 217 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 218 | "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", 219 | "license": "MIT" 220 | }, 221 | "node_modules/debug": { 222 | "version": "2.6.9", 223 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 224 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 225 | "license": "MIT", 226 | "dependencies": { 227 | "ms": "2.0.0" 228 | } 229 | }, 230 | "node_modules/define-data-property": { 231 | "version": "1.1.4", 232 | "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", 233 | "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", 234 | "license": "MIT", 235 | "dependencies": { 236 | "es-define-property": "^1.0.0", 237 | "es-errors": "^1.3.0", 238 | "gopd": "^1.0.1" 239 | }, 240 | "engines": { 241 | "node": ">= 0.4" 242 | }, 243 | "funding": { 244 | "url": "https://github.com/sponsors/ljharb" 245 | } 246 | }, 247 | "node_modules/depd": { 248 | "version": "2.0.0", 249 | "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", 250 | "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", 251 | "license": "MIT", 252 | "engines": { 253 | "node": ">= 0.8" 254 | } 255 | }, 256 | "node_modules/destroy": { 257 | "version": "1.2.0", 258 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", 259 | "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", 260 | "license": "MIT", 261 | "engines": { 262 | "node": ">= 0.8", 263 | "npm": "1.2.8000 || >= 1.4.16" 264 | } 265 | }, 266 | "node_modules/ee-first": { 267 | "version": "1.1.1", 268 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 269 | "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", 270 | "license": "MIT" 271 | }, 272 | "node_modules/encodeurl": { 273 | "version": "2.0.0", 274 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", 275 | "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", 276 | "license": "MIT", 277 | "engines": { 278 | "node": ">= 0.8" 279 | } 280 | }, 281 | "node_modules/es-define-property": { 282 | "version": "1.0.0", 283 | "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", 284 | "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", 285 | "license": "MIT", 286 | "dependencies": { 287 | "get-intrinsic": "^1.2.4" 288 | }, 289 | "engines": { 290 | "node": ">= 0.4" 291 | } 292 | }, 293 | "node_modules/es-errors": { 294 | "version": "1.3.0", 295 | "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", 296 | "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", 297 | "license": "MIT", 298 | "engines": { 299 | "node": ">= 0.4" 300 | } 301 | }, 302 | "node_modules/escape-html": { 303 | "version": "1.0.3", 304 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 305 | "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", 306 | "license": "MIT" 307 | }, 308 | "node_modules/etag": { 309 | "version": "1.8.1", 310 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 311 | "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", 312 | "license": "MIT", 313 | "engines": { 314 | "node": ">= 0.6" 315 | } 316 | }, 317 | "node_modules/express": { 318 | "version": "4.21.1", 319 | "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", 320 | "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", 321 | "license": "MIT", 322 | "dependencies": { 323 | "accepts": "~1.3.8", 324 | "array-flatten": "1.1.1", 325 | "body-parser": "1.20.3", 326 | "content-disposition": "0.5.4", 327 | "content-type": "~1.0.4", 328 | "cookie": "0.7.1", 329 | "cookie-signature": "1.0.6", 330 | "debug": "2.6.9", 331 | "depd": "2.0.0", 332 | "encodeurl": "~2.0.0", 333 | "escape-html": "~1.0.3", 334 | "etag": "~1.8.1", 335 | "finalhandler": "1.3.1", 336 | "fresh": "0.5.2", 337 | "http-errors": "2.0.0", 338 | "merge-descriptors": "1.0.3", 339 | "methods": "~1.1.2", 340 | "on-finished": "2.4.1", 341 | "parseurl": "~1.3.3", 342 | "path-to-regexp": "0.1.10", 343 | "proxy-addr": "~2.0.7", 344 | "qs": "6.13.0", 345 | "range-parser": "~1.2.1", 346 | "safe-buffer": "5.2.1", 347 | "send": "0.19.0", 348 | "serve-static": "1.16.2", 349 | "setprototypeof": "1.2.0", 350 | "statuses": "2.0.1", 351 | "type-is": "~1.6.18", 352 | "utils-merge": "1.0.1", 353 | "vary": "~1.1.2" 354 | }, 355 | "engines": { 356 | "node": ">= 0.10.0" 357 | } 358 | }, 359 | "node_modules/finalhandler": { 360 | "version": "1.3.1", 361 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", 362 | "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", 363 | "license": "MIT", 364 | "dependencies": { 365 | "debug": "2.6.9", 366 | "encodeurl": "~2.0.0", 367 | "escape-html": "~1.0.3", 368 | "on-finished": "2.4.1", 369 | "parseurl": "~1.3.3", 370 | "statuses": "2.0.1", 371 | "unpipe": "~1.0.0" 372 | }, 373 | "engines": { 374 | "node": ">= 0.8" 375 | } 376 | }, 377 | "node_modules/forwarded": { 378 | "version": "0.2.0", 379 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", 380 | "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", 381 | "license": "MIT", 382 | "engines": { 383 | "node": ">= 0.6" 384 | } 385 | }, 386 | "node_modules/fresh": { 387 | "version": "0.5.2", 388 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 389 | "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", 390 | "license": "MIT", 391 | "engines": { 392 | "node": ">= 0.6" 393 | } 394 | }, 395 | "node_modules/function-bind": { 396 | "version": "1.1.2", 397 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", 398 | "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", 399 | "license": "MIT", 400 | "funding": { 401 | "url": "https://github.com/sponsors/ljharb" 402 | } 403 | }, 404 | "node_modules/get-intrinsic": { 405 | "version": "1.2.4", 406 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", 407 | "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", 408 | "license": "MIT", 409 | "dependencies": { 410 | "es-errors": "^1.3.0", 411 | "function-bind": "^1.1.2", 412 | "has-proto": "^1.0.1", 413 | "has-symbols": "^1.0.3", 414 | "hasown": "^2.0.0" 415 | }, 416 | "engines": { 417 | "node": ">= 0.4" 418 | }, 419 | "funding": { 420 | "url": "https://github.com/sponsors/ljharb" 421 | } 422 | }, 423 | "node_modules/gopd": { 424 | "version": "1.0.1", 425 | "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", 426 | "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", 427 | "license": "MIT", 428 | "dependencies": { 429 | "get-intrinsic": "^1.1.3" 430 | }, 431 | "funding": { 432 | "url": "https://github.com/sponsors/ljharb" 433 | } 434 | }, 435 | "node_modules/has-property-descriptors": { 436 | "version": "1.0.2", 437 | "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", 438 | "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", 439 | "license": "MIT", 440 | "dependencies": { 441 | "es-define-property": "^1.0.0" 442 | }, 443 | "funding": { 444 | "url": "https://github.com/sponsors/ljharb" 445 | } 446 | }, 447 | "node_modules/has-proto": { 448 | "version": "1.0.3", 449 | "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", 450 | "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", 451 | "license": "MIT", 452 | "engines": { 453 | "node": ">= 0.4" 454 | }, 455 | "funding": { 456 | "url": "https://github.com/sponsors/ljharb" 457 | } 458 | }, 459 | "node_modules/has-symbols": { 460 | "version": "1.0.3", 461 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", 462 | "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", 463 | "license": "MIT", 464 | "engines": { 465 | "node": ">= 0.4" 466 | }, 467 | "funding": { 468 | "url": "https://github.com/sponsors/ljharb" 469 | } 470 | }, 471 | "node_modules/hasown": { 472 | "version": "2.0.2", 473 | "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", 474 | "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", 475 | "license": "MIT", 476 | "dependencies": { 477 | "function-bind": "^1.1.2" 478 | }, 479 | "engines": { 480 | "node": ">= 0.4" 481 | } 482 | }, 483 | "node_modules/http-errors": { 484 | "version": "2.0.0", 485 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", 486 | "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", 487 | "license": "MIT", 488 | "dependencies": { 489 | "depd": "2.0.0", 490 | "inherits": "2.0.4", 491 | "setprototypeof": "1.2.0", 492 | "statuses": "2.0.1", 493 | "toidentifier": "1.0.1" 494 | }, 495 | "engines": { 496 | "node": ">= 0.8" 497 | } 498 | }, 499 | "node_modules/iconv-lite": { 500 | "version": "0.4.24", 501 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 502 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 503 | "license": "MIT", 504 | "dependencies": { 505 | "safer-buffer": ">= 2.1.2 < 3" 506 | }, 507 | "engines": { 508 | "node": ">=0.10.0" 509 | } 510 | }, 511 | "node_modules/inherits": { 512 | "version": "2.0.4", 513 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 514 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 515 | "license": "ISC" 516 | }, 517 | "node_modules/ipaddr.js": { 518 | "version": "1.9.1", 519 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", 520 | "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", 521 | "license": "MIT", 522 | "engines": { 523 | "node": ">= 0.10" 524 | } 525 | }, 526 | "node_modules/media-typer": { 527 | "version": "0.3.0", 528 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 529 | "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", 530 | "license": "MIT", 531 | "engines": { 532 | "node": ">= 0.6" 533 | } 534 | }, 535 | "node_modules/merge-descriptors": { 536 | "version": "1.0.3", 537 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", 538 | "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", 539 | "license": "MIT", 540 | "funding": { 541 | "url": "https://github.com/sponsors/sindresorhus" 542 | } 543 | }, 544 | "node_modules/methods": { 545 | "version": "1.1.2", 546 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 547 | "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", 548 | "license": "MIT", 549 | "engines": { 550 | "node": ">= 0.6" 551 | } 552 | }, 553 | "node_modules/mime": { 554 | "version": "1.6.0", 555 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", 556 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", 557 | "license": "MIT", 558 | "bin": { 559 | "mime": "cli.js" 560 | }, 561 | "engines": { 562 | "node": ">=4" 563 | } 564 | }, 565 | "node_modules/mime-db": { 566 | "version": "1.52.0", 567 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", 568 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", 569 | "license": "MIT", 570 | "engines": { 571 | "node": ">= 0.6" 572 | } 573 | }, 574 | "node_modules/mime-types": { 575 | "version": "2.1.35", 576 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", 577 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", 578 | "license": "MIT", 579 | "dependencies": { 580 | "mime-db": "1.52.0" 581 | }, 582 | "engines": { 583 | "node": ">= 0.6" 584 | } 585 | }, 586 | "node_modules/ms": { 587 | "version": "2.0.0", 588 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 589 | "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", 590 | "license": "MIT" 591 | }, 592 | "node_modules/negotiator": { 593 | "version": "0.6.3", 594 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", 595 | "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", 596 | "license": "MIT", 597 | "engines": { 598 | "node": ">= 0.6" 599 | } 600 | }, 601 | "node_modules/object-inspect": { 602 | "version": "1.13.2", 603 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", 604 | "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", 605 | "license": "MIT", 606 | "engines": { 607 | "node": ">= 0.4" 608 | }, 609 | "funding": { 610 | "url": "https://github.com/sponsors/ljharb" 611 | } 612 | }, 613 | "node_modules/on-finished": { 614 | "version": "2.4.1", 615 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", 616 | "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", 617 | "license": "MIT", 618 | "dependencies": { 619 | "ee-first": "1.1.1" 620 | }, 621 | "engines": { 622 | "node": ">= 0.8" 623 | } 624 | }, 625 | "node_modules/parseurl": { 626 | "version": "1.3.3", 627 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", 628 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", 629 | "license": "MIT", 630 | "engines": { 631 | "node": ">= 0.8" 632 | } 633 | }, 634 | "node_modules/path-to-regexp": { 635 | "version": "0.1.10", 636 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", 637 | "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", 638 | "license": "MIT" 639 | }, 640 | "node_modules/proxy-addr": { 641 | "version": "2.0.7", 642 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", 643 | "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", 644 | "license": "MIT", 645 | "dependencies": { 646 | "forwarded": "0.2.0", 647 | "ipaddr.js": "1.9.1" 648 | }, 649 | "engines": { 650 | "node": ">= 0.10" 651 | } 652 | }, 653 | "node_modules/qs": { 654 | "version": "6.13.0", 655 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", 656 | "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", 657 | "license": "BSD-3-Clause", 658 | "dependencies": { 659 | "side-channel": "^1.0.6" 660 | }, 661 | "engines": { 662 | "node": ">=0.6" 663 | }, 664 | "funding": { 665 | "url": "https://github.com/sponsors/ljharb" 666 | } 667 | }, 668 | "node_modules/range-parser": { 669 | "version": "1.2.1", 670 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", 671 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", 672 | "license": "MIT", 673 | "engines": { 674 | "node": ">= 0.6" 675 | } 676 | }, 677 | "node_modules/raw-body": { 678 | "version": "2.5.2", 679 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", 680 | "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", 681 | "license": "MIT", 682 | "dependencies": { 683 | "bytes": "3.1.2", 684 | "http-errors": "2.0.0", 685 | "iconv-lite": "0.4.24", 686 | "unpipe": "1.0.0" 687 | }, 688 | "engines": { 689 | "node": ">= 0.8" 690 | } 691 | }, 692 | "node_modules/safe-buffer": { 693 | "version": "5.2.1", 694 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 695 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 696 | "funding": [ 697 | { 698 | "type": "github", 699 | "url": "https://github.com/sponsors/feross" 700 | }, 701 | { 702 | "type": "patreon", 703 | "url": "https://www.patreon.com/feross" 704 | }, 705 | { 706 | "type": "consulting", 707 | "url": "https://feross.org/support" 708 | } 709 | ], 710 | "license": "MIT" 711 | }, 712 | "node_modules/safer-buffer": { 713 | "version": "2.1.2", 714 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 715 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", 716 | "license": "MIT" 717 | }, 718 | "node_modules/send": { 719 | "version": "0.19.0", 720 | "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", 721 | "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", 722 | "license": "MIT", 723 | "dependencies": { 724 | "debug": "2.6.9", 725 | "depd": "2.0.0", 726 | "destroy": "1.2.0", 727 | "encodeurl": "~1.0.2", 728 | "escape-html": "~1.0.3", 729 | "etag": "~1.8.1", 730 | "fresh": "0.5.2", 731 | "http-errors": "2.0.0", 732 | "mime": "1.6.0", 733 | "ms": "2.1.3", 734 | "on-finished": "2.4.1", 735 | "range-parser": "~1.2.1", 736 | "statuses": "2.0.1" 737 | }, 738 | "engines": { 739 | "node": ">= 0.8.0" 740 | } 741 | }, 742 | "node_modules/send/node_modules/encodeurl": { 743 | "version": "1.0.2", 744 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 745 | "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", 746 | "license": "MIT", 747 | "engines": { 748 | "node": ">= 0.8" 749 | } 750 | }, 751 | "node_modules/send/node_modules/ms": { 752 | "version": "2.1.3", 753 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 754 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", 755 | "license": "MIT" 756 | }, 757 | "node_modules/serve-static": { 758 | "version": "1.16.2", 759 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", 760 | "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", 761 | "license": "MIT", 762 | "dependencies": { 763 | "encodeurl": "~2.0.0", 764 | "escape-html": "~1.0.3", 765 | "parseurl": "~1.3.3", 766 | "send": "0.19.0" 767 | }, 768 | "engines": { 769 | "node": ">= 0.8.0" 770 | } 771 | }, 772 | "node_modules/set-function-length": { 773 | "version": "1.2.2", 774 | "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", 775 | "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", 776 | "license": "MIT", 777 | "dependencies": { 778 | "define-data-property": "^1.1.4", 779 | "es-errors": "^1.3.0", 780 | "function-bind": "^1.1.2", 781 | "get-intrinsic": "^1.2.4", 782 | "gopd": "^1.0.1", 783 | "has-property-descriptors": "^1.0.2" 784 | }, 785 | "engines": { 786 | "node": ">= 0.4" 787 | } 788 | }, 789 | "node_modules/setprototypeof": { 790 | "version": "1.2.0", 791 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", 792 | "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", 793 | "license": "ISC" 794 | }, 795 | "node_modules/side-channel": { 796 | "version": "1.0.6", 797 | "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", 798 | "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", 799 | "license": "MIT", 800 | "dependencies": { 801 | "call-bind": "^1.0.7", 802 | "es-errors": "^1.3.0", 803 | "get-intrinsic": "^1.2.4", 804 | "object-inspect": "^1.13.1" 805 | }, 806 | "engines": { 807 | "node": ">= 0.4" 808 | }, 809 | "funding": { 810 | "url": "https://github.com/sponsors/ljharb" 811 | } 812 | }, 813 | "node_modules/statuses": { 814 | "version": "2.0.1", 815 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", 816 | "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", 817 | "license": "MIT", 818 | "engines": { 819 | "node": ">= 0.8" 820 | } 821 | }, 822 | "node_modules/toidentifier": { 823 | "version": "1.0.1", 824 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", 825 | "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", 826 | "license": "MIT", 827 | "engines": { 828 | "node": ">=0.6" 829 | } 830 | }, 831 | "node_modules/type-is": { 832 | "version": "1.6.18", 833 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", 834 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", 835 | "license": "MIT", 836 | "dependencies": { 837 | "media-typer": "0.3.0", 838 | "mime-types": "~2.1.24" 839 | }, 840 | "engines": { 841 | "node": ">= 0.6" 842 | } 843 | }, 844 | "node_modules/typescript": { 845 | "version": "5.6.3", 846 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", 847 | "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", 848 | "license": "Apache-2.0", 849 | "bin": { 850 | "tsc": "bin/tsc", 851 | "tsserver": "bin/tsserver" 852 | }, 853 | "engines": { 854 | "node": ">=14.17" 855 | } 856 | }, 857 | "node_modules/undici-types": { 858 | "version": "6.19.8", 859 | "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", 860 | "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", 861 | "license": "MIT" 862 | }, 863 | "node_modules/unpipe": { 864 | "version": "1.0.0", 865 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 866 | "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", 867 | "license": "MIT", 868 | "engines": { 869 | "node": ">= 0.8" 870 | } 871 | }, 872 | "node_modules/utils-merge": { 873 | "version": "1.0.1", 874 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 875 | "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", 876 | "license": "MIT", 877 | "engines": { 878 | "node": ">= 0.4.0" 879 | } 880 | }, 881 | "node_modules/vary": { 882 | "version": "1.1.2", 883 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 884 | "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", 885 | "license": "MIT", 886 | "engines": { 887 | "node": ">= 0.8" 888 | } 889 | } 890 | } 891 | } 892 | -------------------------------------------------------------------------------- /metaverse/apps/http/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "http", 3 | "version": "1.0.0", 4 | "main": "dist/index.js", 5 | "scripts": { 6 | "build": "npx esbuild src/index.ts --bundle --outfile=dist/index.js --platform=node --tsconfig=tsconfig.json", 7 | "start": "node dist/index.js", 8 | "dev": "npm run build && npm run start" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "description": "", 14 | "dependencies": { 15 | "@repo/db": "workspace:*", 16 | "@types/express": "^5.0.0", 17 | "@types/jsonwebtoken": "^9.0.7", 18 | "esbuild": "^0.24.0", 19 | "express": "^4.21.1", 20 | "jsonwebtoken": "^9.0.2", 21 | "typescript": "^5.6.3", 22 | "zod": "^3.23.8" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /metaverse/apps/http/src/config.ts: -------------------------------------------------------------------------------- 1 | export const JWT_PASSWORD = "123kasdk123" -------------------------------------------------------------------------------- /metaverse/apps/http/src/index.ts: -------------------------------------------------------------------------------- 1 | import express from "express"; 2 | import { router } from "./routes/v1"; 3 | 4 | const app = express(); 5 | app.use(express.json()) 6 | 7 | app.use("/api/v1", router) 8 | 9 | app.listen(process.env.PORT || 3000) 10 | -------------------------------------------------------------------------------- /metaverse/apps/http/src/middleware/admin.ts: -------------------------------------------------------------------------------- 1 | 2 | import jwt from "jsonwebtoken"; 3 | import { JWT_PASSWORD } from "../config"; 4 | import { NextFunction, Request, Response } from "express"; 5 | 6 | export const adminMiddleware = (req: Request, res: Response, next: NextFunction) => { 7 | const header = req.headers["authorization"]; 8 | const token = header?.split(" ")[1]; 9 | 10 | if (!token) { 11 | res.status(403).json({message: "Unauthorized"}) 12 | return 13 | } 14 | 15 | try { 16 | const decoded = jwt.verify(token, JWT_PASSWORD) as { role: string, userId: string } 17 | if (decoded.role !== "Admin") { 18 | res.status(403).json({message: "Unauthorized"}) 19 | return 20 | } 21 | req.userId = decoded.userId 22 | next() 23 | } catch(e) { 24 | res.status(401).json({message: "Unauthorized"}) 25 | return 26 | } 27 | } -------------------------------------------------------------------------------- /metaverse/apps/http/src/middleware/user.ts: -------------------------------------------------------------------------------- 1 | 2 | import jwt from "jsonwebtoken"; 3 | import { JWT_PASSWORD } from "../config"; 4 | import { NextFunction, Request, Response } from "express"; 5 | 6 | export const userMiddleware = (req: Request, res: Response, next: NextFunction) => { 7 | const header = req.headers["authorization"]; 8 | const token = header?.split(" ")[1]; 9 | console.log(req.route.path) 10 | console.log(token) 11 | 12 | if (!token) { 13 | res.status(403).json({message: "Unauthorized"}) 14 | return 15 | } 16 | 17 | try { 18 | const decoded = jwt.verify(token, JWT_PASSWORD) as { role: string, userId: string } 19 | req.userId = decoded.userId 20 | next() 21 | } catch(e) { 22 | res.status(401).json({message: "Unauthorized"}) 23 | return 24 | } 25 | } -------------------------------------------------------------------------------- /metaverse/apps/http/src/routes/v1/admin.ts: -------------------------------------------------------------------------------- 1 | import { Router } from "express"; 2 | import { adminMiddleware } from "../../middleware/admin"; 3 | import { AddElementSchema, CreateAvatarSchema, CreateElementSchema, CreateMapSchema, UpdateElementSchema } from "../../types"; 4 | import client from "@repo/db/client"; 5 | export const adminRouter = Router(); 6 | adminRouter.use(adminMiddleware) 7 | 8 | adminRouter.post("/element", async (req, res) => { 9 | const parsedData = CreateElementSchema.safeParse(req.body) 10 | if (!parsedData.success) { 11 | res.status(400).json({message: "Validation failed"}) 12 | return 13 | } 14 | 15 | const element = await client.element.create({ 16 | data: { 17 | width: parsedData.data.width, 18 | height: parsedData.data.height, 19 | static: parsedData.data.static, 20 | imageUrl: parsedData.data.imageUrl, 21 | } 22 | }) 23 | 24 | res.json({ 25 | id: element.id 26 | }) 27 | }) 28 | 29 | adminRouter.put("/element/:elementId", (req, res) => { 30 | const parsedData = UpdateElementSchema.safeParse(req.body) 31 | if (!parsedData.success) { 32 | res.status(400).json({message: "Validation failed"}) 33 | return 34 | } 35 | client.element.update({ 36 | where: { 37 | id: req.params.elementId 38 | }, 39 | data: { 40 | imageUrl: parsedData.data.imageUrl 41 | } 42 | }) 43 | res.json({message: "Element updated"}) 44 | }) 45 | 46 | adminRouter.post("/avatar", async (req, res) => { 47 | const parsedData = CreateAvatarSchema.safeParse(req.body) 48 | if (!parsedData.success) { 49 | res.status(400).json({message: "Validation failed"}) 50 | return 51 | } 52 | const avatar = await client.avatar.create({ 53 | data: { 54 | name: parsedData.data.name, 55 | imageUrl: parsedData.data.imageUrl 56 | } 57 | }) 58 | res.json({avatarId: avatar.id}) 59 | }) 60 | 61 | adminRouter.post("/map", async (req, res) => { 62 | const parsedData = CreateMapSchema.safeParse(req.body) 63 | if (!parsedData.success) { 64 | res.status(400).json({message: "Validation failed"}) 65 | return 66 | } 67 | const map = await client.map.create({ 68 | data: { 69 | name: parsedData.data.name, 70 | width: parseInt(parsedData.data.dimensions.split("x")[0]), 71 | height: parseInt(parsedData.data.dimensions.split("x")[1]), 72 | thumbnail: parsedData.data.thumbnail, 73 | mapElements: { 74 | create: parsedData.data.defaultElements.map(e => ({ 75 | elementId: e.elementId, 76 | x: e.x, 77 | y: e.y 78 | })) 79 | } 80 | } 81 | }) 82 | 83 | res.json({ 84 | id: map.id 85 | }) 86 | }) -------------------------------------------------------------------------------- /metaverse/apps/http/src/routes/v1/index.ts: -------------------------------------------------------------------------------- 1 | import { Router } from "express"; 2 | import { userRouter } from "./user"; 3 | import { spaceRouter } from "./space"; 4 | import { adminRouter } from "./admin"; 5 | import { SigninSchema, SignupSchema } from "../../types"; 6 | import {hash, compare} from "../../scrypt"; 7 | import client from "@repo/db/client"; 8 | import jwt from "jsonwebtoken"; 9 | import { JWT_PASSWORD } from "../../config"; 10 | 11 | export const router = Router(); 12 | 13 | router.post("/signup", async (req, res) => { 14 | console.log("inside signup") 15 | // check the user 16 | const parsedData = SignupSchema.safeParse(req.body) 17 | if (!parsedData.success) { 18 | console.log("parsed data incorrect") 19 | res.status(400).json({message: "Validation failed"}) 20 | return 21 | } 22 | 23 | const hashedPassword = await hash(parsedData.data.password) 24 | 25 | try { 26 | const user = await client.user.create({ 27 | data: { 28 | username: parsedData.data.username, 29 | password: hashedPassword, 30 | role: parsedData.data.type === "admin" ? "Admin" : "User", 31 | } 32 | }) 33 | res.json({ 34 | userId: user.id 35 | }) 36 | } catch(e) { 37 | console.log("erroer thrown") 38 | console.log(e) 39 | res.status(400).json({message: "User already exists"}) 40 | } 41 | }) 42 | 43 | router.post("/signin", async (req, res) => { 44 | const parsedData = SigninSchema.safeParse(req.body) 45 | if (!parsedData.success) { 46 | res.status(403).json({message: "Validation failed"}) 47 | return 48 | } 49 | 50 | try { 51 | const user = await client.user.findUnique({ 52 | where: { 53 | username: parsedData.data.username 54 | } 55 | }) 56 | 57 | if (!user) { 58 | res.status(403).json({message: "User not found"}) 59 | return 60 | } 61 | const isValid = await compare(parsedData.data.password, user.password) 62 | 63 | if (!isValid) { 64 | res.status(403).json({message: "Invalid password"}) 65 | return 66 | } 67 | 68 | const token = jwt.sign({ 69 | userId: user.id, 70 | role: user.role 71 | }, JWT_PASSWORD); 72 | 73 | res.json({ 74 | token 75 | }) 76 | } catch(e) { 77 | res.status(400).json({message: "Internal server error"}) 78 | } 79 | }) 80 | 81 | router.get("/elements", async (req, res) => { 82 | const elements = await client.element.findMany() 83 | 84 | res.json({elements: elements.map(e => ({ 85 | id: e.id, 86 | imageUrl: e.imageUrl, 87 | width: e.width, 88 | height: e.height, 89 | static: e.static 90 | }))}) 91 | }) 92 | 93 | router.get("/avatars", async (req, res) => { 94 | const avatars = await client.avatar.findMany() 95 | res.json({avatars: avatars.map(x => ({ 96 | id: x.id, 97 | imageUrl: x.imageUrl, 98 | name: x.name 99 | }))}) 100 | }) 101 | 102 | router.use("/user", userRouter) 103 | router.use("/space", spaceRouter) 104 | router.use("/admin", adminRouter) 105 | -------------------------------------------------------------------------------- /metaverse/apps/http/src/routes/v1/space.ts: -------------------------------------------------------------------------------- 1 | import { Router } from "express"; 2 | import client from "@repo/db/client"; 3 | import { userMiddleware } from "../../middleware/user"; 4 | import { AddElementSchema, CreateElementSchema, CreateSpaceSchema, DeleteElementSchema } from "../../types"; 5 | export const spaceRouter = Router(); 6 | 7 | spaceRouter.post("/", userMiddleware, async (req, res) => { 8 | console.log("endopibnt") 9 | const parsedData = CreateSpaceSchema.safeParse(req.body) 10 | if (!parsedData.success) { 11 | console.log(JSON.stringify(parsedData)) 12 | res.status(400).json({message: "Validation failed"}) 13 | return 14 | } 15 | 16 | if (!parsedData.data.mapId) { 17 | const space = await client.space.create({ 18 | data: { 19 | name: parsedData.data.name, 20 | width: parseInt(parsedData.data.dimensions.split("x")[0]), 21 | height: parseInt(parsedData.data.dimensions.split("x")[1]), 22 | creatorId: req.userId! 23 | } 24 | }); 25 | res.json({spaceId: space.id}) 26 | return; 27 | } 28 | 29 | const map = await client.map.findFirst({ 30 | where: { 31 | id: parsedData.data.mapId 32 | }, select: { 33 | mapElements: true, 34 | width: true, 35 | height: true 36 | } 37 | }) 38 | console.log("after") 39 | if (!map) { 40 | res.status(400).json({message: "Map not found"}) 41 | return 42 | } 43 | console.log("map.mapElements.length") 44 | console.log(map.mapElements.length) 45 | let space = await client.$transaction(async () => { 46 | const space = await client.space.create({ 47 | data: { 48 | name: parsedData.data.name, 49 | width: map.width, 50 | height: map.height, 51 | creatorId: req.userId!, 52 | } 53 | }); 54 | 55 | await client.spaceElements.createMany({ 56 | data: map.mapElements.map(e => ({ 57 | spaceId: space.id, 58 | elementId: e.elementId, 59 | x: e.x!, 60 | y: e.y! 61 | })) 62 | }) 63 | 64 | return space; 65 | 66 | }) 67 | console.log("space crated") 68 | res.json({spaceId: space.id}) 69 | }) 70 | 71 | 72 | spaceRouter.delete("/element", userMiddleware, async (req, res) => { 73 | console.log("spaceElement?.space1 ") 74 | const parsedData = DeleteElementSchema.safeParse(req.body) 75 | if (!parsedData.success) { 76 | res.status(400).json({message: "Validation failed"}) 77 | return 78 | } 79 | const spaceElement = await client.spaceElements.findFirst({ 80 | where: { 81 | id: parsedData.data.id 82 | }, 83 | include: { 84 | space: true 85 | } 86 | }) 87 | console.log(spaceElement?.space) 88 | console.log("spaceElement?.space") 89 | if (!spaceElement?.space.creatorId || spaceElement.space.creatorId !== req.userId) { 90 | res.status(403).json({message: "Unauthorized"}) 91 | return 92 | } 93 | await client.spaceElements.delete({ 94 | where: { 95 | id: parsedData.data.id 96 | } 97 | }) 98 | res.json({message: "Element deleted"}) 99 | }) 100 | 101 | spaceRouter.delete("/:spaceId", userMiddleware, async(req, res) => { 102 | console.log("req.params.spaceId", req.params.spaceId) 103 | const space = await client.space.findUnique({ 104 | where: { 105 | id: req.params.spaceId 106 | }, select: { 107 | creatorId: true 108 | } 109 | }) 110 | if (!space) { 111 | res.status(400).json({message: "Space not found"}) 112 | return 113 | } 114 | 115 | if (space.creatorId !== req.userId) { 116 | console.log("code should reach here") 117 | res.status(403).json({message: "Unauthorized"}) 118 | return 119 | } 120 | 121 | await client.space.delete({ 122 | where: { 123 | id: req.params.spaceId 124 | } 125 | }) 126 | res.json({message: "Space deleted"}) 127 | }) 128 | 129 | spaceRouter.get("/all", userMiddleware, async (req, res) => { 130 | const spaces = await client.space.findMany({ 131 | where: { 132 | creatorId: req.userId! 133 | } 134 | }); 135 | 136 | res.json({ 137 | spaces: spaces.map(s => ({ 138 | id: s.id, 139 | name: s.name, 140 | thumbnail: s.thumbnail, 141 | dimensions: `${s.width}x${s.height}`, 142 | })) 143 | }) 144 | 145 | 146 | }) 147 | 148 | spaceRouter.post("/element", userMiddleware, async (req, res) => { 149 | const parsedData = AddElementSchema.safeParse(req.body) 150 | if (!parsedData.success) { 151 | res.status(400).json({message: "Validation failed"}) 152 | return 153 | } 154 | const space = await client.space.findUnique({ 155 | where: { 156 | id: req.body.spaceId, 157 | creatorId: req.userId! 158 | }, select: { 159 | width: true, 160 | height: true 161 | } 162 | }) 163 | 164 | if(req.body.x < 0 || req.body.y < 0 || req.body.x > space?.width! || req.body.y > space?.height!) { 165 | res.status(400).json({message: "Point is outside of the boundary"}) 166 | return 167 | } 168 | 169 | if (!space) { 170 | res.status(400).json({message: "Space not found"}) 171 | return 172 | } 173 | await client.spaceElements.create({ 174 | data: { 175 | spaceId: req.body.spaceId, 176 | elementId: req.body.elementId, 177 | x: req.body.x, 178 | y: req.body.y 179 | } 180 | }) 181 | 182 | res.json({message: "Element added"}) 183 | }) 184 | 185 | spaceRouter.get("/:spaceId",async (req, res) => { 186 | const space = await client.space.findUnique({ 187 | where: { 188 | id: req.params.spaceId 189 | }, 190 | include: { 191 | elements: { 192 | include: { 193 | element: true 194 | } 195 | }, 196 | } 197 | }) 198 | 199 | if (!space) { 200 | res.status(400).json({message: "Space not found"}) 201 | return 202 | } 203 | 204 | res.json({ 205 | "dimensions": `${space.width}x${space.height}`, 206 | elements: space.elements.map(e => ({ 207 | id: e.id, 208 | element: { 209 | id: e.element.id, 210 | imageUrl: e.element.imageUrl, 211 | width: e.element.width, 212 | height: e.element.height, 213 | static: e.element.static 214 | }, 215 | x: e.x, 216 | y: e.y 217 | })), 218 | }) 219 | }) -------------------------------------------------------------------------------- /metaverse/apps/http/src/routes/v1/user.ts: -------------------------------------------------------------------------------- 1 | import { Router } from "express"; 2 | import { UpdateMetadataSchema } from "../../types"; 3 | import client from "@repo/db/client"; 4 | import { userMiddleware } from "../../middleware/user"; 5 | 6 | export const userRouter = Router(); 7 | 8 | userRouter.post("/metadata", userMiddleware, async (req, res) => { 9 | const parsedData = UpdateMetadataSchema.safeParse(req.body) 10 | if (!parsedData.success) { 11 | console.log("parsed data incorrect") 12 | res.status(400).json({message: "Validation failed"}) 13 | return 14 | } 15 | try { 16 | await client.user.update({ 17 | where: { 18 | id: req.userId 19 | }, 20 | data: { 21 | avatarId: parsedData.data.avatarId 22 | } 23 | }) 24 | res.json({message: "Metadata updated"}) 25 | } catch(e) { 26 | console.log("error") 27 | res.status(400).json({message: "Internal server error"}) 28 | } 29 | }) 30 | 31 | userRouter.get("/metadata/bulk", async (req, res) => { 32 | const userIdString = (req.query.ids ?? "[]") as string; 33 | const userIds = (userIdString).slice(1, userIdString?.length - 1).split(","); 34 | console.log(userIds) 35 | const metadata = await client.user.findMany({ 36 | where: { 37 | id: { 38 | in: userIds 39 | } 40 | }, select: { 41 | avatar: true, 42 | id: true 43 | } 44 | }) 45 | 46 | res.json({ 47 | avatars: metadata.map(m => ({ 48 | userId: m.id, 49 | avatarId: m.avatar?.imageUrl 50 | })) 51 | }) 52 | }) -------------------------------------------------------------------------------- /metaverse/apps/http/src/scrypt.ts: -------------------------------------------------------------------------------- 1 | import { randomBytes, scrypt, timingSafeEqual } from 'node:crypto'; 2 | 3 | /** 4 | * https://dev.to/advename/comment/24a9e 5 | */ 6 | const keyLength = 32; 7 | 8 | /** 9 | * Has a password or a secret with a password hashing algorithm (scrypt) 10 | * @param {string} password 11 | * @returns {string} The salt+hash 12 | */ 13 | export const hash = async (password: string): Promise => { 14 | return new Promise((resolve, reject) => { 15 | // generate random 16 bytes long salt - recommended by NodeJS Docs 16 | const salt = randomBytes(16).toString('hex'); 17 | 18 | scrypt(password, salt, keyLength, (error, derivedKey) => { 19 | if (error) reject(error); 20 | // derivedKey is of type Buffer 21 | resolve(`${salt}.${derivedKey.toString('hex')}`); 22 | }); 23 | }); 24 | }; 25 | 26 | /** 27 | * Compare a plain text password with a salt+hash password 28 | * @param {string} password The plain text password 29 | * @param {string} hash The hash+salt to check against 30 | * @returns {boolean} 31 | */ 32 | export const compare = async (password: string, hash: string): Promise => { 33 | return new Promise((resolve, reject) => { 34 | const [salt, hashKey] = hash.split('.'); 35 | // we need to pass buffer values to timingSafeEqual 36 | const hashKeyBuff = Buffer.from(hashKey, 'hex'); 37 | scrypt(password, salt, keyLength, (error, derivedKey) => { 38 | if (error) reject(error); 39 | // compare the new supplied password with the hashed password using timeSafeEqual 40 | resolve(timingSafeEqual(hashKeyBuff, derivedKey)); 41 | }); 42 | }); 43 | }; -------------------------------------------------------------------------------- /metaverse/apps/http/src/types/index.ts: -------------------------------------------------------------------------------- 1 | import z from "zod"; 2 | 3 | export const SignupSchema = z.object({ 4 | username: z.string(), 5 | password: z.string(), 6 | type: z.enum(["user", "admin"]), 7 | }) 8 | 9 | export const SigninSchema = z.object({ 10 | username: z.string(), 11 | password: z.string(), 12 | }) 13 | 14 | export const UpdateMetadataSchema = z.object({ 15 | avatarId: z.string() 16 | }) 17 | 18 | export const CreateSpaceSchema = z.object({ 19 | name: z.string(), 20 | dimensions: z.string().regex(/^[0-9]{1,4}x[0-9]{1,4}$/), 21 | mapId: z.string().optional(), 22 | }) 23 | 24 | export const DeleteElementSchema = z.object({ 25 | id: z.string(), 26 | }) 27 | 28 | export const AddElementSchema = z.object({ 29 | spaceId: z.string(), 30 | elementId: z.string(), 31 | x: z.number(), 32 | y: z.number(), 33 | }) 34 | 35 | export const CreateElementSchema = z.object({ 36 | imageUrl: z.string(), 37 | width: z.number(), 38 | height: z.number(), 39 | static: z.boolean(), 40 | }) 41 | 42 | export const UpdateElementSchema = z.object({ 43 | imageUrl: z.string(), 44 | }) 45 | 46 | export const CreateAvatarSchema = z.object({ 47 | name: z.string(), 48 | imageUrl: z.string(), 49 | }) 50 | 51 | export const CreateMapSchema = z.object({ 52 | thumbnail: z.string(), 53 | dimensions: z.string().regex(/^[0-9]{1,4}x[0-9]{1,4}$/), 54 | name: z.string(), 55 | defaultElements: z.array(z.object({ 56 | elementId: z.string(), 57 | x: z.number(), 58 | y: z.number(), 59 | })) 60 | }) 61 | 62 | 63 | declare global { 64 | namespace Express { 65 | export interface Request { 66 | role?: "Admin" | "User"; 67 | userId?: string; 68 | } 69 | } 70 | } -------------------------------------------------------------------------------- /metaverse/apps/http/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2016", 4 | /* Modules */ 5 | "rootDir": "./src", /* Specify the root folder within your source files. */ 6 | "module": "NodeNext", 7 | "moduleDetection": "force", 8 | "moduleResolution": "NodeNext", 9 | "outDir": "./dist", 10 | "esModuleInterop": true, 11 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ 12 | "strict": true, /* Enable all strict type-checking options. */ 13 | "skipLibCheck": true, 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /metaverse/apps/http/tsconfig.tsbuildinfo: -------------------------------------------------------------------------------- 1 | {"root":["./src/config.ts","./src/index.ts","./src/scrypt.ts","./src/middleware/admin.ts","./src/middleware/user.ts","./src/routes/v1/admin.ts","./src/routes/v1/index.ts","./src/routes/v1/space.ts","./src/routes/v1/user.ts","./src/types/index.ts"],"version":"5.6.3"} -------------------------------------------------------------------------------- /metaverse/apps/ws/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ws", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "scripts": { 6 | "build": "npx esbuild src/index.ts --bundle --outfile=dist/index.js --platform=node --tsconfig=tsconfig.json", 7 | "start": "node dist/index.js", 8 | "dev": "npm run build && npm run start" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "description": "", 14 | "dependencies": { 15 | "@repo/db": "workspace:*", 16 | "@types/jsonwebtoken": "^9.0.7", 17 | "@types/ws": "^8.5.12", 18 | "esbuild": "^0.24.0", 19 | "jsonwebtoken": "^9.0.2", 20 | "ws": "^8.18.0" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /metaverse/apps/ws/src/RoomManager.ts: -------------------------------------------------------------------------------- 1 | import type { User } from "./User"; 2 | import { OutgoingMessage } from "./types"; 3 | 4 | export class RoomManager { 5 | rooms: Map = new Map(); 6 | static instance: RoomManager; 7 | 8 | private constructor() { 9 | this.rooms = new Map(); 10 | } 11 | 12 | static getInstance() { 13 | if (!this.instance) { 14 | this.instance = new RoomManager(); 15 | } 16 | return this.instance; 17 | } 18 | 19 | public removeUser(user: User, spaceId: string) { 20 | if (!this.rooms.has(spaceId)) { 21 | return; 22 | } 23 | this.rooms.set(spaceId, (this.rooms.get(spaceId)?.filter((u) => u.id !== user.id) ?? [])); 24 | } 25 | 26 | public addUser(spaceId: string, user: User) { 27 | if (!this.rooms.has(spaceId)) { 28 | this.rooms.set(spaceId, [user]); 29 | return; 30 | } 31 | this.rooms.set(spaceId, [...(this.rooms.get(spaceId) ?? []), user]); 32 | } 33 | 34 | public broadcast(message: OutgoingMessage, user: User, roomId: string) { 35 | if (!this.rooms.has(roomId)) { 36 | return; 37 | } 38 | this.rooms.get(roomId)?.forEach((u) => { 39 | if (u.id !== user.id) { 40 | u.send(message); 41 | } 42 | }); 43 | } 44 | } -------------------------------------------------------------------------------- /metaverse/apps/ws/src/User.ts: -------------------------------------------------------------------------------- 1 | import { WebSocket } from "ws"; 2 | import { RoomManager } from "./RoomManager"; 3 | import { OutgoingMessage } from "./types"; 4 | import client from "@repo/db/client"; 5 | import jwt, { JwtPayload } from "jsonwebtoken"; 6 | import { JWT_PASSWORD } from "./config"; 7 | 8 | function getRandomString(length: number) { 9 | const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; 10 | let result = ""; 11 | for (let i = 0; i < length; i++) { 12 | result += characters.charAt(Math.floor(Math.random() * characters.length)); 13 | } 14 | return result; 15 | } 16 | 17 | export class User { 18 | public id: string; 19 | public userId?: string; 20 | private spaceId?: string; 21 | private x: number; 22 | private y: number; 23 | private ws: WebSocket; 24 | 25 | constructor(ws: WebSocket) { 26 | this.id = getRandomString(10); 27 | this.x = 0; 28 | this.y = 0; 29 | this.ws = ws; 30 | this.initHandlers() 31 | } 32 | 33 | initHandlers() { 34 | this.ws.on("message", async (data) => { 35 | console.log(data) 36 | const parsedData = JSON.parse(data.toString()); 37 | console.log(parsedData) 38 | console.log("parsedData") 39 | switch (parsedData.type) { 40 | case "join": 41 | console.log("jouin receiverdfd") 42 | const spaceId = parsedData.payload.spaceId; 43 | const token = parsedData.payload.token; 44 | const userId = (jwt.verify(token, JWT_PASSWORD) as JwtPayload).userId 45 | if (!userId) { 46 | this.ws.close() 47 | return 48 | } 49 | console.log("jouin receiverdfd 2") 50 | this.userId = userId 51 | const space = await client.space.findFirst({ 52 | where: { 53 | id: spaceId 54 | } 55 | }) 56 | console.log("jouin receiverdfd 3") 57 | if (!space) { 58 | this.ws.close() 59 | return; 60 | } 61 | console.log("jouin receiverdfd 4") 62 | this.spaceId = spaceId 63 | RoomManager.getInstance().addUser(spaceId, this); 64 | this.x = Math.floor(Math.random() * space?.width); 65 | this.y = Math.floor(Math.random() * space?.height); 66 | this.send({ 67 | type: "space-joined", 68 | payload: { 69 | spawn: { 70 | x: this.x, 71 | y: this.y 72 | }, 73 | users: RoomManager.getInstance().rooms.get(spaceId)?.filter(x => x.id !== this.id)?.map((u) => ({id: u.id})) ?? [] 74 | } 75 | }); 76 | console.log("jouin receiverdf5") 77 | RoomManager.getInstance().broadcast({ 78 | type: "user-joined", 79 | payload: { 80 | userId: this.userId, 81 | x: this.x, 82 | y: this.y 83 | } 84 | }, this, this.spaceId!); 85 | break; 86 | case "move": 87 | const moveX = parsedData.payload.x; 88 | const moveY = parsedData.payload.y; 89 | const xDisplacement = Math.abs(this.x - moveX); 90 | const yDisplacement = Math.abs(this.y - moveY); 91 | if ((xDisplacement == 1 && yDisplacement== 0) || (xDisplacement == 0 && yDisplacement == 1)) { 92 | this.x = moveX; 93 | this.y = moveY; 94 | RoomManager.getInstance().broadcast({ 95 | type: "movement", 96 | payload: { 97 | x: this.x, 98 | y: this.y 99 | } 100 | }, this, this.spaceId!); 101 | return; 102 | } 103 | 104 | this.send({ 105 | type: "movement-rejected", 106 | payload: { 107 | x: this.x, 108 | y: this.y 109 | } 110 | }); 111 | 112 | } 113 | }); 114 | } 115 | 116 | destroy() { 117 | RoomManager.getInstance().broadcast({ 118 | type: "user-left", 119 | payload: { 120 | userId: this.userId 121 | } 122 | }, this, this.spaceId!); 123 | RoomManager.getInstance().removeUser(this, this.spaceId!); 124 | } 125 | 126 | send(payload: OutgoingMessage) { 127 | this.ws.send(JSON.stringify(payload)); 128 | } 129 | } -------------------------------------------------------------------------------- /metaverse/apps/ws/src/config.ts: -------------------------------------------------------------------------------- 1 | export const JWT_PASSWORD = "123kasdk123" -------------------------------------------------------------------------------- /metaverse/apps/ws/src/index.ts: -------------------------------------------------------------------------------- 1 | import { WebSocketServer } from 'ws'; 2 | import { User } from './User'; 3 | 4 | const wss = new WebSocketServer({ port: 3001 }); 5 | 6 | wss.on('connection', function connection(ws) { 7 | console.log("yser connected") 8 | let user = new User(ws); 9 | ws.on('error', console.error); 10 | 11 | ws.on('close', () => { 12 | user?.destroy(); 13 | }); 14 | }); -------------------------------------------------------------------------------- /metaverse/apps/ws/src/types.ts: -------------------------------------------------------------------------------- 1 | export type OutgoingMessage = any; -------------------------------------------------------------------------------- /metaverse/apps/ws/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2016", 4 | /* Modules */ 5 | "rootDir": "./src", /* Specify the root folder within your source files. */ 6 | "module": "NodeNext", 7 | "moduleDetection": "force", 8 | "moduleResolution": "NodeNext", 9 | "outDir": "./dist", 10 | "esModuleInterop": true, 11 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ 12 | "strict": true, /* Enable all strict type-checking options. */ 13 | "skipLibCheck": true, 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /metaverse/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "metaverse", 3 | "private": true, 4 | "scripts": { 5 | "build": "turbo build", 6 | "dev": "turbo dev", 7 | "lint": "turbo lint", 8 | "format": "prettier --write \"**/*.{ts,tsx,md}\"" 9 | }, 10 | "devDependencies": { 11 | "prettier": "^3.2.5", 12 | "turbo": "^2.2.3", 13 | "typescript": "5.5.4" 14 | }, 15 | "packageManager": "pnpm@8.15.6", 16 | "engines": { 17 | "node": ">=18" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /metaverse/packages/db/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | # Keep environment variables out of version control 3 | .env 4 | -------------------------------------------------------------------------------- /metaverse/packages/db/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@repo/db", 3 | "version": "1.0.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "@repo/db", 9 | "version": "1.0.0", 10 | "license": "ISC", 11 | "dependencies": { 12 | "@prisma/client": "^5.21.1", 13 | "prisma": "^5.21.1", 14 | "typescript": "^5.6.3" 15 | } 16 | }, 17 | "node_modules/@prisma/client": { 18 | "version": "5.21.1", 19 | "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.21.1.tgz", 20 | "integrity": "sha512-3n+GgbAZYjaS/k0M03yQsQfR1APbr411r74foknnsGpmhNKBG49VuUkxIU6jORgvJPChoD4WC4PqoHImN1FP0w==", 21 | "hasInstallScript": true, 22 | "license": "Apache-2.0", 23 | "engines": { 24 | "node": ">=16.13" 25 | }, 26 | "peerDependencies": { 27 | "prisma": "*" 28 | }, 29 | "peerDependenciesMeta": { 30 | "prisma": { 31 | "optional": true 32 | } 33 | } 34 | }, 35 | "node_modules/@prisma/debug": { 36 | "version": "5.21.1", 37 | "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.21.1.tgz", 38 | "integrity": "sha512-uY8SAhcnORhvgtOrNdvWS98Aq/nkQ9QDUxrWAgW8XrCZaI3j2X7zb7Xe6GQSh6xSesKffFbFlkw0c2luHQviZA==", 39 | "license": "Apache-2.0" 40 | }, 41 | "node_modules/@prisma/engines": { 42 | "version": "5.21.1", 43 | "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.21.1.tgz", 44 | "integrity": "sha512-hGVTldUkIkTwoV8//hmnAAiAchi4oMEKD3aW5H2RrnI50tTdwza7VQbTTAyN3OIHWlK5DVg6xV7X8N/9dtOydA==", 45 | "hasInstallScript": true, 46 | "license": "Apache-2.0", 47 | "dependencies": { 48 | "@prisma/debug": "5.21.1", 49 | "@prisma/engines-version": "5.21.1-1.bf0e5e8a04cada8225617067eaa03d041e2bba36", 50 | "@prisma/fetch-engine": "5.21.1", 51 | "@prisma/get-platform": "5.21.1" 52 | } 53 | }, 54 | "node_modules/@prisma/engines-version": { 55 | "version": "5.21.1-1.bf0e5e8a04cada8225617067eaa03d041e2bba36", 56 | "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.21.1-1.bf0e5e8a04cada8225617067eaa03d041e2bba36.tgz", 57 | "integrity": "sha512-qvnEflL0//lh44S/T9NcvTMxfyowNeUxTunPcDfKPjyJNrCNf2F1zQLcUv5UHAruECpX+zz21CzsC7V2xAeM7Q==", 58 | "license": "Apache-2.0" 59 | }, 60 | "node_modules/@prisma/fetch-engine": { 61 | "version": "5.21.1", 62 | "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.21.1.tgz", 63 | "integrity": "sha512-70S31vgpCGcp9J+mh/wHtLCkVezLUqe/fGWk3J3JWZIN7prdYSlr1C0niaWUyNK2VflLXYi8kMjAmSxUVq6WGQ==", 64 | "license": "Apache-2.0", 65 | "dependencies": { 66 | "@prisma/debug": "5.21.1", 67 | "@prisma/engines-version": "5.21.1-1.bf0e5e8a04cada8225617067eaa03d041e2bba36", 68 | "@prisma/get-platform": "5.21.1" 69 | } 70 | }, 71 | "node_modules/@prisma/get-platform": { 72 | "version": "5.21.1", 73 | "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.21.1.tgz", 74 | "integrity": "sha512-sRxjL3Igst3ct+e8ya/x//cDXmpLbZQ5vfps2N4tWl4VGKQAmym77C/IG/psSMsQKszc8uFC/q1dgmKFLUgXZQ==", 75 | "license": "Apache-2.0", 76 | "dependencies": { 77 | "@prisma/debug": "5.21.1" 78 | } 79 | }, 80 | "node_modules/fsevents": { 81 | "version": "2.3.3", 82 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", 83 | "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", 84 | "hasInstallScript": true, 85 | "license": "MIT", 86 | "optional": true, 87 | "os": [ 88 | "darwin" 89 | ], 90 | "engines": { 91 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 92 | } 93 | }, 94 | "node_modules/prisma": { 95 | "version": "5.21.1", 96 | "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.21.1.tgz", 97 | "integrity": "sha512-PB+Iqzld/uQBPaaw2UVIk84kb0ITsLajzsxzsadxxl54eaU5Gyl2/L02ysivHxK89t7YrfQJm+Ggk37uvM70oQ==", 98 | "hasInstallScript": true, 99 | "license": "Apache-2.0", 100 | "dependencies": { 101 | "@prisma/engines": "5.21.1" 102 | }, 103 | "bin": { 104 | "prisma": "build/index.js" 105 | }, 106 | "engines": { 107 | "node": ">=16.13" 108 | }, 109 | "optionalDependencies": { 110 | "fsevents": "2.3.3" 111 | } 112 | }, 113 | "node_modules/typescript": { 114 | "version": "5.6.3", 115 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", 116 | "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", 117 | "license": "Apache-2.0", 118 | "bin": { 119 | "tsc": "bin/tsc", 120 | "tsserver": "bin/tsserver" 121 | }, 122 | "engines": { 123 | "node": ">=14.17" 124 | } 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /metaverse/packages/db/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@repo/db", 3 | "version": "1.0.0", 4 | "private": true, 5 | "scripts": { 6 | "build": "tsc -b" 7 | }, 8 | "exports": { 9 | "./client": "./src/index.ts" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "description": "", 15 | "dependencies": { 16 | "@prisma/client": "^5.21.1", 17 | "prisma": "^5.21.1", 18 | "typescript": "^5.6.3" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /metaverse/packages/db/prisma/migrations/20241030155258_init/migration.sql: -------------------------------------------------------------------------------- 1 | -- CreateEnum 2 | CREATE TYPE "Role" AS ENUM ('Admin', 'User'); 3 | 4 | -- CreateTable 5 | CREATE TABLE "User" ( 6 | "id" TEXT NOT NULL, 7 | "username" TEXT NOT NULL, 8 | "password" TEXT NOT NULL, 9 | "avatarId" TEXT NOT NULL, 10 | "role" "Role" NOT NULL, 11 | 12 | CONSTRAINT "User_pkey" PRIMARY KEY ("id") 13 | ); 14 | 15 | -- CreateTable 16 | CREATE TABLE "Space" ( 17 | "id" TEXT NOT NULL, 18 | "name" TEXT NOT NULL, 19 | "width" INTEGER NOT NULL, 20 | "height" INTEGER, 21 | "thumbnail" TEXT, 22 | "creatorId" TEXT NOT NULL, 23 | 24 | CONSTRAINT "Space_pkey" PRIMARY KEY ("id") 25 | ); 26 | 27 | -- CreateTable 28 | CREATE TABLE "spaceElements" ( 29 | "id" TEXT NOT NULL, 30 | "elementId" TEXT NOT NULL, 31 | "spaceId" TEXT NOT NULL, 32 | "x" INTEGER NOT NULL, 33 | "y" INTEGER NOT NULL, 34 | 35 | CONSTRAINT "spaceElements_pkey" PRIMARY KEY ("id") 36 | ); 37 | 38 | -- CreateTable 39 | CREATE TABLE "Element" ( 40 | "id" TEXT NOT NULL, 41 | "width" INTEGER NOT NULL, 42 | "height" INTEGER NOT NULL, 43 | "imageUrl" TEXT NOT NULL, 44 | 45 | CONSTRAINT "Element_pkey" PRIMARY KEY ("id") 46 | ); 47 | 48 | -- CreateTable 49 | CREATE TABLE "Map" ( 50 | "id" TEXT NOT NULL, 51 | "width" INTEGER NOT NULL, 52 | "height" INTEGER NOT NULL, 53 | "name" TEXT NOT NULL, 54 | 55 | CONSTRAINT "Map_pkey" PRIMARY KEY ("id") 56 | ); 57 | 58 | -- CreateTable 59 | CREATE TABLE "MapElements" ( 60 | "id" TEXT NOT NULL, 61 | "mapId" TEXT NOT NULL, 62 | "elementId" TEXT NOT NULL, 63 | "x" INTEGER, 64 | "y" INTEGER, 65 | 66 | CONSTRAINT "MapElements_pkey" PRIMARY KEY ("id") 67 | ); 68 | 69 | -- CreateTable 70 | CREATE TABLE "Avatar" ( 71 | "id" TEXT NOT NULL, 72 | "imageUrl" TEXT, 73 | "name" TEXT, 74 | 75 | CONSTRAINT "Avatar_pkey" PRIMARY KEY ("id") 76 | ); 77 | 78 | -- CreateIndex 79 | CREATE UNIQUE INDEX "User_id_key" ON "User"("id"); 80 | 81 | -- CreateIndex 82 | CREATE UNIQUE INDEX "User_username_key" ON "User"("username"); 83 | 84 | -- CreateIndex 85 | CREATE UNIQUE INDEX "User_password_key" ON "User"("password"); 86 | 87 | -- CreateIndex 88 | CREATE UNIQUE INDEX "Space_id_key" ON "Space"("id"); 89 | 90 | -- CreateIndex 91 | CREATE UNIQUE INDEX "spaceElements_id_key" ON "spaceElements"("id"); 92 | 93 | -- CreateIndex 94 | CREATE UNIQUE INDEX "Element_id_key" ON "Element"("id"); 95 | 96 | -- CreateIndex 97 | CREATE UNIQUE INDEX "Map_id_key" ON "Map"("id"); 98 | 99 | -- CreateIndex 100 | CREATE UNIQUE INDEX "MapElements_id_key" ON "MapElements"("id"); 101 | 102 | -- CreateIndex 103 | CREATE UNIQUE INDEX "Avatar_id_key" ON "Avatar"("id"); 104 | 105 | -- AddForeignKey 106 | ALTER TABLE "User" ADD CONSTRAINT "User_avatarId_fkey" FOREIGN KEY ("avatarId") REFERENCES "Avatar"("id") ON DELETE RESTRICT ON UPDATE CASCADE; 107 | 108 | -- AddForeignKey 109 | ALTER TABLE "Space" ADD CONSTRAINT "Space_creatorId_fkey" FOREIGN KEY ("creatorId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; 110 | 111 | -- AddForeignKey 112 | ALTER TABLE "spaceElements" ADD CONSTRAINT "spaceElements_spaceId_fkey" FOREIGN KEY ("spaceId") REFERENCES "Space"("id") ON DELETE RESTRICT ON UPDATE CASCADE; 113 | 114 | -- AddForeignKey 115 | ALTER TABLE "spaceElements" ADD CONSTRAINT "spaceElements_elementId_fkey" FOREIGN KEY ("elementId") REFERENCES "Element"("id") ON DELETE RESTRICT ON UPDATE CASCADE; 116 | 117 | -- AddForeignKey 118 | ALTER TABLE "MapElements" ADD CONSTRAINT "MapElements_mapId_fkey" FOREIGN KEY ("mapId") REFERENCES "Map"("id") ON DELETE RESTRICT ON UPDATE CASCADE; 119 | 120 | -- AddForeignKey 121 | ALTER TABLE "MapElements" ADD CONSTRAINT "MapElements_elementId_fkey" FOREIGN KEY ("elementId") REFERENCES "Element"("id") ON DELETE RESTRICT ON UPDATE CASCADE; 122 | -------------------------------------------------------------------------------- /metaverse/packages/db/prisma/migrations/20241030164544_made_password_non_unique/migration.sql: -------------------------------------------------------------------------------- 1 | -- DropIndex 2 | DROP INDEX "User_password_key"; 3 | -------------------------------------------------------------------------------- /metaverse/packages/db/prisma/migrations/20241030164722_made_avatar_optional/migration.sql: -------------------------------------------------------------------------------- 1 | -- DropForeignKey 2 | ALTER TABLE "User" DROP CONSTRAINT "User_avatarId_fkey"; 3 | 4 | -- AlterTable 5 | ALTER TABLE "User" ALTER COLUMN "avatarId" DROP NOT NULL; 6 | 7 | -- AddForeignKey 8 | ALTER TABLE "User" ADD CONSTRAINT "User_avatarId_fkey" FOREIGN KEY ("avatarId") REFERENCES "Avatar"("id") ON DELETE SET NULL ON UPDATE CASCADE; 9 | -------------------------------------------------------------------------------- /metaverse/packages/db/prisma/migrations/20241031112104_add_static/migration.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Warnings: 3 | 4 | - Added the required column `static` to the `Element` table without a default value. This is not possible if the table is not empty. 5 | - Made the column `height` on table `Space` required. This step will fail if there are existing NULL values in that column. 6 | 7 | */ 8 | -- AlterTable 9 | ALTER TABLE "Element" ADD COLUMN "static" BOOLEAN NOT NULL; 10 | 11 | -- AlterTable 12 | ALTER TABLE "Space" ALTER COLUMN "height" SET NOT NULL; 13 | -------------------------------------------------------------------------------- /metaverse/packages/db/prisma/migrations/20241031112726_add_thumbnail/migration.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Warnings: 3 | 4 | - Added the required column `thumbnail` to the `Map` table without a default value. This is not possible if the table is not empty. 5 | 6 | */ 7 | -- AlterTable 8 | ALTER TABLE "Map" ADD COLUMN "thumbnail" TEXT NOT NULL; 9 | -------------------------------------------------------------------------------- /metaverse/packages/db/prisma/migrations/migration_lock.toml: -------------------------------------------------------------------------------- 1 | # Please do not edit this file manually 2 | # It should be added in your version-control system (i.e. Git) 3 | provider = "postgresql" -------------------------------------------------------------------------------- /metaverse/packages/db/prisma/schema.prisma: -------------------------------------------------------------------------------- 1 | // This is your Prisma schema file, 2 | // learn more about it in the docs: https://pris.ly/d/prisma-schema 3 | 4 | // Looking for ways to speed up your queries, or scale easily with your serverless or edge functions? 5 | // Try Prisma Accelerate: https://pris.ly/cli/accelerate-init 6 | 7 | generator client { 8 | provider = "prisma-client-js" 9 | } 10 | 11 | datasource db { 12 | provider = "postgresql" 13 | url = env("DATABASE_URL") 14 | } 15 | 16 | model User { 17 | id String @id @unique @default(cuid()) 18 | username String @unique 19 | password String 20 | avatarId String? 21 | role Role 22 | spaces Space[] 23 | avatar Avatar? @relation(fields: [avatarId], references: [id]) 24 | } 25 | 26 | model Space { 27 | id String @id @unique @default(cuid()) 28 | name String 29 | width Int 30 | height Int 31 | thumbnail String? 32 | creatorId String 33 | creator User @relation(fields: [creatorId], references: [id]) 34 | elements spaceElements[] 35 | } 36 | 37 | model spaceElements { 38 | id String @id @unique @default(cuid()) 39 | elementId String 40 | spaceId String 41 | x Int 42 | y Int 43 | space Space @relation(fields: [spaceId], references: [id]) 44 | element Element @relation(fields: [elementId], references: [id]) 45 | } 46 | 47 | model Element { 48 | id String @id @unique @default(cuid()) 49 | width Int 50 | height Int 51 | static Boolean 52 | imageUrl String 53 | spaces spaceElements[] 54 | mapElements MapElements[] 55 | } 56 | 57 | model Map { 58 | id String @id @unique @default(cuid()) 59 | width Int 60 | height Int 61 | name String 62 | thumbnail String 63 | mapElements MapElements[] 64 | } 65 | 66 | model MapElements { 67 | id String @id @unique @default(cuid()) 68 | mapId String 69 | elementId String 70 | x Int? 71 | y Int? 72 | map Map @relation(fields: [mapId], references: [id]) 73 | element Element @relation(fields: [elementId], references: [id]) 74 | } 75 | 76 | model Avatar { 77 | id String @id @unique @default(cuid()) 78 | imageUrl String? 79 | name String? 80 | users User[] 81 | } 82 | 83 | enum Role { 84 | Admin 85 | User 86 | } 87 | -------------------------------------------------------------------------------- /metaverse/packages/db/src/index.ts: -------------------------------------------------------------------------------- 1 | import { PrismaClient } from "@prisma/client" 2 | 3 | export default new PrismaClient(); -------------------------------------------------------------------------------- /metaverse/packages/db/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig to read more about this file */ 4 | 5 | /* Projects */ 6 | // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ 7 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ 8 | // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ 9 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ 10 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ 11 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ 12 | 13 | /* Language and Environment */ 14 | "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ 15 | // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ 16 | // "jsx": "preserve", /* Specify what JSX code is generated. */ 17 | // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ 18 | // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ 19 | // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ 20 | // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ 21 | // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ 22 | // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ 23 | // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ 24 | // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ 25 | // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ 26 | 27 | /* Modules */ 28 | "module": "commonjs", /* Specify what module code is generated. */ 29 | "rootDir": "./src", /* Specify the root folder within your source files. */ 30 | // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ 31 | // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ 32 | // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ 33 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ 34 | // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ 35 | // "types": [], /* Specify type package names to be included without being referenced in a source file. */ 36 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 37 | // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ 38 | // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ 39 | // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ 40 | // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ 41 | // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ 42 | // "resolveJsonModule": true, /* Enable importing .json files. */ 43 | // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ 44 | // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ 45 | 46 | /* JavaScript Support */ 47 | // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ 48 | // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ 49 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ 50 | 51 | /* Emit */ 52 | // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ 53 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */ 54 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ 55 | // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ 56 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ 57 | // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ 58 | "outDir": "./dist", /* Specify an output folder for all emitted files. */ 59 | // "removeComments": true, /* Disable emitting comments. */ 60 | // "noEmit": true, /* Disable emitting files from a compilation. */ 61 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ 62 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ 63 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ 64 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 65 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ 66 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ 67 | // "newLine": "crlf", /* Set the newline character for emitting files. */ 68 | // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ 69 | // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ 70 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ 71 | // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ 72 | // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ 73 | 74 | /* Interop Constraints */ 75 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ 76 | // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ 77 | // "isolatedDeclarations": true, /* Require sufficient annotation on exports so other tools can trivially generate declaration files. */ 78 | // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ 79 | "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ 80 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ 81 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ 82 | 83 | /* Type Checking */ 84 | "strict": true, /* Enable all strict type-checking options. */ 85 | // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ 86 | // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ 87 | // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ 88 | // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ 89 | // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ 90 | // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ 91 | // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ 92 | // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ 93 | // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ 94 | // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ 95 | // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ 96 | // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ 97 | // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ 98 | // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ 99 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ 100 | // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ 101 | // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ 102 | // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ 103 | 104 | /* Completeness */ 105 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ 106 | "skipLibCheck": true, /* Skip type checking all .d.ts files. */ 107 | "composite": true 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /metaverse/packages/db/tsconfig.tsbuildinfo: -------------------------------------------------------------------------------- 1 | {"fileNames":["../../node_modules/.pnpm/typescript@5.6.3/node_modules/typescript/lib/lib.es5.d.ts","../../node_modules/.pnpm/typescript@5.6.3/node_modules/typescript/lib/lib.es2015.d.ts","../../node_modules/.pnpm/typescript@5.6.3/node_modules/typescript/lib/lib.es2016.d.ts","../../node_modules/.pnpm/typescript@5.6.3/node_modules/typescript/lib/lib.es2017.d.ts","../../node_modules/.pnpm/typescript@5.6.3/node_modules/typescript/lib/lib.es2018.d.ts","../../node_modules/.pnpm/typescript@5.6.3/node_modules/typescript/lib/lib.es2019.d.ts","../../node_modules/.pnpm/typescript@5.6.3/node_modules/typescript/lib/lib.es2020.d.ts","../../node_modules/.pnpm/typescript@5.6.3/node_modules/typescript/lib/lib.dom.d.ts","../../node_modules/.pnpm/typescript@5.6.3/node_modules/typescript/lib/lib.dom.iterable.d.ts","../../node_modules/.pnpm/typescript@5.6.3/node_modules/typescript/lib/lib.webworker.importscripts.d.ts","../../node_modules/.pnpm/typescript@5.6.3/node_modules/typescript/lib/lib.scripthost.d.ts","../../node_modules/.pnpm/typescript@5.6.3/node_modules/typescript/lib/lib.es2015.core.d.ts","../../node_modules/.pnpm/typescript@5.6.3/node_modules/typescript/lib/lib.es2015.collection.d.ts","../../node_modules/.pnpm/typescript@5.6.3/node_modules/typescript/lib/lib.es2015.generator.d.ts","../../node_modules/.pnpm/typescript@5.6.3/node_modules/typescript/lib/lib.es2015.iterable.d.ts","../../node_modules/.pnpm/typescript@5.6.3/node_modules/typescript/lib/lib.es2015.promise.d.ts","../../node_modules/.pnpm/typescript@5.6.3/node_modules/typescript/lib/lib.es2015.proxy.d.ts","../../node_modules/.pnpm/typescript@5.6.3/node_modules/typescript/lib/lib.es2015.reflect.d.ts","../../node_modules/.pnpm/typescript@5.6.3/node_modules/typescript/lib/lib.es2015.symbol.d.ts","../../node_modules/.pnpm/typescript@5.6.3/node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../../node_modules/.pnpm/typescript@5.6.3/node_modules/typescript/lib/lib.es2016.array.include.d.ts","../../node_modules/.pnpm/typescript@5.6.3/node_modules/typescript/lib/lib.es2016.intl.d.ts","../../node_modules/.pnpm/typescript@5.6.3/node_modules/typescript/lib/lib.es2017.date.d.ts","../../node_modules/.pnpm/typescript@5.6.3/node_modules/typescript/lib/lib.es2017.object.d.ts","../../node_modules/.pnpm/typescript@5.6.3/node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../../node_modules/.pnpm/typescript@5.6.3/node_modules/typescript/lib/lib.es2017.string.d.ts","../../node_modules/.pnpm/typescript@5.6.3/node_modules/typescript/lib/lib.es2017.intl.d.ts","../../node_modules/.pnpm/typescript@5.6.3/node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../../node_modules/.pnpm/typescript@5.6.3/node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../../node_modules/.pnpm/typescript@5.6.3/node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../../node_modules/.pnpm/typescript@5.6.3/node_modules/typescript/lib/lib.es2018.intl.d.ts","../../node_modules/.pnpm/typescript@5.6.3/node_modules/typescript/lib/lib.es2018.promise.d.ts","../../node_modules/.pnpm/typescript@5.6.3/node_modules/typescript/lib/lib.es2018.regexp.d.ts","../../node_modules/.pnpm/typescript@5.6.3/node_modules/typescript/lib/lib.es2019.array.d.ts","../../node_modules/.pnpm/typescript@5.6.3/node_modules/typescript/lib/lib.es2019.object.d.ts","../../node_modules/.pnpm/typescript@5.6.3/node_modules/typescript/lib/lib.es2019.string.d.ts","../../node_modules/.pnpm/typescript@5.6.3/node_modules/typescript/lib/lib.es2019.symbol.d.ts","../../node_modules/.pnpm/typescript@5.6.3/node_modules/typescript/lib/lib.es2019.intl.d.ts","../../node_modules/.pnpm/typescript@5.6.3/node_modules/typescript/lib/lib.es2020.bigint.d.ts","../../node_modules/.pnpm/typescript@5.6.3/node_modules/typescript/lib/lib.es2020.date.d.ts","../../node_modules/.pnpm/typescript@5.6.3/node_modules/typescript/lib/lib.es2020.promise.d.ts","../../node_modules/.pnpm/typescript@5.6.3/node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../../node_modules/.pnpm/typescript@5.6.3/node_modules/typescript/lib/lib.es2020.string.d.ts","../../node_modules/.pnpm/typescript@5.6.3/node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../../node_modules/.pnpm/typescript@5.6.3/node_modules/typescript/lib/lib.es2020.intl.d.ts","../../node_modules/.pnpm/typescript@5.6.3/node_modules/typescript/lib/lib.es2020.number.d.ts","../../node_modules/.pnpm/typescript@5.6.3/node_modules/typescript/lib/lib.esnext.intl.d.ts","../../node_modules/.pnpm/typescript@5.6.3/node_modules/typescript/lib/lib.decorators.d.ts","../../node_modules/.pnpm/typescript@5.6.3/node_modules/typescript/lib/lib.decorators.legacy.d.ts","../../node_modules/.pnpm/typescript@5.6.3/node_modules/typescript/lib/lib.es2016.full.d.ts","../../node_modules/.pnpm/@prisma+client@5.21.1_prisma@5.21.1/node_modules/@prisma/client/runtime/library.d.ts","../../node_modules/.pnpm/@prisma+client@5.21.1_prisma@5.21.1/node_modules/.prisma/client/index.d.ts","../../node_modules/.pnpm/@prisma+client@5.21.1_prisma@5.21.1/node_modules/.prisma/client/default.d.ts","../../node_modules/.pnpm/@prisma+client@5.21.1_prisma@5.21.1/node_modules/@prisma/client/default.d.ts","./src/index.ts","../../node_modules/.pnpm/@types+eslint@8.56.12/node_modules/@types/eslint/helpers.d.ts","../../node_modules/.pnpm/@types+estree@1.0.5/node_modules/@types/estree/index.d.ts","../../node_modules/.pnpm/@types+json-schema@7.0.15/node_modules/@types/json-schema/index.d.ts","../../node_modules/.pnpm/@types+eslint@8.56.12/node_modules/@types/eslint/index.d.ts","../../../../node_modules/@types/node/assert.d.ts","../../../../node_modules/@types/node/assert/strict.d.ts","../../../../node_modules/@types/node/globals.d.ts","../../../../node_modules/@types/node/async_hooks.d.ts","../../../../node_modules/@types/node/buffer.d.ts","../../../../node_modules/@types/node/child_process.d.ts","../../../../node_modules/@types/node/cluster.d.ts","../../../../node_modules/@types/node/console.d.ts","../../../../node_modules/@types/node/constants.d.ts","../../../../node_modules/@types/node/crypto.d.ts","../../../../node_modules/@types/node/dgram.d.ts","../../../../node_modules/@types/node/diagnostics_channel.d.ts","../../../../node_modules/@types/node/dns.d.ts","../../../../node_modules/@types/node/dns/promises.d.ts","../../../../node_modules/@types/node/domain.d.ts","../../../../node_modules/@types/node/dom-events.d.ts","../../../../node_modules/@types/node/events.d.ts","../../../../node_modules/@types/node/fs.d.ts","../../../../node_modules/@types/node/fs/promises.d.ts","../../../../node_modules/@types/node/http.d.ts","../../../../node_modules/@types/node/http2.d.ts","../../../../node_modules/@types/node/https.d.ts","../../../../node_modules/@types/node/inspector.d.ts","../../../../node_modules/@types/node/module.d.ts","../../../../node_modules/@types/node/net.d.ts","../../../../node_modules/@types/node/os.d.ts","../../../../node_modules/@types/node/path.d.ts","../../../../node_modules/@types/node/perf_hooks.d.ts","../../../../node_modules/@types/node/process.d.ts","../../../../node_modules/@types/node/punycode.d.ts","../../../../node_modules/@types/node/querystring.d.ts","../../../../node_modules/@types/node/readline.d.ts","../../../../node_modules/@types/node/readline/promises.d.ts","../../../../node_modules/@types/node/repl.d.ts","../../../../node_modules/@types/node/stream.d.ts","../../../../node_modules/@types/node/stream/promises.d.ts","../../../../node_modules/@types/node/stream/consumers.d.ts","../../../../node_modules/@types/node/stream/web.d.ts","../../../../node_modules/@types/node/string_decoder.d.ts","../../../../node_modules/@types/node/test.d.ts","../../../../node_modules/@types/node/timers.d.ts","../../../../node_modules/@types/node/timers/promises.d.ts","../../../../node_modules/@types/node/tls.d.ts","../../../../node_modules/@types/node/trace_events.d.ts","../../../../node_modules/@types/node/tty.d.ts","../../../../node_modules/@types/node/url.d.ts","../../../../node_modules/@types/node/util.d.ts","../../../../node_modules/@types/node/v8.d.ts","../../../../node_modules/@types/node/vm.d.ts","../../../../node_modules/@types/node/wasi.d.ts","../../../../node_modules/@types/node/worker_threads.d.ts","../../../../node_modules/@types/node/zlib.d.ts","../../../../node_modules/@types/node/globals.global.d.ts","../../../../node_modules/@types/node/index.d.ts","../../../../node_modules/@types/connect/index.d.ts","../../../../node_modules/@types/istanbul-lib-coverage/index.d.ts","../../../../node_modules/@types/istanbul-lib-report/index.d.ts","../../../../node_modules/@types/istanbul-reports/index.d.ts","../../../../node_modules/@types/node-forge/index.d.ts","../../../../node_modules/@types/stack-utils/index.d.ts","../../../../node_modules/@types/uuid/index.d.ts","../../../../node_modules/@types/ws/index.d.ts","../../../../node_modules/@types/yargs-parser/index.d.ts","../../../../node_modules/@types/yargs/index.d.ts"],"fileIdsList":[[52,106],[51,106],[53,106],[106],[56,57,58,106],[54,106],[79,106,113],[106,115],[106,116],[106,113],[60,106],[63,106],[64,69,97,106],[65,76,77,84,94,105,106],[65,66,76,84,106],[67,106],[68,69,77,85,106],[69,94,102,106],[70,72,76,84,106],[71,106],[72,73,106],[76,106],[74,76,106],[76,77,78,94,105,106],[76,77,78,91,94,97,106],[106,110],[72,79,84,94,105,106],[76,77,79,80,84,94,102,105,106],[79,81,94,102,105,106],[60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112],[76,82,106],[83,105,106],[72,76,84,94,106],[85,106],[86,106],[63,87,106],[88,104,106,110],[89,106],[90,106],[76,91,92,106],[91,93,106,108],[64,76,94,95,96,97,106],[64,94,96,106],[94,95,106],[97,106],[98,106],[76,100,101,106],[100,101,106],[69,84,94,102,106],[103,106],[84,104,106],[64,79,90,105,106],[69,106],[94,106,107],[106,108],[106,109],[64,69,76,78,87,94,105,106,108,110],[94,106,111],[76,79,81,84,94,102,105,106,111,113],[106,122]],"fileInfos":[{"version":"44e584d4f6444f58791784f1d530875970993129442a847597db702a073ca68c","affectsGlobalScope":true,"impliedFormat":1},{"version":"45b7ab580deca34ae9729e97c13cfd999df04416a79116c3bfb483804f85ded4","impliedFormat":1},{"version":"3facaf05f0c5fc569c5649dd359892c98a85557e3e0c847964caeb67076f4d75","impliedFormat":1},{"version":"9a68c0c07ae2fa71b44384a839b7b8d81662a236d4b9ac30916718f7510b1b2d","impliedFormat":1},{"version":"5e1c4c362065a6b95ff952c0eab010f04dcd2c3494e813b493ecfd4fcb9fc0d8","impliedFormat":1},{"version":"68d73b4a11549f9c0b7d352d10e91e5dca8faa3322bfb77b661839c42b1ddec7","impliedFormat":1},{"version":"5efce4fc3c29ea84e8928f97adec086e3dc876365e0982cc8479a07954a3efd4","impliedFormat":1},{"version":"9e8ca8ed051c2697578c023d9c29d6df689a083561feba5c14aedee895853999","affectsGlobalScope":true,"impliedFormat":1},{"version":"69e65d976bf166ce4a9e6f6c18f94d2424bf116e90837ace179610dbccad9b42","affectsGlobalScope":true,"impliedFormat":1},{"version":"80e18897e5884b6723488d4f5652167e7bb5024f946743134ecc4aa4ee731f89","affectsGlobalScope":true,"impliedFormat":1},{"version":"cd034f499c6cdca722b60c04b5b1b78e058487a7085a8e0d6fb50809947ee573","affectsGlobalScope":true,"impliedFormat":1},{"version":"6920e1448680767498a0b77c6a00a8e77d14d62c3da8967b171f1ddffa3c18e4","affectsGlobalScope":true,"impliedFormat":1},{"version":"dc2df20b1bcdc8c2d34af4926e2c3ab15ffe1160a63e58b7e09833f616efff44","affectsGlobalScope":true,"impliedFormat":1},{"version":"515d0b7b9bea2e31ea4ec968e9edd2c39d3eebf4a2d5cbd04e88639819ae3b71","affectsGlobalScope":true,"impliedFormat":1},{"version":"45d8ccb3dfd57355eb29749919142d4321a0aa4df6acdfc54e30433d7176600a","affectsGlobalScope":true,"impliedFormat":1},{"version":"0dc1e7ceda9b8b9b455c3a2d67b0412feab00bd2f66656cd8850e8831b08b537","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce691fb9e5c64efb9547083e4a34091bcbe5bdb41027e310ebba8f7d96a98671","affectsGlobalScope":true,"impliedFormat":1},{"version":"8d697a2a929a5fcb38b7a65594020fcef05ec1630804a33748829c5ff53640d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ff2a353abf8a80ee399af572debb8faab2d33ad38c4b4474cff7f26e7653b8d","affectsGlobalScope":true,"impliedFormat":1},{"version":"93495ff27b8746f55d19fcbcdbaccc99fd95f19d057aed1bd2c0cafe1335fbf0","affectsGlobalScope":true,"impliedFormat":1},{"version":"6fc23bb8c3965964be8c597310a2878b53a0306edb71d4b5a4dfe760186bcc01","affectsGlobalScope":true,"impliedFormat":1},{"version":"ea011c76963fb15ef1cdd7ce6a6808b46322c527de2077b6cfdf23ae6f5f9ec7","affectsGlobalScope":true,"impliedFormat":1},{"version":"38f0219c9e23c915ef9790ab1d680440d95419ad264816fa15009a8851e79119","affectsGlobalScope":true,"impliedFormat":1},{"version":"69ab18c3b76cd9b1be3d188eaf8bba06112ebbe2f47f6c322b5105a6fbc45a2e","affectsGlobalScope":true,"impliedFormat":1},{"version":"4738f2420687fd85629c9efb470793bb753709c2379e5f85bc1815d875ceadcd","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f11ff796926e0832f9ae148008138ad583bd181899ab7dd768a2666700b1893","affectsGlobalScope":true,"impliedFormat":1},{"version":"4de680d5bb41c17f7f68e0419412ca23c98d5749dcaaea1896172f06435891fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"9fc46429fbe091ac5ad2608c657201eb68b6f1b8341bd6d670047d32ed0a88fa","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac9538681b19688c8eae65811b329d3744af679e0bdfa5d842d0e32524c73e1c","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a969edff4bd52585473d24995c5ef223f6652d6ef46193309b3921d65dd4376","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e9fbd7030c440b33d021da145d3232984c8bb7916f277e8ffd3dc2e3eae2bdb","affectsGlobalScope":true,"impliedFormat":1},{"version":"811ec78f7fefcabbda4bfa93b3eb67d9ae166ef95f9bff989d964061cbf81a0c","affectsGlobalScope":true,"impliedFormat":1},{"version":"717937616a17072082152a2ef351cb51f98802fb4b2fdabd32399843875974ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"d7e7d9b7b50e5f22c915b525acc5a49a7a6584cf8f62d0569e557c5cfc4b2ac2","affectsGlobalScope":true,"impliedFormat":1},{"version":"71c37f4c9543f31dfced6c7840e068c5a5aacb7b89111a4364b1d5276b852557","affectsGlobalScope":true,"impliedFormat":1},{"version":"576711e016cf4f1804676043e6a0a5414252560eb57de9faceee34d79798c850","affectsGlobalScope":true,"impliedFormat":1},{"version":"89c1b1281ba7b8a96efc676b11b264de7a8374c5ea1e6617f11880a13fc56dc6","affectsGlobalScope":true,"impliedFormat":1},{"version":"74f7fa2d027d5b33eb0471c8e82a6c87216223181ec31247c357a3e8e2fddc5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"1a94697425a99354df73d9c8291e2ecd4dddd370aed4023c2d6dee6cccb32666","affectsGlobalScope":true,"impliedFormat":1},{"version":"063600664504610fe3e99b717a1223f8b1900087fab0b4cad1496a114744f8df","affectsGlobalScope":true,"impliedFormat":1},{"version":"934019d7e3c81950f9a8426d093458b65d5aff2c7c1511233c0fd5b941e608ab","affectsGlobalScope":true,"impliedFormat":1},{"version":"bf14a426dbbf1022d11bd08d6b8e709a2e9d246f0c6c1032f3b2edb9a902adbe","affectsGlobalScope":true,"impliedFormat":1},{"version":"e3f9fc0ec0b96a9e642f11eda09c0be83a61c7b336977f8b9fdb1e9788e925fe","affectsGlobalScope":true,"impliedFormat":1},{"version":"59fb2c069260b4ba00b5643b907ef5d5341b167e7d1dbf58dfd895658bda2867","affectsGlobalScope":true,"impliedFormat":1},{"version":"479553e3779be7d4f68e9f40cdb82d038e5ef7592010100410723ceced22a0f7","affectsGlobalScope":true,"impliedFormat":1},{"version":"368af93f74c9c932edd84c58883e736c9e3d53cec1fe24c0b0ff451f529ceab1","affectsGlobalScope":true,"impliedFormat":1},{"version":"811c71eee4aa0ac5f7adf713323a5c41b0cf6c4e17367a34fbce379e12bbf0a4","affectsGlobalScope":true,"impliedFormat":1},{"version":"33358442698bb565130f52ba79bfd3d4d484ac85fe33f3cb1759c54d18201393","affectsGlobalScope":true,"impliedFormat":1},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true,"impliedFormat":1},{"version":"807e0e0bdc67605dd28efe18f20ab5fcd75d944ef95936120702335f9379094b","impliedFormat":1},{"version":"8bbaee3df87495f955400252869914d72159835151e73f9ac6b67fabc75393d8","impliedFormat":1},{"version":"91f45b546bb83a11e79c96b309c93c5a7b9ea63bc8e013eb539c4345d331e5ff","impliedFormat":1},{"version":"d5eb5865d4cbaa9985cc3cfb920b230cdcf3363f1e70903a08dc4baab80b0ce1","impliedFormat":1},{"version":"51ebca098538b252953b1ef83c165f25b52271bfb6049cd09d197dddd4cd43c5","impliedFormat":1},{"version":"cee1ce581f32de4155032a973db9fd1c05c7fe784eaa3eb8cd5f9d102c110a85","signature":"0ce8b2974c17ca4d1834116180a56bfe1f7e57acbb1fbab7d02c457b9bd48b41"},{"version":"64d4b35c5456adf258d2cf56c341e203a073253f229ef3208fc0d5020253b241","affectsGlobalScope":true,"impliedFormat":1},{"version":"ee7d8894904b465b072be0d2e4b45cf6b887cdba16a467645c4e200982ece7ea","impliedFormat":1},{"version":"f3d8c757e148ad968f0d98697987db363070abada5f503da3c06aefd9d4248c1","impliedFormat":1},{"version":"dd0c1b380ba3437adedef134b2e48869449b1db0b07b2a229069309ce7b9dd39","impliedFormat":1},{"version":"7e771891adaa85b690266bc37bd6eb43bc57eecc4b54693ead36467e7369952a","impliedFormat":1},{"version":"a69c09dbea52352f479d3e7ac949fde3d17b195abe90b045d619f747b38d6d1a","impliedFormat":1},{"version":"8d81612302e009aacd595b125ae1530b6342f690eb83da7788503617d1362185","affectsGlobalScope":true,"impliedFormat":1},{"version":"11e2d554398d2bd460e7d06b2fa5827a297c8acfbe00b4f894a224ac0862857f","impliedFormat":1},{"version":"e193e634a99c9c1d71f1c6e4e1567a4a73584328d21ea02dd5cddbaad6693f61","affectsGlobalScope":true,"impliedFormat":1},{"version":"374ca798f244e464346f14301dc2a8b4b111af1a83b49fffef5906c338a1f922","impliedFormat":1},{"version":"5a94487653355b56018122d92392beb2e5f4a6c63ba5cef83bbe1c99775ef713","impliedFormat":1},{"version":"d5135ad93b33adcce80b18f8065087934cdc1730d63db58562edcf017e1aad9b","affectsGlobalScope":true,"impliedFormat":1},{"version":"82408ed3e959ddc60d3e9904481b5a8dc16469928257af22a3f7d1a3bc7fd8c4","impliedFormat":1},{"version":"e596c9bb2f29a2699fdd4ae89139612652245192f67f45617c5a4b20832aaae9","impliedFormat":1},{"version":"bb9c4ffa5e6290c6980b63c815cdd1625876dadb2efaf77edbe82984be93e55e","impliedFormat":1},{"version":"1cdcfc1f624d6c08aa12c73935f6e13f095919cd99edf95752951796eb225729","impliedFormat":1},{"version":"216717f17c095cde1dc19375e1ab3af0a4a485355860c077a4f9d6ea59fab5b5","impliedFormat":1},{"version":"14b5aa23c5d0ae1907bc696ac7b6915d88f7d85799cc0dc2dcf98fbce2c5a67c","impliedFormat":1},{"version":"5c439dafdc09abe4d6c260a96b822fa0ba5be7203c71a63ab1f1423cd9e838ea","impliedFormat":1},{"version":"6b526a5ec4a401ca7c26cfe6a48e641d8f30af76673bad3b06a1b4504594a960","affectsGlobalScope":true,"impliedFormat":1},{"version":"816ad2e607a96de5bcac7d437f843f5afd8957f1fa5eefa6bba8e4ed7ca8fd84","affectsGlobalScope":true,"impliedFormat":1},{"version":"80473bd0dd90ca1e166514c2dfead9d5803f9c51418864ca35abbeec6e6847e1","impliedFormat":1},{"version":"1c84b46267610a34028edfd0d035509341751262bac1062857f3c8df7aff7153","impliedFormat":1},{"version":"e6c86d83bd526c8bdb5d0bf935b8e72ce983763d600743f74d812fdf4abf4df6","impliedFormat":1},{"version":"a3d541d303ee505053f5dcbf9fafb65cac3d5631037501cd616195863a6c5740","impliedFormat":1},{"version":"8d3c583a07e0c37e876908c2d5da575019f689df8d9fa4c081d99119d53dba22","impliedFormat":1},{"version":"2c828a5405191d006115ab34e191b8474bc6c86ffdc401d1a9864b1b6e088a58","impliedFormat":1},{"version":"e630e5528e899219ae319e83bef54bf3bcb91b01d76861ecf881e8e614b167f0","affectsGlobalScope":true,"impliedFormat":1},{"version":"bcebb922784739bdb34c18ee51095d25a92b560c78ccd2eaacd6bd00f7443d83","impliedFormat":1},{"version":"7ee6ed878c4528215c82b664fe0cfe80e8b4da6c0d4cc80869367868774db8b1","impliedFormat":1},{"version":"b0973c3cbcdc59b37bf477731d468696ecaf442593ec51bab497a613a580fe30","impliedFormat":1},{"version":"4989e92ba5b69b182d2caaea6295af52b7dc73a4f7a2e336a676722884e7139d","affectsGlobalScope":true,"impliedFormat":1},{"version":"0715e4cd28ad471b2a93f3e552ff51a3ae423417a01a10aa1d3bc7c6b95059d6","affectsGlobalScope":true,"impliedFormat":1},{"version":"5153a2fd150e46ce57bb3f8db1318d33f6ad3261ed70ceeff92281c0608c74a3","impliedFormat":1},{"version":"210d54cd652ec0fec8c8916e4af59bb341065576ecda039842f9ffb2e908507c","impliedFormat":1},{"version":"36b03690b628eab08703d63f04eaa89c5df202e5f1edf3989f13ad389cd2c091","impliedFormat":1},{"version":"0effadd232a20498b11308058e334d3339cc5bf8c4c858393e38d9d4c0013dcf","impliedFormat":1},{"version":"25846d43937c672bab7e8195f3d881f93495df712ee901860effc109918938cc","impliedFormat":1},{"version":"4f3fdeba4e28e21aa719c081b8dc8f91d47e12e773389b9d35679c08151c9d37","impliedFormat":1},{"version":"1b952304137851e45bc009785de89ada562d9376177c97e37702e39e60c2f1ff","impliedFormat":1},{"version":"69ee23dd0d215b09907ad30d23f88b7790c93329d1faf31d7835552a10cf7cbf","impliedFormat":1},{"version":"44b8b584a338b190a59f4f6929d072431950c7bd92ec2694821c11bce180c8a5","impliedFormat":1},{"version":"23b89798789dffbd437c0c423f5d02d11f9736aea73d6abf16db4f812ff36eda","impliedFormat":1},{"version":"f69ff39996a61a0dd10f4bce73272b52e8024a4d58b13ab32bf4712909d0a2b7","impliedFormat":1},{"version":"3c4ba1dd9b12ffa284b565063108f2f031d150ea15b8fafbdc17f5d2a07251f3","affectsGlobalScope":true,"impliedFormat":1},{"version":"e10177274a35a9d07c825615340b2fcde2f610f53f3fb40269fd196b4288dda6","impliedFormat":1},{"version":"c4577fb855ca259bdbf3ea663ca73988ce5f84251a92b4aef80a1f4122b6f98e","impliedFormat":1},{"version":"3c13ef48634e7b5012fcf7e8fce7496352c2d779a7201389ca96a2a81ee4314d","impliedFormat":1},{"version":"5d0a25ec910fa36595f85a67ac992d7a53dd4064a1ba6aea1c9f14ab73a023f2","impliedFormat":1},{"version":"f0900cd5d00fe1263ff41201fb8073dbeb984397e4af3b8002a5c207a30bdc33","affectsGlobalScope":true,"impliedFormat":1},{"version":"ff07a9a03c65732ccc59b3c65bc584173da093bd563a6565411c01f5703bd3cb","affectsGlobalScope":true,"impliedFormat":1},{"version":"6de4a219df57d2b27274d59b67708f13c2cbf7ed211abe57d8f9ab8b25cde776","impliedFormat":1},{"version":"0fe8985a28f82c450a04a6edf1279d7181c0893f37da7d2a27f8efd4fd5edb03","impliedFormat":1},{"version":"e59a892d87e72733e2a9ca21611b9beb52977be2696c7ba4b216cbbb9a48f5aa","impliedFormat":1},{"version":"da26af7362f53d122283bc69fed862b9a9fe27e01bc6a69d1d682e0e5a4df3e6","affectsGlobalScope":true,"impliedFormat":1},{"version":"8a300fa9b698845a1f9c41ecbe2c5966634582a8e2020d51abcace9b55aa959e","impliedFormat":1},{"version":"ab9b9a36e5284fd8d3bf2f7d5fcbc60052f25f27e4d20954782099282c60d23e","affectsGlobalScope":true,"impliedFormat":1},{"version":"d8d555f3d607ecaa18d55de6995ea8f206342ecc93305919eac945c7c78c78c6","impliedFormat":1},{"version":"104c67f0da1bdf0d94865419247e20eded83ce7f9911a1aa75fc675c077ca66e","impliedFormat":1},{"version":"035a5df183489c2e22f3cf59fc1ed2b043d27f357eecc0eb8d8e840059d44245","impliedFormat":1},{"version":"a4809f4d92317535e6b22b01019437030077a76fec1d93b9881c9ed4738fcc54","impliedFormat":1},{"version":"5f53fa0bd22096d2a78533f94e02c899143b8f0f9891a46965294ee8b91a9434","impliedFormat":1},{"version":"8b5402ae709d042c3530ed3506c135a967159f42aed3221267e70c5b7240b577","impliedFormat":1},{"version":"ab82804a14454734010dcdcd43f564ff7b0389bee4c5692eec76ff5b30d4cf66","impliedFormat":1},{"version":"fab58e600970e66547644a44bc9918e3223aa2cbd9e8763cec004b2cfb48827e","impliedFormat":1},{"version":"bc81aff061c53a7140270555f4b22da4ecfe8601e8027cf5aa175fbdc7927c31","impliedFormat":1},{"version":"bae8d023ef6b23df7da26f51cea44321f95817c190342a36882e93b80d07a960","impliedFormat":1},{"version":"26a770cec4bd2e7dbba95c6e536390fffe83c6268b78974a93727903b515c4e7","impliedFormat":1}],"root":[55],"options":{"composite":true,"esModuleInterop":true,"module":1,"outDir":"./dist","rootDir":"./src","skipLibCheck":true,"strict":true,"target":3},"referencedMap":[[53,1],[52,2],[54,3],[51,4],[56,4],[59,5],[57,4],[58,4],[48,4],[49,4],[8,4],[9,4],[13,4],[12,4],[2,4],[14,4],[15,4],[16,4],[17,4],[18,4],[19,4],[20,4],[21,4],[3,4],[50,4],[22,4],[4,4],[23,4],[27,4],[24,4],[25,4],[26,4],[28,4],[29,4],[30,4],[5,4],[31,4],[32,4],[33,4],[34,4],[6,4],[38,4],[35,4],[36,4],[37,4],[39,4],[7,4],[40,4],[45,4],[46,4],[41,4],[42,4],[43,4],[44,4],[1,4],[47,4],[11,4],[10,4],[55,6],[114,7],[115,4],[116,8],[117,9],[118,10],[60,11],[61,11],[63,12],[64,13],[65,14],[66,15],[67,16],[68,17],[69,18],[70,19],[71,20],[72,21],[73,21],[75,22],[74,23],[76,22],[77,24],[78,25],[62,26],[112,4],[79,27],[80,28],[81,29],[113,30],[82,31],[83,32],[84,33],[85,34],[86,35],[87,36],[88,37],[89,38],[90,39],[91,40],[92,40],[93,41],[94,42],[96,43],[95,44],[97,45],[98,46],[99,4],[100,47],[101,48],[102,49],[103,50],[104,51],[105,52],[106,53],[107,54],[108,55],[109,56],[110,57],[111,58],[119,4],[120,4],[121,59],[122,4],[123,60]],"latestChangedDtsFile":"./dist/index.d.ts","version":"5.6.3"} -------------------------------------------------------------------------------- /metaverse/packages/eslint-config/README.md: -------------------------------------------------------------------------------- 1 | # `@turbo/eslint-config` 2 | 3 | Collection of internal eslint configurations. 4 | -------------------------------------------------------------------------------- /metaverse/packages/eslint-config/library.js: -------------------------------------------------------------------------------- 1 | const { resolve } = require("node:path"); 2 | 3 | const project = resolve(process.cwd(), "tsconfig.json"); 4 | 5 | /** @type {import("eslint").Linter.Config} */ 6 | module.exports = { 7 | extends: ["eslint:recommended", "prettier", "turbo"], 8 | plugins: ["only-warn"], 9 | globals: { 10 | React: true, 11 | JSX: true, 12 | }, 13 | env: { 14 | node: true, 15 | }, 16 | settings: { 17 | "import/resolver": { 18 | typescript: { 19 | project, 20 | }, 21 | }, 22 | }, 23 | ignorePatterns: [ 24 | // Ignore dotfiles 25 | ".*.js", 26 | "node_modules/", 27 | "dist/", 28 | ], 29 | overrides: [ 30 | { 31 | files: ["*.js?(x)", "*.ts?(x)"], 32 | }, 33 | ], 34 | }; 35 | -------------------------------------------------------------------------------- /metaverse/packages/eslint-config/next.js: -------------------------------------------------------------------------------- 1 | const { resolve } = require("node:path"); 2 | 3 | const project = resolve(process.cwd(), "tsconfig.json"); 4 | 5 | /** @type {import("eslint").Linter.Config} */ 6 | module.exports = { 7 | extends: [ 8 | "eslint:recommended", 9 | "prettier", 10 | require.resolve("@vercel/style-guide/eslint/next"), 11 | "turbo", 12 | ], 13 | globals: { 14 | React: true, 15 | JSX: true, 16 | }, 17 | env: { 18 | node: true, 19 | browser: true, 20 | }, 21 | plugins: ["only-warn"], 22 | settings: { 23 | "import/resolver": { 24 | typescript: { 25 | project, 26 | }, 27 | }, 28 | }, 29 | ignorePatterns: [ 30 | // Ignore dotfiles 31 | ".*.js", 32 | "node_modules/", 33 | ], 34 | overrides: [{ files: ["*.js?(x)", "*.ts?(x)"] }], 35 | }; 36 | -------------------------------------------------------------------------------- /metaverse/packages/eslint-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@repo/eslint-config", 3 | "version": "0.0.0", 4 | "private": true, 5 | "files": [ 6 | "library.js", 7 | "next.js", 8 | "react-internal.js" 9 | ], 10 | "devDependencies": { 11 | "@vercel/style-guide": "^5.2.0", 12 | "eslint-config-turbo": "^2.0.0", 13 | "eslint-config-prettier": "^9.1.0", 14 | "eslint-plugin-only-warn": "^1.1.0", 15 | "@typescript-eslint/parser": "^7.1.0", 16 | "@typescript-eslint/eslint-plugin": "^7.1.0", 17 | "typescript": "5.5.4" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /metaverse/packages/eslint-config/react-internal.js: -------------------------------------------------------------------------------- 1 | const { resolve } = require("node:path"); 2 | 3 | const project = resolve(process.cwd(), "tsconfig.json"); 4 | 5 | /* 6 | * This is a custom ESLint configuration for use with 7 | * internal (bundled by their consumer) libraries 8 | * that utilize React. 9 | */ 10 | 11 | /** @type {import("eslint").Linter.Config} */ 12 | module.exports = { 13 | extends: ["eslint:recommended", "prettier", "turbo"], 14 | plugins: ["only-warn"], 15 | globals: { 16 | React: true, 17 | JSX: true, 18 | }, 19 | env: { 20 | browser: true, 21 | }, 22 | settings: { 23 | "import/resolver": { 24 | typescript: { 25 | project, 26 | }, 27 | }, 28 | }, 29 | ignorePatterns: [ 30 | // Ignore dotfiles 31 | ".*.js", 32 | "node_modules/", 33 | "dist/", 34 | ], 35 | overrides: [ 36 | // Force ESLint to detect .tsx files 37 | { files: ["*.js?(x)", "*.ts?(x)"] }, 38 | ], 39 | }; 40 | -------------------------------------------------------------------------------- /metaverse/packages/typescript-config/base.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "compilerOptions": { 4 | "declaration": true, 5 | "declarationMap": true, 6 | "esModuleInterop": true, 7 | "incremental": false, 8 | "isolatedModules": true, 9 | "lib": ["es2022", "DOM", "DOM.Iterable"], 10 | "module": "NodeNext", 11 | "moduleDetection": "force", 12 | "moduleResolution": "NodeNext", 13 | "noUncheckedIndexedAccess": true, 14 | "resolveJsonModule": true, 15 | "skipLibCheck": true, 16 | "strict": true, 17 | "target": "ES2022" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /metaverse/packages/typescript-config/nextjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "extends": "./base.json", 4 | "compilerOptions": { 5 | "plugins": [{ "name": "next" }], 6 | "module": "ESNext", 7 | "moduleResolution": "Bundler", 8 | "allowJs": true, 9 | "jsx": "preserve", 10 | "noEmit": true 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /metaverse/packages/typescript-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@repo/typescript-config", 3 | "version": "0.0.0", 4 | "private": true, 5 | "license": "MIT", 6 | "publishConfig": { 7 | "access": "public" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /metaverse/packages/typescript-config/react-library.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "extends": "./base.json", 4 | "compilerOptions": { 5 | "jsx": "react-jsx" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /metaverse/packages/ui/.eslintrc.js: -------------------------------------------------------------------------------- 1 | /** @type {import("eslint").Linter.Config} */ 2 | module.exports = { 3 | root: true, 4 | extends: ["@repo/eslint-config/react-internal.js"], 5 | parser: "@typescript-eslint/parser", 6 | parserOptions: { 7 | project: "./tsconfig.lint.json", 8 | tsconfigRootDir: __dirname, 9 | }, 10 | }; 11 | -------------------------------------------------------------------------------- /metaverse/packages/ui/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@repo/ui", 3 | "version": "0.0.0", 4 | "private": true, 5 | "exports": { 6 | "./button": "./src/button.tsx", 7 | "./card": "./src/card.tsx", 8 | "./code": "./src/code.tsx" 9 | }, 10 | "scripts": { 11 | "lint": "eslint . --max-warnings 0", 12 | "generate:component": "turbo gen react-component" 13 | }, 14 | "devDependencies": { 15 | "@repo/eslint-config": "workspace:*", 16 | "@repo/typescript-config": "workspace:*", 17 | "@turbo/gen": "^1.12.4", 18 | "@types/node": "^20.11.24", 19 | "@types/eslint": "^8.56.5", 20 | "@types/react": "^18.2.61", 21 | "@types/react-dom": "^18.2.19", 22 | "eslint": "^8.57.0", 23 | "typescript": "5.5.4" 24 | }, 25 | "dependencies": { 26 | "react": "^18.2.0" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /metaverse/packages/ui/src/button.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { ReactNode } from "react"; 4 | 5 | interface ButtonProps { 6 | children: ReactNode; 7 | className?: string; 8 | appName: string; 9 | } 10 | 11 | export const Button = ({ children, className, appName }: ButtonProps) => { 12 | return ( 13 | 19 | ); 20 | }; 21 | -------------------------------------------------------------------------------- /metaverse/packages/ui/src/card.tsx: -------------------------------------------------------------------------------- 1 | export function Card({ 2 | className, 3 | title, 4 | children, 5 | href, 6 | }: { 7 | className?: string; 8 | title: string; 9 | children: React.ReactNode; 10 | href: string; 11 | }): JSX.Element { 12 | return ( 13 | 19 |

20 | {title} -> 21 |

22 |

{children}

23 |
24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /metaverse/packages/ui/src/code.tsx: -------------------------------------------------------------------------------- 1 | export function Code({ 2 | children, 3 | className, 4 | }: { 5 | children: React.ReactNode; 6 | className?: string; 7 | }): JSX.Element { 8 | return {children}; 9 | } 10 | -------------------------------------------------------------------------------- /metaverse/packages/ui/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@repo/typescript-config/react-library.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": ["src"], 7 | "exclude": ["node_modules", "dist"] 8 | } 9 | -------------------------------------------------------------------------------- /metaverse/packages/ui/tsconfig.lint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@repo/typescript-config/react-library.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": ["src", "turbo"], 7 | "exclude": ["node_modules", "dist"] 8 | } 9 | -------------------------------------------------------------------------------- /metaverse/packages/ui/turbo/generators/config.ts: -------------------------------------------------------------------------------- 1 | import type { PlopTypes } from "@turbo/gen"; 2 | 3 | // Learn more about Turborepo Generators at https://turbo.build/repo/docs/core-concepts/monorepos/code-generation 4 | 5 | export default function generator(plop: PlopTypes.NodePlopAPI): void { 6 | // A simple generator to add a new React component to the internal UI library 7 | plop.setGenerator("react-component", { 8 | description: "Adds a new react component", 9 | prompts: [ 10 | { 11 | type: "input", 12 | name: "name", 13 | message: "What is the name of the component?", 14 | }, 15 | ], 16 | actions: [ 17 | { 18 | type: "add", 19 | path: "src/{{kebabCase name}}.tsx", 20 | templateFile: "templates/component.hbs", 21 | }, 22 | { 23 | type: "append", 24 | path: "package.json", 25 | pattern: /"exports": {(?)/g, 26 | template: ' "./{{kebabCase name}}": "./src/{{kebabCase name}}.tsx",', 27 | }, 28 | ], 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /metaverse/packages/ui/turbo/generators/templates/component.hbs: -------------------------------------------------------------------------------- 1 | export const {{ pascalCase name }} = ({ children }: { children: React.ReactNode }) => { 2 | return ( 3 |
4 |

{{ pascalCase name }} Component

5 | {children} 6 |
7 | ); 8 | }; 9 | -------------------------------------------------------------------------------- /metaverse/pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - "apps/*" 3 | - "packages/*" 4 | -------------------------------------------------------------------------------- /metaverse/turbo.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://turbo.build/schema.json", 3 | "ui": "tui", 4 | "tasks": { 5 | "build": { 6 | "dependsOn": ["^build"], 7 | "inputs": ["$TURBO_DEFAULT$", ".env*"], 8 | "outputs": [".next/**", "!.next/cache/**"] 9 | }, 10 | "lint": { 11 | "dependsOn": ["^lint"] 12 | }, 13 | "dev": { 14 | "cache": false, 15 | "persistent": true 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tests/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /tests/index.test.js: -------------------------------------------------------------------------------- 1 | const axios2 = require("axios"); 2 | 3 | const BACKEND_URL = "http://localhost:3000" 4 | const WS_URL = "ws://localhost:3001" 5 | 6 | const axios = { 7 | post: async (...args) => { 8 | try { 9 | const res = await axios2.post(...args) 10 | return res 11 | } catch(e) { 12 | return e.response 13 | } 14 | }, 15 | get: async (...args) => { 16 | try { 17 | const res = await axios2.get(...args) 18 | return res 19 | } catch(e) { 20 | return e.response 21 | } 22 | }, 23 | put: async (...args) => { 24 | try { 25 | const res = await axios2.put(...args) 26 | return res 27 | } catch(e) { 28 | return e.response 29 | } 30 | }, 31 | delete: async (...args) => { 32 | try { 33 | const res = await axios2.delete(...args) 34 | return res 35 | } catch(e) { 36 | return e.response 37 | } 38 | }, 39 | } 40 | 41 | describe("Authentication", () => { 42 | test('User is able to sign up only once', async () => { 43 | const username = "kirat" + Math.random(); // kirat0.12331313 44 | const password = "123456"; 45 | const response = await axios.post(`${BACKEND_URL}/api/v1/signup`, { 46 | username, 47 | password, 48 | type: "admin" 49 | }) 50 | 51 | expect(response.status).toBe(200) 52 | const updatedResponse = await axios.post(`${BACKEND_URL}/api/v1/signup`, { 53 | username, 54 | password, 55 | type: "admin" 56 | }) 57 | 58 | expect(updatedResponse.status).toBe(400); 59 | }); 60 | 61 | test('Signup request fails if the username is empty', async () => { 62 | const username = `kirat-${Math.random()}` // kirat-0.12312313 63 | const password = "123456" 64 | 65 | const response = await axios.post(`${BACKEND_URL}/api/v1/signup`, { 66 | password 67 | }) 68 | 69 | expect(response.status).toBe(400) 70 | }) 71 | 72 | test('Signin succeeds if the username and password are correct', async() => { 73 | const username = `kirat-${Math.random()}` 74 | const password = "123456" 75 | 76 | await axios.post(`${BACKEND_URL}/api/v1/signup`, { 77 | username, 78 | password, 79 | type: "admin" 80 | }); 81 | 82 | const response = await axios.post(`${BACKEND_URL}/api/v1/signin`, { 83 | username, 84 | password 85 | }); 86 | 87 | expect(response.status).toBe(200) 88 | expect(response.data.token).toBeDefined() 89 | 90 | }) 91 | 92 | test('Signin fails if the username and password are incorrect', async() => { 93 | const username = `kirat-${Math.random()}` 94 | const password = "123456" 95 | 96 | await axios.post(`${BACKEND_URL}/api/v1/signup`, { 97 | username, 98 | password, 99 | role: "admin" 100 | }); 101 | 102 | const response = await axios.post(`${BACKEND_URL}/api/v1/signin`, { 103 | username: "WrongUsername", 104 | password 105 | }) 106 | 107 | expect(response.status).toBe(403) 108 | }) 109 | }) 110 | 111 | describe("User metadata endpoint", () => { 112 | let token = ""; 113 | let avatarId = "" 114 | 115 | beforeAll(async () => { 116 | const username = `kirat-${Math.random()}` 117 | const password = "123456" 118 | 119 | await axios.post(`${BACKEND_URL}/api/v1/signup`, { 120 | username, 121 | password, 122 | type: "admin" 123 | }); 124 | 125 | const response = await axios.post(`${BACKEND_URL}/api/v1/signin`, { 126 | username, 127 | password 128 | }) 129 | 130 | token = response.data.token 131 | 132 | const avatarResponse = await axios.post(`${BACKEND_URL}/api/v1/admin/avatar`, { 133 | "imageUrl": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQm3RFDZM21teuCMFYx_AROjt-AzUwDBROFww&s", 134 | "name": "Timmy" 135 | }, { 136 | headers: { 137 | authorization: `Bearer ${token}` 138 | } 139 | }) 140 | console.log("avatarresponse is " + avatarResponse.data.avatarId) 141 | 142 | avatarId = avatarResponse.data.avatarId; 143 | 144 | }) 145 | 146 | test("User cant update their metadata with a wrong avatar id", async () => { 147 | const response = await axios.post(`${BACKEND_URL}/api/v1/user/metadata`, { 148 | avatarId: "123123123" 149 | }, { 150 | headers: { 151 | "authorization": `Bearer ${token}` 152 | } 153 | }) 154 | 155 | expect(response.status).toBe(400) 156 | }) 157 | 158 | test("User can update their metadata with the right avatar id", async () => { 159 | const response = await axios.post(`${BACKEND_URL}/api/v1/user/metadata`, { 160 | avatarId 161 | }, { 162 | headers: { 163 | "authorization": `Bearer ${token}` 164 | } 165 | }) 166 | 167 | expect(response.status).toBe(200) 168 | }) 169 | 170 | test("User is not able to update their metadata if the auth header is not present", async () => { 171 | const response = await axios.post(`${BACKEND_URL}/api/v1/user/metadata`, { 172 | avatarId 173 | }) 174 | 175 | expect(response.status).toBe(403) 176 | }) 177 | 178 | test("test 3", () => { 179 | 180 | }) 181 | }); 182 | 183 | describe("User avatar information", () => { 184 | let avatarId; 185 | let token; 186 | let userId; 187 | 188 | beforeAll(async () => { 189 | const username = `kirat-${Math.random()}` 190 | const password = "123456" 191 | 192 | const signupResponse = await axios.post(`${BACKEND_URL}/api/v1/signup`, { 193 | username, 194 | password, 195 | type: "admin" 196 | }); 197 | 198 | userId = signupResponse.data.userId 199 | 200 | console.log("userid is " + userId) 201 | const response = await axios.post(`${BACKEND_URL}/api/v1/signin`, { 202 | username, 203 | password 204 | }) 205 | 206 | token = response.data.token 207 | 208 | const avatarResponse = await axios.post(`${BACKEND_URL}/api/v1/admin/avatar`, { 209 | "imageUrl": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQm3RFDZM21teuCMFYx_AROjt-AzUwDBROFww&s", 210 | "name": "Timmy" 211 | }, { 212 | headers: { 213 | authorization: `Bearer ${token}` 214 | } 215 | }) 216 | 217 | avatarId = avatarResponse.data.avatarId; 218 | 219 | }) 220 | 221 | test("Get back avatar information for a user", async () => { 222 | console.log("asking for user with id " + userId) 223 | const response = await axios.get(`${BACKEND_URL}/api/v1/user/metadata/bulk?ids=[${userId}]`); 224 | console.log("response was " + userId) 225 | console.log(JSON.stringify(response.data)) 226 | expect(response.data.avatars.length).toBe(1); 227 | expect(response.data.avatars[0].userId).toBe(userId); 228 | }) 229 | 230 | test("Available avatars lists the recently created avatar", async () => { 231 | const response = await axios.get(`${BACKEND_URL}/api/v1/avatars`); 232 | expect(response.data.avatars.length).not.toBe(0); 233 | const currentAvatar = response.data.avatars.find(x => x.id == avatarId); 234 | expect(currentAvatar).toBeDefined() 235 | }) 236 | 237 | }) 238 | 239 | describe("Space information", () => { 240 | let mapId; 241 | let element1Id; 242 | let element2Id; 243 | let adminToken; 244 | let adminId; 245 | let userToken; 246 | let userId; 247 | 248 | beforeAll(async () => { 249 | const username = `kirat-${Math.random()}` 250 | const password = "123456" 251 | 252 | const signupResponse = await axios.post(`${BACKEND_URL}/api/v1/signup`, { 253 | username, 254 | password, 255 | type: "admin" 256 | }); 257 | 258 | adminId = signupResponse.data.userId 259 | 260 | const response = await axios.post(`${BACKEND_URL}/api/v1/signin`, { 261 | username, 262 | password 263 | }) 264 | 265 | adminToken = response.data.token 266 | 267 | const userSignupResponse = await axios.post(`${BACKEND_URL}/api/v1/signup`, { 268 | username: username + "-user", 269 | password, 270 | type: "user" 271 | }); 272 | 273 | userId = userSignupResponse.data.userId 274 | 275 | const userSigninResponse = await axios.post(`${BACKEND_URL}/api/v1/signin`, { 276 | username: username + "-user", 277 | password 278 | }) 279 | 280 | userToken = userSigninResponse.data.token 281 | 282 | const element1Response = await axios.post(`${BACKEND_URL}/api/v1/admin/element`, { 283 | "imageUrl": "https://encrypted-tbn0.gstatic.com/shopping?q=tbn:ANd9GcRCRca3wAR4zjPPTzeIY9rSwbbqB6bB2hVkoTXN4eerXOIkJTG1GpZ9ZqSGYafQPToWy_JTcmV5RHXsAsWQC3tKnMlH_CsibsSZ5oJtbakq&usqp=CAE", 284 | "width": 1, 285 | "height": 1, 286 | "static": true 287 | }, { 288 | headers: { 289 | authorization: `Bearer ${adminToken}` 290 | } 291 | }); 292 | 293 | const element2Response = await axios.post(`${BACKEND_URL}/api/v1/admin/element`, { 294 | "imageUrl": "https://encrypted-tbn0.gstatic.com/shopping?q=tbn:ANd9GcRCRca3wAR4zjPPTzeIY9rSwbbqB6bB2hVkoTXN4eerXOIkJTG1GpZ9ZqSGYafQPToWy_JTcmV5RHXsAsWQC3tKnMlH_CsibsSZ5oJtbakq&usqp=CAE", 295 | "width": 1, 296 | "height": 1, 297 | "static": true 298 | }, { 299 | headers: { 300 | authorization: `Bearer ${adminToken}` 301 | } 302 | }) 303 | element1Id = element1Response.data.id 304 | element2Id = element2Response.data.id 305 | console.log(element2Id) 306 | console.log(element1Id) 307 | const mapResponse = await axios.post(`${BACKEND_URL}/api/v1/admin/map`, { 308 | "thumbnail": "https://thumbnail.com/a.png", 309 | "dimensions": "100x200", 310 | "name": "Test space", 311 | "defaultElements": [{ 312 | elementId: element1Id, 313 | x: 20, 314 | y: 20 315 | }, { 316 | elementId: element1Id, 317 | x: 18, 318 | y: 20 319 | }, { 320 | elementId: element2Id, 321 | x: 19, 322 | y: 20 323 | } 324 | ] 325 | }, { 326 | headers: { 327 | authorization: `Bearer ${adminToken}` 328 | } 329 | }) 330 | console.log("mapResponse.status") 331 | console.log(mapResponse.data.id) 332 | 333 | mapId = mapResponse.data.id 334 | 335 | }); 336 | 337 | test("User is able to create a space", async () => { 338 | 339 | const response = await axios.post(`${BACKEND_URL}/api/v1/space`, { 340 | "name": "Test", 341 | "dimensions": "100x200", 342 | "mapId": mapId 343 | }, { 344 | headers: { 345 | authorization: `Bearer ${userToken}` 346 | } 347 | }) 348 | expect(response.status).toBe(200) 349 | expect(response.data.spaceId).toBeDefined() 350 | }) 351 | 352 | test("User is able to create a space without mapId (empty space)", async () => { 353 | const response = await axios.post(`${BACKEND_URL}/api/v1/space`, { 354 | "name": "Test", 355 | "dimensions": "100x200", 356 | }, { 357 | headers: { 358 | authorization: `Bearer ${userToken}` 359 | } 360 | }) 361 | 362 | expect(response.data.spaceId).toBeDefined() 363 | }) 364 | 365 | test("User is not able to create a space without mapId and dimensions", async () => { 366 | const response = await axios.post(`${BACKEND_URL}/api/v1/space`, { 367 | "name": "Test", 368 | }, { 369 | headers: { 370 | authorization: `Bearer ${userToken}` 371 | } 372 | }) 373 | 374 | expect(response.status).toBe(400) 375 | }) 376 | 377 | test("User is not able to delete a space that doesnt exist", async () => { 378 | const response = await axios.delete(`${BACKEND_URL}/api/v1/space/randomIdDoesntExist`, { 379 | headers: { 380 | authorization: `Bearer ${userToken}` 381 | } 382 | }) 383 | 384 | expect(response.status).toBe(400) 385 | }) 386 | 387 | test("User is able to delete a space that does exist", async () => { 388 | const response = await axios.post(`${BACKEND_URL}/api/v1/space`, { 389 | "name": "Test", 390 | "dimensions": "100x200", 391 | }, { 392 | headers: { 393 | authorization: `Bearer ${userToken}` 394 | } 395 | }) 396 | 397 | const deleteReponse = await axios.delete(`${BACKEND_URL}/api/v1/space/${response.data.spaceId}`, { 398 | headers: { 399 | authorization: `Bearer ${userToken}` 400 | } 401 | }) 402 | 403 | expect(deleteReponse.status).toBe(200) 404 | }) 405 | 406 | test("User should not be able to delete a space created by another user", async () => { 407 | const response = await axios.post(`${BACKEND_URL}/api/v1/space`, { 408 | "name": "Test", 409 | "dimensions": "100x200", 410 | }, { 411 | headers: { 412 | authorization: `Bearer ${userToken}` 413 | } 414 | }) 415 | 416 | const deleteReponse = await axios.delete(`${BACKEND_URL}/api/v1/space/${response.data.spaceId}`, { 417 | headers: { 418 | authorization: `Bearer ${adminToken}` 419 | } 420 | }) 421 | 422 | expect(deleteReponse.status).toBe(403) 423 | }) 424 | 425 | test("Admin has no spaces initially", async () => { 426 | const response = await axios.get(`${BACKEND_URL}/api/v1/space/all`, { 427 | headers: { 428 | authorization: `Bearer ${adminToken}` 429 | } 430 | }); 431 | expect(response.data.spaces.length).toBe(0) 432 | }) 433 | 434 | test("Admin has gets once space after", async () => { 435 | const spaceCreateReponse = await axios.post(`${BACKEND_URL}/api/v1/space`, { 436 | "name": "Test", 437 | "dimensions": "100x200", 438 | }, { 439 | headers: { 440 | authorization: `Bearer ${adminToken}` 441 | } 442 | }); 443 | console.log('jhflksdjflksdfjlksdfj') 444 | console.log(spaceCreateReponse.data) 445 | const response = await axios.get(`${BACKEND_URL}/api/v1/space/all`, { 446 | headers: { 447 | authorization: `Bearer ${adminToken}` 448 | } 449 | }); 450 | const filteredSpace = response.data.spaces.find(x => x.id == spaceCreateReponse.data.spaceId) 451 | expect(response.data.spaces.length).toBe(1) 452 | expect(filteredSpace).toBeDefined() 453 | 454 | }) 455 | }) 456 | 457 | describe("Arena endpoints", () => { 458 | let mapId; 459 | let element1Id; 460 | let element2Id; 461 | let adminToken; 462 | let adminId; 463 | let userToken; 464 | let userId; 465 | let spaceId; 466 | 467 | beforeAll(async () => { 468 | const username = `kirat-${Math.random()}` 469 | const password = "123456" 470 | 471 | const signupResponse = await axios.post(`${BACKEND_URL}/api/v1/signup`, { 472 | username, 473 | password, 474 | type: "admin" 475 | }); 476 | 477 | adminId = signupResponse.data.userId 478 | 479 | const response = await axios.post(`${BACKEND_URL}/api/v1/signin`, { 480 | username: username, 481 | password 482 | }) 483 | 484 | adminToken = response.data.token 485 | 486 | const userSignupResponse = await axios.post(`${BACKEND_URL}/api/v1/signup`, { 487 | username: username + "-user", 488 | password, 489 | type: "user" 490 | }); 491 | 492 | userId = userSignupResponse.data.userId 493 | 494 | const userSigninResponse = await axios.post(`${BACKEND_URL}/api/v1/signin`, { 495 | username: username + "-user", 496 | password 497 | }) 498 | 499 | userToken = userSigninResponse.data.token 500 | 501 | const element1Response = await axios.post(`${BACKEND_URL}/api/v1/admin/element`, { 502 | "imageUrl": "https://encrypted-tbn0.gstatic.com/shopping?q=tbn:ANd9GcRCRca3wAR4zjPPTzeIY9rSwbbqB6bB2hVkoTXN4eerXOIkJTG1GpZ9ZqSGYafQPToWy_JTcmV5RHXsAsWQC3tKnMlH_CsibsSZ5oJtbakq&usqp=CAE", 503 | "width": 1, 504 | "height": 1, 505 | "static": true 506 | }, { 507 | headers: { 508 | authorization: `Bearer ${adminToken}` 509 | } 510 | }); 511 | 512 | const element2Response = await axios.post(`${BACKEND_URL}/api/v1/admin/element`, { 513 | "imageUrl": "https://encrypted-tbn0.gstatic.com/shopping?q=tbn:ANd9GcRCRca3wAR4zjPPTzeIY9rSwbbqB6bB2hVkoTXN4eerXOIkJTG1GpZ9ZqSGYafQPToWy_JTcmV5RHXsAsWQC3tKnMlH_CsibsSZ5oJtbakq&usqp=CAE", 514 | "width": 1, 515 | "height": 1, 516 | "static": true 517 | }, { 518 | headers: { 519 | authorization: `Bearer ${adminToken}` 520 | } 521 | }) 522 | element1Id = element1Response.data.id 523 | element2Id = element2Response.data.id 524 | 525 | const mapResponse = await axios.post(`${BACKEND_URL}/api/v1/admin/map`, { 526 | "thumbnail": "https://thumbnail.com/a.png", 527 | "dimensions": "100x200", 528 | name: "Default space", 529 | "defaultElements": [{ 530 | elementId: element1Id, 531 | x: 20, 532 | y: 20 533 | }, { 534 | elementId: element1Id, 535 | x: 18, 536 | y: 20 537 | }, { 538 | elementId: element2Id, 539 | x: 19, 540 | y: 20 541 | } 542 | ] 543 | }, { 544 | headers: { 545 | authorization: `Bearer ${adminToken}` 546 | } 547 | }) 548 | mapId = mapResponse.data.id 549 | 550 | const spaceResponse = await axios.post(`${BACKEND_URL}/api/v1/space`, { 551 | "name": "Test", 552 | "dimensions": "100x200", 553 | "mapId": mapId 554 | }, {headers: { 555 | "authorization": `Bearer ${userToken}` 556 | }}) 557 | console.log(spaceResponse.data) 558 | spaceId = spaceResponse.data.spaceId 559 | }); 560 | 561 | test("Incorrect spaceId returns a 400", async () => { 562 | const response = await axios.get(`${BACKEND_URL}/api/v1/space/123kasdk01`, { 563 | headers: { 564 | "authorization": `Bearer ${userToken}` 565 | } 566 | }); 567 | expect(response.status).toBe(400) 568 | }) 569 | 570 | test("Correct spaceId returns all the elements", async () => { 571 | const response = await axios.get(`${BACKEND_URL}/api/v1/space/${spaceId}`, { 572 | headers: { 573 | "authorization": `Bearer ${userToken}` 574 | } 575 | }); 576 | console.log(response.data) 577 | expect(response.data.dimensions).toBe("100x200") 578 | expect(response.data.elements.length).toBe(3) 579 | }) 580 | 581 | test("Delete endpoint is able to delete an element", async () => { 582 | const response = await axios.get(`${BACKEND_URL}/api/v1/space/${spaceId}`, { 583 | headers: { 584 | "authorization": `Bearer ${userToken}` 585 | } 586 | }); 587 | 588 | console.log(response.data.elements[0].id ) 589 | let res = await axios.delete(`${BACKEND_URL}/api/v1/space/element`, { 590 | data: {id: response.data.elements[0].id}, 591 | headers: { 592 | "authorization": `Bearer ${userToken}` 593 | } 594 | }); 595 | 596 | 597 | const newResponse = await axios.get(`${BACKEND_URL}/api/v1/space/${spaceId}`, { 598 | headers: { 599 | "authorization": `Bearer ${userToken}` 600 | } 601 | }); 602 | 603 | expect(newResponse.data.elements.length).toBe(2) 604 | }) 605 | 606 | test("Adding an element fails if the element lies outside the dimensions", async () => { 607 | const newResponse = await axios.post(`${BACKEND_URL}/api/v1/space/element`, { 608 | "elementId": element1Id, 609 | "spaceId": spaceId, 610 | "x": 10000, 611 | "y": 210000 612 | }, { 613 | headers: { 614 | "authorization": `Bearer ${userToken}` 615 | } 616 | }); 617 | 618 | expect(newResponse.status).toBe(400) 619 | }) 620 | 621 | test("Adding an element works as expected", async () => { 622 | await axios.post(`${BACKEND_URL}/api/v1/space/element`, { 623 | "elementId": element1Id, 624 | "spaceId": spaceId, 625 | "x": 50, 626 | "y": 20 627 | }, { 628 | headers: { 629 | "authorization": `Bearer ${userToken}` 630 | } 631 | }); 632 | 633 | const newResponse = await axios.get(`${BACKEND_URL}/api/v1/space/${spaceId}`, { 634 | headers: { 635 | "authorization": `Bearer ${userToken}` 636 | } 637 | }); 638 | 639 | expect(newResponse.data.elements.length).toBe(3) 640 | }) 641 | 642 | }) 643 | 644 | describe("Admin Endpoints", () => { 645 | let adminToken; 646 | let adminId; 647 | let userToken; 648 | let userId; 649 | 650 | beforeAll(async () => { 651 | const username = `kirat-${Math.random()}` 652 | const password = "123456" 653 | 654 | const signupResponse = await axios.post(`${BACKEND_URL}/api/v1/signup`, { 655 | username, 656 | password, 657 | type: "admin" 658 | }); 659 | 660 | adminId = signupResponse.data.userId 661 | 662 | const response = await axios.post(`${BACKEND_URL}/api/v1/signin`, { 663 | username: username, 664 | password 665 | }) 666 | 667 | adminToken = response.data.token 668 | 669 | const userSignupResponse = await axios.post(`${BACKEND_URL}/api/v1/signup`, { 670 | username: username + "-user", 671 | password, 672 | type: "user" 673 | }); 674 | 675 | userId = userSignupResponse.data.userId 676 | 677 | const userSigninResponse = await axios.post(`${BACKEND_URL}/api/v1/signin`, { 678 | username: username + "-user", 679 | password 680 | }) 681 | 682 | userToken = userSigninResponse.data.token 683 | }); 684 | 685 | test("User is not able to hit admin Endpoints", async () => { 686 | const elementReponse = await axios.post(`${BACKEND_URL}/api/v1/admin/element`, { 687 | "imageUrl": "https://encrypted-tbn0.gstatic.com/shopping?q=tbn:ANd9GcRCRca3wAR4zjPPTzeIY9rSwbbqB6bB2hVkoTXN4eerXOIkJTG1GpZ9ZqSGYafQPToWy_JTcmV5RHXsAsWQC3tKnMlH_CsibsSZ5oJtbakq&usqp=CAE", 688 | "width": 1, 689 | "height": 1, 690 | "static": true 691 | }, { 692 | headers: { 693 | authorization: `Bearer ${userToken}` 694 | } 695 | }); 696 | 697 | const mapResponse = await axios.post(`${BACKEND_URL}/api/v1/admin/map`, { 698 | "thumbnail": "https://thumbnail.com/a.png", 699 | "dimensions": "100x200", 700 | "name": "test space", 701 | "defaultElements": [] 702 | }, { 703 | headers: { 704 | authorization: `Bearer ${userToken}` 705 | } 706 | }) 707 | 708 | const avatarResponse = await axios.post(`${BACKEND_URL}/api/v1/admin/avatar`, { 709 | "imageUrl": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQm3RFDZM21teuCMFYx_AROjt-AzUwDBROFww&s", 710 | "name": "Timmy" 711 | }, { 712 | headers: { 713 | "authorization": `Bearer ${userToken}` 714 | } 715 | }) 716 | 717 | const updateElementResponse = await axios.put(`${BACKEND_URL}/api/v1/admin/element/123`, { 718 | "imageUrl": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQm3RFDZM21teuCMFYx_AROjt-AzUwDBROFww&s", 719 | }, { 720 | headers: { 721 | "authorization": `Bearer ${userToken}` 722 | } 723 | }) 724 | 725 | expect(elementReponse.status).toBe(403) 726 | expect(mapResponse.status).toBe(403) 727 | expect(avatarResponse.status).toBe(403) 728 | expect(updateElementResponse.status).toBe(403) 729 | }) 730 | 731 | test("Admin is able to hit admin Endpoints", async () => { 732 | const elementReponse = await axios.post(`${BACKEND_URL}/api/v1/admin/element`, { 733 | "imageUrl": "https://encrypted-tbn0.gstatic.com/shopping?q=tbn:ANd9GcRCRca3wAR4zjPPTzeIY9rSwbbqB6bB2hVkoTXN4eerXOIkJTG1GpZ9ZqSGYafQPToWy_JTcmV5RHXsAsWQC3tKnMlH_CsibsSZ5oJtbakq&usqp=CAE", 734 | "width": 1, 735 | "height": 1, 736 | "static": true 737 | }, { 738 | headers: { 739 | authorization: `Bearer ${adminToken}` 740 | } 741 | }); 742 | 743 | const mapResponse = await axios.post(`${BACKEND_URL}/api/v1/admin/map`, { 744 | "thumbnail": "https://thumbnail.com/a.png", 745 | "name": "Space", 746 | "dimensions": "100x200", 747 | "defaultElements": [] 748 | }, { 749 | headers: { 750 | authorization: `Bearer ${adminToken}` 751 | } 752 | }) 753 | 754 | const avatarResponse = await axios.post(`${BACKEND_URL}/api/v1/admin/avatar`, { 755 | "imageUrl": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQm3RFDZM21teuCMFYx_AROjt-AzUwDBROFww&s", 756 | "name": "Timmy" 757 | }, { 758 | headers: { 759 | "authorization": `Bearer ${adminToken}` 760 | } 761 | }) 762 | expect(elementReponse.status).toBe(200) 763 | expect(mapResponse.status).toBe(200) 764 | expect(avatarResponse.status).toBe(200) 765 | }) 766 | 767 | test("Admin is able to update the imageUrl for an element", async () => { 768 | const elementResponse = await axios.post(`${BACKEND_URL}/api/v1/admin/element`, { 769 | "imageUrl": "https://encrypted-tbn0.gstatic.com/shopping?q=tbn:ANd9GcRCRca3wAR4zjPPTzeIY9rSwbbqB6bB2hVkoTXN4eerXOIkJTG1GpZ9ZqSGYafQPToWy_JTcmV5RHXsAsWQC3tKnMlH_CsibsSZ5oJtbakq&usqp=CAE", 770 | "width": 1, 771 | "height": 1, 772 | "static": true 773 | }, { 774 | headers: { 775 | authorization: `Bearer ${adminToken}` 776 | } 777 | }); 778 | 779 | const updateElementResponse = await axios.put(`${BACKEND_URL}/api/v1/admin/element/${elementResponse.data.id}`, { 780 | "imageUrl": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQm3RFDZM21teuCMFYx_AROjt-AzUwDBROFww&s", 781 | }, { 782 | headers: { 783 | "authorization": `Bearer ${adminToken}` 784 | } 785 | }) 786 | 787 | expect(updateElementResponse.status).toBe(200); 788 | 789 | }) 790 | }); 791 | 792 | describe("Websocket tests", () => { 793 | let adminToken; 794 | let adminUserId; 795 | let userToken; 796 | let adminId; 797 | let userId; 798 | let mapId; 799 | let element1Id; 800 | let element2Id; 801 | let spaceId; 802 | let ws1; 803 | let ws2; 804 | let ws1Messages = [] 805 | let ws2Messages = [] 806 | let userX; 807 | let userY; 808 | let adminX; 809 | let adminY; 810 | 811 | function waitForAndPopLatestMessage(messageArray) { 812 | return new Promise(resolve => { 813 | if (messageArray.length > 0) { 814 | resolve(messageArray.shift()) 815 | } else { 816 | let interval = setInterval(() => { 817 | if (messageArray.length > 0) { 818 | resolve(messageArray.shift()) 819 | clearInterval(interval) 820 | } 821 | }, 100) 822 | } 823 | }) 824 | } 825 | 826 | async function setupHTTP() { 827 | const username = `kirat-${Math.random()}` 828 | const password = "123456" 829 | const adminSignupResponse = await axios.post(`${BACKEND_URL}/api/v1/signup`, { 830 | username, 831 | password, 832 | type: "admin" 833 | }) 834 | 835 | const adminSigninResponse = await axios.post(`${BACKEND_URL}/api/v1/signin`, { 836 | username, 837 | password 838 | }) 839 | 840 | adminUserId = adminSignupResponse.data.userId; 841 | adminToken = adminSigninResponse.data.token; 842 | console.log("adminSignupResponse.status") 843 | console.log(adminSignupResponse.status) 844 | 845 | const userSignupResponse = await axios.post(`${BACKEND_URL}/api/v1/signup`, { 846 | username: username + `-user`, 847 | password, 848 | type: "user" 849 | }) 850 | const userSigninResponse = await axios.post(`${BACKEND_URL}/api/v1/signin`, { 851 | username: username + `-user`, 852 | password 853 | }) 854 | userId = userSignupResponse.data.userId 855 | userToken = userSigninResponse.data.token 856 | console.log("useroktne", userToken) 857 | const element1Response = await axios.post(`${BACKEND_URL}/api/v1/admin/element`, { 858 | "imageUrl": "https://encrypted-tbn0.gstatic.com/shopping?q=tbn:ANd9GcRCRca3wAR4zjPPTzeIY9rSwbbqB6bB2hVkoTXN4eerXOIkJTG1GpZ9ZqSGYafQPToWy_JTcmV5RHXsAsWQC3tKnMlH_CsibsSZ5oJtbakq&usqp=CAE", 859 | "width": 1, 860 | "height": 1, 861 | "static": true 862 | }, { 863 | headers: { 864 | authorization: `Bearer ${adminToken}` 865 | } 866 | }); 867 | 868 | const element2Response = await axios.post(`${BACKEND_URL}/api/v1/admin/element`, { 869 | "imageUrl": "https://encrypted-tbn0.gstatic.com/shopping?q=tbn:ANd9GcRCRca3wAR4zjPPTzeIY9rSwbbqB6bB2hVkoTXN4eerXOIkJTG1GpZ9ZqSGYafQPToWy_JTcmV5RHXsAsWQC3tKnMlH_CsibsSZ5oJtbakq&usqp=CAE", 870 | "width": 1, 871 | "height": 1, 872 | "static": true 873 | }, { 874 | headers: { 875 | authorization: `Bearer ${adminToken}` 876 | } 877 | }) 878 | element1Id = element1Response.data.id 879 | element2Id = element2Response.data.id 880 | 881 | const mapResponse = await axios.post(`${BACKEND_URL}/api/v1/admin/map`, { 882 | "thumbnail": "https://thumbnail.com/a.png", 883 | "dimensions": "100x200", 884 | "name": "Defaul space", 885 | "defaultElements": [{ 886 | elementId: element1Id, 887 | x: 20, 888 | y: 20 889 | }, { 890 | elementId: element1Id, 891 | x: 18, 892 | y: 20 893 | }, { 894 | elementId: element2Id, 895 | x: 19, 896 | y: 20 897 | } 898 | ] 899 | }, { 900 | headers: { 901 | authorization: `Bearer ${adminToken}` 902 | } 903 | }) 904 | mapId = mapResponse.data.id 905 | 906 | const spaceResponse = await axios.post(`${BACKEND_URL}/api/v1/space`, { 907 | "name": "Test", 908 | "dimensions": "100x200", 909 | "mapId": mapId 910 | }, {headers: { 911 | "authorization": `Bearer ${userToken}` 912 | }}) 913 | 914 | console.log(spaceResponse.status) 915 | spaceId = spaceResponse.data.spaceId 916 | } 917 | async function setupWs() { 918 | ws1 = new WebSocket(WS_URL) 919 | 920 | ws1.onmessage = (event) => { 921 | console.log("got back adata 1") 922 | console.log(event.data) 923 | 924 | ws1Messages.push(JSON.parse(event.data)) 925 | } 926 | await new Promise(r => { 927 | ws1.onopen = r 928 | }) 929 | 930 | ws2 = new WebSocket(WS_URL) 931 | 932 | ws2.onmessage = (event) => { 933 | console.log("got back data 2") 934 | console.log(event.data) 935 | ws2Messages.push(JSON.parse(event.data)) 936 | } 937 | await new Promise(r => { 938 | ws2.onopen = r 939 | }) 940 | } 941 | 942 | beforeAll(async () => { 943 | await setupHTTP() 944 | await setupWs() 945 | }) 946 | 947 | test("Get back ack for joining the space", async () => { 948 | console.log("insixce first test") 949 | ws1.send(JSON.stringify({ 950 | "type": "join", 951 | "payload": { 952 | "spaceId": spaceId, 953 | "token": adminToken 954 | } 955 | })) 956 | console.log("insixce first test1") 957 | const message1 = await waitForAndPopLatestMessage(ws1Messages); 958 | console.log("insixce first test2") 959 | ws2.send(JSON.stringify({ 960 | "type": "join", 961 | "payload": { 962 | "spaceId": spaceId, 963 | "token": userToken 964 | } 965 | })) 966 | console.log("insixce first test3") 967 | 968 | const message2 = await waitForAndPopLatestMessage(ws2Messages); 969 | const message3 = await waitForAndPopLatestMessage(ws1Messages); 970 | 971 | expect(message1.type).toBe("space-joined") 972 | expect(message2.type).toBe("space-joined") 973 | expect(message1.payload.users.length).toBe(0) 974 | expect(message2.payload.users.length).toBe(1) 975 | expect(message3.type).toBe("user-joined"); 976 | expect(message3.payload.x).toBe(message2.payload.spawn.x); 977 | expect(message3.payload.y).toBe(message2.payload.spawn.y); 978 | expect(message3.payload.userId).toBe(userId); 979 | 980 | adminX = message1.payload.spawn.x 981 | adminY = message1.payload.spawn.y 982 | 983 | userX = message2.payload.spawn.x 984 | userY = message2.payload.spawn.y 985 | }) 986 | 987 | test("User should not be able to move across the boundary of the wall", async () => { 988 | ws1.send(JSON.stringify({ 989 | type: "move", 990 | payload: { 991 | x: 1000000, 992 | y: 10000 993 | } 994 | })); 995 | 996 | const message = await waitForAndPopLatestMessage(ws1Messages); 997 | expect(message.type).toBe("movement-rejected") 998 | expect(message.payload.x).toBe(adminX) 999 | expect(message.payload.y).toBe(adminY) 1000 | }) 1001 | 1002 | test("User should not be able to move two blocks at the same time", async () => { 1003 | ws1.send(JSON.stringify({ 1004 | type: "move", 1005 | payload: { 1006 | x: adminX + 2, 1007 | y: adminY 1008 | } 1009 | })); 1010 | 1011 | const message = await waitForAndPopLatestMessage(ws1Messages); 1012 | expect(message.type).toBe("movement-rejected") 1013 | expect(message.payload.x).toBe(adminX) 1014 | expect(message.payload.y).toBe(adminY) 1015 | }) 1016 | 1017 | test("Correct movement should be broadcasted to the other sockets in the room",async () => { 1018 | ws1.send(JSON.stringify({ 1019 | type: "move", 1020 | payload: { 1021 | x: adminX + 1, 1022 | y: adminY, 1023 | userId: adminId 1024 | } 1025 | })); 1026 | 1027 | const message = await waitForAndPopLatestMessage(ws2Messages); 1028 | expect(message.type).toBe("movement") 1029 | expect(message.payload.x).toBe(adminX + 1) 1030 | expect(message.payload.y).toBe(adminY) 1031 | }) 1032 | 1033 | test("If a user leaves, the other user receives a leave event", async () => { 1034 | ws1.close() 1035 | const message = await waitForAndPopLatestMessage(ws2Messages); 1036 | expect(message.type).toBe("user-left") 1037 | expect(message.payload.userId).toBe(adminUserId) 1038 | }) 1039 | }) -------------------------------------------------------------------------------- /tests/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tests", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "scripts": { 6 | "test": "jest" 7 | }, 8 | "keywords": [], 9 | "author": "", 10 | "license": "ISC", 11 | "description": "", 12 | "devDependencies": { 13 | "jest": "^29.7.0" 14 | }, 15 | "dependencies": { 16 | "axios": "^1.7.7" 17 | } 18 | } 19 | --------------------------------------------------------------------------------