diff --git a/.env b/.env new file mode 100644 index 0000000..402820f --- /dev/null +++ b/.env @@ -0,0 +1,5 @@ +PORT=3001 +DB_URL=postgres://postgres:v1sq3vD5faXL@194.26.138.94:5432/mate +JWT_SECRET=722fdcd1d98ae1a56b285db89d4df8a608fba313910210183c0a2caf558cce62 +JWT_EXPIRATION=30d +HMAC_SECRET=9a9ccda5db157ccfd04b4094264c55f58097f85d1fd6c22fbab0a86680dd3efd \ No newline at end of file diff --git a/.gitignore b/.gitignore index 87e5610..6ca856c 100644 --- a/.gitignore +++ b/.gitignore @@ -13,7 +13,7 @@ /out/ # production -/build +/dist # misc .DS_Store diff --git a/bun.build.ts b/bun.build.ts new file mode 100644 index 0000000..e18b185 --- /dev/null +++ b/bun.build.ts @@ -0,0 +1,31 @@ +import { $, Glob } from "bun"; +import path from "path"; + +// Cross-platform directory removal +if (process.platform === "win32") { + // await $`cmd /c "rmdir /s /q dist"`; +} else { + await $`rm -rf ./dist`; +} + +// await Bun.build({ +// entrypoints: ["./src/index.ts"], +// env: "inline", +// target: "bun", +// outdir: `./dist`, +// minify: true, +// }); + +// Build all files in src +for (const entrypoint of new Glob("./src/**/*.ts").scanSync()) { + const parts = entrypoint.split(path.sep); + const entrypointPath = path.join(...parts.slice(2, -1)); + + await Bun.build({ + entrypoints: [entrypoint], + target: "bun", + outdir: path.join("dist", entrypointPath), + env: "inline", + minify: true, + }); +} diff --git a/bun.lock b/bun.lock new file mode 100644 index 0000000..f76ce9a --- /dev/null +++ b/bun.lock @@ -0,0 +1,284 @@ +{ + "lockfileVersion": 1, + "workspaces": { + "": { + "name": "graff-mate-server", + "dependencies": { + "@elysiajs/cors": "^1.2.0", + "drizzle-orm": "^0.40.0", + "elysia": "latest", + "jose": "^6.0.10", + "postgres": "^3.4.5", + }, + "devDependencies": { + "@types/bun": "^1.2.5", + "bun-types": "latest", + "drizzle-kit": "^0.30.5", + "tsx": "^4.19.3", + }, + }, + }, + "packages": { + "@drizzle-team/brocli": ["@drizzle-team/brocli@0.10.2", "", {}, "sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w=="], + + "@elysiajs/cors": ["@elysiajs/cors@1.2.0", "", { "peerDependencies": { "elysia": ">= 1.2.0" } }, "sha512-qsJwDAg6WfdQRMfj6uSMcDPSpXvm/zQFeAX1uuJXhIgazH8itSfcDxcH9pMuXVRX1yQNi2pPwNQLJmAcw5mzvw=="], + + "@esbuild-kit/core-utils": ["@esbuild-kit/core-utils@3.3.2", "", { "dependencies": { "esbuild": "~0.18.20", "source-map-support": "^0.5.21" } }, "sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ=="], + + "@esbuild-kit/esm-loader": ["@esbuild-kit/esm-loader@2.6.5", "", { "dependencies": { "@esbuild-kit/core-utils": "^3.3.2", "get-tsconfig": "^4.7.0" } }, "sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA=="], + + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.19.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA=="], + + "@esbuild/android-arm": ["@esbuild/android-arm@0.19.12", "", { "os": "android", "cpu": "arm" }, "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w=="], + + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.19.12", "", { "os": "android", "cpu": "arm64" }, "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA=="], + + "@esbuild/android-x64": ["@esbuild/android-x64@0.19.12", "", { "os": "android", "cpu": "x64" }, "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew=="], + + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.19.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g=="], + + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.19.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A=="], + + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.19.12", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA=="], + + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.19.12", "", { "os": "freebsd", "cpu": "x64" }, "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg=="], + + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.19.12", "", { "os": "linux", "cpu": "arm" }, "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w=="], + + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.19.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA=="], + + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.19.12", "", { "os": "linux", "cpu": "ia32" }, "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA=="], + + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.19.12", "", { "os": "linux", "cpu": "none" }, "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA=="], + + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.19.12", "", { "os": "linux", "cpu": "none" }, "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w=="], + + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.19.12", "", { "os": "linux", "cpu": "ppc64" }, "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg=="], + + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.19.12", "", { "os": "linux", "cpu": "none" }, "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg=="], + + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.19.12", "", { "os": "linux", "cpu": "s390x" }, "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg=="], + + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.19.12", "", { "os": "linux", "cpu": "x64" }, "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg=="], + + "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.1", "", { "os": "none", "cpu": "arm64" }, "sha512-O96poM2XGhLtpTh+s4+nP7YCCAfb4tJNRVZHfIE7dgmax+yMP2WgMd2OecBuaATHKTHsLWHQeuaxMRnCsH8+5g=="], + + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.19.12", "", { "os": "none", "cpu": "x64" }, "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA=="], + + "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.1", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-Na9T3szbXezdzM/Kfs3GcRQNjHzM6GzFBeU1/6IV/npKP5ORtp9zbQjvkDJ47s6BCgaAZnnnu/cY1x342+MvZg=="], + + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.19.12", "", { "os": "openbsd", "cpu": "x64" }, "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw=="], + + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.19.12", "", { "os": "sunos", "cpu": "x64" }, "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA=="], + + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.19.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A=="], + + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.19.12", "", { "os": "win32", "cpu": "ia32" }, "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ=="], + + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.19.12", "", { "os": "win32", "cpu": "x64" }, "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA=="], + + "@petamoriken/float16": ["@petamoriken/float16@3.9.2", "", {}, "sha512-VgffxawQde93xKxT3qap3OH+meZf7VaSB5Sqd4Rqc+FP5alWbpOyan/7tRbOAvynjpG3GpdtAuGU/NdhQpmrog=="], + + "@sinclair/typebox": ["@sinclair/typebox@0.34.30", "", {}, "sha512-gFB3BiqjDxEoadW0zn+xyMVb7cLxPCoblVn2C/BKpI41WPYi2d6fwHAlynPNZ5O/Q4WEiujdnJzVtvG/Jc2CBQ=="], + + "@types/bun": ["@types/bun@1.2.5", "", { "dependencies": { "bun-types": "1.2.5" } }, "sha512-w2OZTzrZTVtbnJew1pdFmgV99H0/L+Pvw+z1P67HaR18MHOzYnTYOi6qzErhK8HyT+DB782ADVPPE92Xu2/Opg=="], + + "@types/node": ["@types/node@22.13.10", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-I6LPUvlRH+O6VRUqYOcMudhaIdUVWfsjnZavnsraHvpBwaEyMN29ry+0UVJhImYL16xsscu0aske3yA+uPOWfw=="], + + "@types/pg": ["@types/pg@8.11.11", "", { "dependencies": { "@types/node": "*", "pg-protocol": "*", "pg-types": "^4.0.1" } }, "sha512-kGT1qKM8wJQ5qlawUrEkXgvMSXoV213KfMGXcwfDwUIfUHXqXYXOfS1nE1LINRJVVVx5wCm70XnFlMHaIcQAfw=="], + + "@types/ws": ["@types/ws@8.5.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-bd/YFLW+URhBzMXurx7lWByOu+xzU9+kb3RboOteXYDfW+tr+JZa99OyNmPINEGB/ahzKrEuc8rcv4gnpJmxTw=="], + + "buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="], + + "bun-types": ["bun-types@1.2.5", "", { "dependencies": { "@types/node": "*", "@types/ws": "~8.5.10" } }, "sha512-3oO6LVGGRRKI4kHINx5PIdIgnLRb7l/SprhzqXapmoYkFl5m4j6EvALvbDVuuBFaamB46Ap6HCUxIXNLCGy+tg=="], + + "cookie": ["cookie@1.0.2", "", {}, "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA=="], + + "debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="], + + "drizzle-kit": ["drizzle-kit@0.30.5", "", { "dependencies": { "@drizzle-team/brocli": "^0.10.2", "@esbuild-kit/esm-loader": "^2.5.5", "esbuild": "^0.19.7", "esbuild-register": "^3.5.0", "gel": "^2.0.0" }, "bin": { "drizzle-kit": "bin.cjs" } }, "sha512-l6dMSE100u7sDaTbLczibrQZjA35jLsHNqIV+jmhNVO3O8jzM6kywMOmV9uOz9ZVSCMPQhAZEFjL/qDPVrqpUA=="], + + "drizzle-orm": ["drizzle-orm@0.40.0", "", { "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=4", "@electric-sql/pglite": ">=0.2.0", "@libsql/client": ">=0.10.0", "@libsql/client-wasm": ">=0.10.0", "@neondatabase/serverless": ">=0.10.0", "@op-engineering/op-sqlite": ">=2", "@opentelemetry/api": "^1.4.1", "@planetscale/database": ">=1", "@prisma/client": "*", "@tidbcloud/serverless": "*", "@types/better-sqlite3": "*", "@types/pg": "*", "@types/sql.js": "*", "@vercel/postgres": ">=0.8.0", "@xata.io/client": "*", "better-sqlite3": ">=7", "bun-types": "*", "expo-sqlite": ">=14.0.0", "gel": ">=2", "knex": "*", "kysely": "*", "mysql2": ">=2", "pg": ">=8", "postgres": ">=3", "sql.js": ">=1", "sqlite3": ">=5" }, "optionalPeers": ["@aws-sdk/client-rds-data", "@cloudflare/workers-types", "@electric-sql/pglite", "@libsql/client", "@libsql/client-wasm", "@neondatabase/serverless", "@op-engineering/op-sqlite", "@opentelemetry/api", "@planetscale/database", "@prisma/client", "@tidbcloud/serverless", "@types/better-sqlite3", "@types/pg", "@types/sql.js", "@vercel/postgres", "@xata.io/client", "better-sqlite3", "bun-types", "expo-sqlite", "gel", "knex", "kysely", "mysql2", "pg", "postgres", "sql.js", "sqlite3"] }, "sha512-7ptk/HQiMSrEZHnAsSlBESXWj52VwgMmyTEfoNmpNN2ZXpcz13LwHfXTIghsAEud7Z5UJhDOp8U07ujcqme7wg=="], + + "elysia": ["elysia@1.2.25", "", { "dependencies": { "@sinclair/typebox": "^0.34.27", "cookie": "^1.0.2", "memoirist": "^0.3.0", "openapi-types": "^12.1.3" }, "peerDependencies": { "typescript": ">= 5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-WsdQpORJvb4uszzeqYT0lg97knw1iBW1NTzJ1Jm57tiHg+DfAotlWXYbjmvQ039ssV0fYELDHinLLoUazZkEHg=="], + + "env-paths": ["env-paths@3.0.0", "", {}, "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A=="], + + "esbuild": ["esbuild@0.19.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.19.12", "@esbuild/android-arm": "0.19.12", "@esbuild/android-arm64": "0.19.12", "@esbuild/android-x64": "0.19.12", "@esbuild/darwin-arm64": "0.19.12", "@esbuild/darwin-x64": "0.19.12", "@esbuild/freebsd-arm64": "0.19.12", "@esbuild/freebsd-x64": "0.19.12", "@esbuild/linux-arm": "0.19.12", "@esbuild/linux-arm64": "0.19.12", "@esbuild/linux-ia32": "0.19.12", "@esbuild/linux-loong64": "0.19.12", "@esbuild/linux-mips64el": "0.19.12", "@esbuild/linux-ppc64": "0.19.12", "@esbuild/linux-riscv64": "0.19.12", "@esbuild/linux-s390x": "0.19.12", "@esbuild/linux-x64": "0.19.12", "@esbuild/netbsd-x64": "0.19.12", "@esbuild/openbsd-x64": "0.19.12", "@esbuild/sunos-x64": "0.19.12", "@esbuild/win32-arm64": "0.19.12", "@esbuild/win32-ia32": "0.19.12", "@esbuild/win32-x64": "0.19.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg=="], + + "esbuild-register": ["esbuild-register@3.6.0", "", { "dependencies": { "debug": "^4.3.4" }, "peerDependencies": { "esbuild": ">=0.12 <1" } }, "sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg=="], + + "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], + + "gel": ["gel@2.0.1", "", { "dependencies": { "@petamoriken/float16": "^3.8.7", "debug": "^4.3.4", "env-paths": "^3.0.0", "semver": "^7.6.2", "shell-quote": "^1.8.1", "which": "^4.0.0" }, "bin": { "gel": "dist/cli.mjs" } }, "sha512-gfem3IGvqKqXwEq7XseBogyaRwGsQGuE7Cw/yQsjLGdgiyqX92G1xENPCE0ltunPGcsJIa6XBOTx/PK169mOqw=="], + + "get-tsconfig": ["get-tsconfig@4.10.0", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A=="], + + "isexe": ["isexe@3.1.1", "", {}, "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ=="], + + "jose": ["jose@6.0.10", "", {}, "sha512-skIAxZqcMkOrSwjJvplIPYrlXGpxTPnro2/QWTDCxAdWQrSTV5/KqspMWmi5WAx5+ULswASJiZ0a+1B/Lxt9cw=="], + + "memoirist": ["memoirist@0.3.0", "", {}, "sha512-wR+4chMgVPq+T6OOsk40u9Wlpw1Pjx66NMNiYxCQQ4EUJ7jDs3D9kTCeKdBOkvAiqXlHLVJlvYL01PvIJ1MPNg=="], + + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + + "obuf": ["obuf@1.1.2", "", {}, "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg=="], + + "openapi-types": ["openapi-types@12.1.3", "", {}, "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="], + + "pg": ["pg@8.14.0", "", { "dependencies": { "pg-connection-string": "^2.7.0", "pg-pool": "^3.8.0", "pg-protocol": "^1.8.0", "pg-types": "^2.1.0", "pgpass": "1.x" }, "optionalDependencies": { "pg-cloudflare": "^1.1.1" }, "peerDependencies": { "pg-native": ">=3.0.1" }, "optionalPeers": ["pg-native"] }, "sha512-nXbVpyoaXVmdqlKEzToFf37qzyeeh7mbiXsnoWvstSqohj88yaa/I/Rq/HEVn2QPSZEuLIJa/jSpRDyzjEx4FQ=="], + + "pg-cloudflare": ["pg-cloudflare@1.1.1", "", {}, "sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q=="], + + "pg-connection-string": ["pg-connection-string@2.7.0", "", {}, "sha512-PI2W9mv53rXJQEOb8xNR8lH7Hr+EKa6oJa38zsK0S/ky2er16ios1wLKhZyxzD7jUReiWokc9WK5nxSnC7W1TA=="], + + "pg-int8": ["pg-int8@1.0.1", "", {}, "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw=="], + + "pg-numeric": ["pg-numeric@1.0.2", "", {}, "sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw=="], + + "pg-pool": ["pg-pool@3.8.0", "", { "peerDependencies": { "pg": ">=8.0" } }, "sha512-VBw3jiVm6ZOdLBTIcXLNdSotb6Iy3uOCwDGFAksZCXmi10nyRvnP2v3jl4d+IsLYRyXf6o9hIm/ZtUzlByNUdw=="], + + "pg-protocol": ["pg-protocol@1.8.0", "", {}, "sha512-jvuYlEkL03NRvOoyoRktBK7+qU5kOvlAwvmrH8sr3wbLrOdVWsRxQfz8mMy9sZFsqJ1hEWNfdWKI4SAmoL+j7g=="], + + "pg-types": ["pg-types@4.0.2", "", { "dependencies": { "pg-int8": "1.0.1", "pg-numeric": "1.0.2", "postgres-array": "~3.0.1", "postgres-bytea": "~3.0.0", "postgres-date": "~2.1.0", "postgres-interval": "^3.0.0", "postgres-range": "^1.1.1" } }, "sha512-cRL3JpS3lKMGsKaWndugWQoLOCoP+Cic8oseVcbr0qhPzYD5DWXK+RZ9LY9wxRf7RQia4SCwQlXk0q6FCPrVng=="], + + "pgpass": ["pgpass@1.0.5", "", { "dependencies": { "split2": "^4.1.0" } }, "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug=="], + + "postgres": ["postgres@3.4.5", "", {}, "sha512-cDWgoah1Gez9rN3H4165peY9qfpEo+SA61oQv65O3cRUE1pOEoJWwddwcqKE8XZYjbblOJlYDlLV4h67HrEVDg=="], + + "postgres-array": ["postgres-array@3.0.4", "", {}, "sha512-nAUSGfSDGOaOAEGwqsRY27GPOea7CNipJPOA7lPbdEpx5Kg3qzdP0AaWC5MlhTWV9s4hFX39nomVZ+C4tnGOJQ=="], + + "postgres-bytea": ["postgres-bytea@3.0.0", "", { "dependencies": { "obuf": "~1.1.2" } }, "sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw=="], + + "postgres-date": ["postgres-date@2.1.0", "", {}, "sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA=="], + + "postgres-interval": ["postgres-interval@3.0.0", "", {}, "sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw=="], + + "postgres-range": ["postgres-range@1.1.4", "", {}, "sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w=="], + + "resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="], + + "semver": ["semver@7.7.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA=="], + + "shell-quote": ["shell-quote@1.8.2", "", {}, "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA=="], + + "source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], + + "source-map-support": ["source-map-support@0.5.21", "", { "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w=="], + + "split2": ["split2@4.2.0", "", {}, "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg=="], + + "tsx": ["tsx@4.19.3", "", { "dependencies": { "esbuild": "~0.25.0", "get-tsconfig": "^4.7.5" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "bin": { "tsx": "dist/cli.mjs" } }, "sha512-4H8vUNGNjQ4V2EOoGw005+c+dGuPSnhpPBPHBtsZdGZBk/iJb4kguGlPWaZTZ3q5nMtFOEsY0nRDlh9PJyd6SQ=="], + + "undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], + + "which": ["which@4.0.0", "", { "dependencies": { "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg=="], + + "xtend": ["xtend@4.0.2", "", {}, "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="], + + "@esbuild-kit/core-utils/esbuild": ["esbuild@0.18.20", "", { "optionalDependencies": { "@esbuild/android-arm": "0.18.20", "@esbuild/android-arm64": "0.18.20", "@esbuild/android-x64": "0.18.20", "@esbuild/darwin-arm64": "0.18.20", "@esbuild/darwin-x64": "0.18.20", "@esbuild/freebsd-arm64": "0.18.20", "@esbuild/freebsd-x64": "0.18.20", "@esbuild/linux-arm": "0.18.20", "@esbuild/linux-arm64": "0.18.20", "@esbuild/linux-ia32": "0.18.20", "@esbuild/linux-loong64": "0.18.20", "@esbuild/linux-mips64el": "0.18.20", "@esbuild/linux-ppc64": "0.18.20", "@esbuild/linux-riscv64": "0.18.20", "@esbuild/linux-s390x": "0.18.20", "@esbuild/linux-x64": "0.18.20", "@esbuild/netbsd-x64": "0.18.20", "@esbuild/openbsd-x64": "0.18.20", "@esbuild/sunos-x64": "0.18.20", "@esbuild/win32-arm64": "0.18.20", "@esbuild/win32-ia32": "0.18.20", "@esbuild/win32-x64": "0.18.20" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA=="], + + "pg/pg-types": ["pg-types@2.2.0", "", { "dependencies": { "pg-int8": "1.0.1", "postgres-array": "~2.0.0", "postgres-bytea": "~1.0.0", "postgres-date": "~1.0.4", "postgres-interval": "^1.1.0" } }, "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA=="], + + "tsx/esbuild": ["esbuild@0.25.1", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.1", "@esbuild/android-arm": "0.25.1", "@esbuild/android-arm64": "0.25.1", "@esbuild/android-x64": "0.25.1", "@esbuild/darwin-arm64": "0.25.1", "@esbuild/darwin-x64": "0.25.1", "@esbuild/freebsd-arm64": "0.25.1", "@esbuild/freebsd-x64": "0.25.1", "@esbuild/linux-arm": "0.25.1", "@esbuild/linux-arm64": "0.25.1", "@esbuild/linux-ia32": "0.25.1", "@esbuild/linux-loong64": "0.25.1", "@esbuild/linux-mips64el": "0.25.1", "@esbuild/linux-ppc64": "0.25.1", "@esbuild/linux-riscv64": "0.25.1", "@esbuild/linux-s390x": "0.25.1", "@esbuild/linux-x64": "0.25.1", "@esbuild/netbsd-arm64": "0.25.1", "@esbuild/netbsd-x64": "0.25.1", "@esbuild/openbsd-arm64": "0.25.1", "@esbuild/openbsd-x64": "0.25.1", "@esbuild/sunos-x64": "0.25.1", "@esbuild/win32-arm64": "0.25.1", "@esbuild/win32-ia32": "0.25.1", "@esbuild/win32-x64": "0.25.1" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-BGO5LtrGC7vxnqucAe/rmvKdJllfGaYWdyABvyMoXQlfYMb2bbRuReWR5tEGE//4LcNJj9XrkovTqNYRFZHAMQ=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.18.20", "", { "os": "android", "cpu": "arm" }, "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.18.20", "", { "os": "android", "cpu": "arm64" }, "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.18.20", "", { "os": "android", "cpu": "x64" }, "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.18.20", "", { "os": "darwin", "cpu": "arm64" }, "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.18.20", "", { "os": "darwin", "cpu": "x64" }, "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.18.20", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.18.20", "", { "os": "freebsd", "cpu": "x64" }, "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.18.20", "", { "os": "linux", "cpu": "arm" }, "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.18.20", "", { "os": "linux", "cpu": "arm64" }, "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.18.20", "", { "os": "linux", "cpu": "ia32" }, "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.18.20", "", { "os": "linux", "cpu": "ppc64" }, "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.18.20", "", { "os": "linux", "cpu": "s390x" }, "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.18.20", "", { "os": "linux", "cpu": "x64" }, "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.18.20", "", { "os": "none", "cpu": "x64" }, "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.18.20", "", { "os": "openbsd", "cpu": "x64" }, "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.18.20", "", { "os": "sunos", "cpu": "x64" }, "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.18.20", "", { "os": "win32", "cpu": "arm64" }, "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.18.20", "", { "os": "win32", "cpu": "ia32" }, "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g=="], + + "@esbuild-kit/core-utils/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.18.20", "", { "os": "win32", "cpu": "x64" }, "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ=="], + + "pg/pg-types/postgres-array": ["postgres-array@2.0.0", "", {}, "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA=="], + + "pg/pg-types/postgres-bytea": ["postgres-bytea@1.0.0", "", {}, "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w=="], + + "pg/pg-types/postgres-date": ["postgres-date@1.0.7", "", {}, "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q=="], + + "pg/pg-types/postgres-interval": ["postgres-interval@1.2.0", "", { "dependencies": { "xtend": "^4.0.0" } }, "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ=="], + + "tsx/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.1", "", { "os": "aix", "cpu": "ppc64" }, "sha512-kfYGy8IdzTGy+z0vFGvExZtxkFlA4zAxgKEahG9KE1ScBjpQnFsNOX8KTU5ojNru5ed5CVoJYXFtoxaq5nFbjQ=="], + + "tsx/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.25.1", "", { "os": "android", "cpu": "arm" }, "sha512-dp+MshLYux6j/JjdqVLnMglQlFu+MuVeNrmT5nk6q07wNhCdSnB7QZj+7G8VMUGh1q+vj2Bq8kRsuyA00I/k+Q=="], + + "tsx/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.1", "", { "os": "android", "cpu": "arm64" }, "sha512-50tM0zCJW5kGqgG7fQ7IHvQOcAn9TKiVRuQ/lN0xR+T2lzEFvAi1ZcS8DiksFcEpf1t/GYOeOfCAgDHFpkiSmA=="], + + "tsx/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.25.1", "", { "os": "android", "cpu": "x64" }, "sha512-GCj6WfUtNldqUzYkN/ITtlhwQqGWu9S45vUXs7EIYf+7rCiiqH9bCloatO9VhxsL0Pji+PF4Lz2XXCES+Q8hDw=="], + + "tsx/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-5hEZKPf+nQjYoSr/elb62U19/l1mZDdqidGfmFutVUjjUZrOazAtwK+Kr+3y0C/oeJfLlxo9fXb1w7L+P7E4FQ=="], + + "tsx/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-hxVnwL2Dqs3fM1IWq8Iezh0cX7ZGdVhbTfnOy5uURtao5OIVCEyj9xIzemDi7sRvKsuSdtCAhMKarxqtlyVyfA=="], + + "tsx/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.1", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-1MrCZs0fZa2g8E+FUo2ipw6jw5qqQiH+tERoS5fAfKnRx6NXH31tXBKI3VpmLijLH6yriMZsxJtaXUyFt/8Y4A=="], + + "tsx/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-0IZWLiTyz7nm0xuIs0q1Y3QWJC52R8aSXxe40VUxm6BB1RNmkODtW6LHvWRrGiICulcX7ZvyH6h5fqdLu4gkww=="], + + "tsx/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.1", "", { "os": "linux", "cpu": "arm" }, "sha512-NdKOhS4u7JhDKw9G3cY6sWqFcnLITn6SqivVArbzIaf3cemShqfLGHYMx8Xlm/lBit3/5d7kXvriTUGa5YViuQ=="], + + "tsx/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-jaN3dHi0/DDPelk0nLcXRm1q7DNJpjXy7yWaWvbfkPvI+7XNSc/lDOnCLN7gzsyzgu6qSAmgSvP9oXAhP973uQ=="], + + "tsx/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.1", "", { "os": "linux", "cpu": "ia32" }, "sha512-OJykPaF4v8JidKNGz8c/q1lBO44sQNUQtq1KktJXdBLn1hPod5rE/Hko5ugKKZd+D2+o1a9MFGUEIUwO2YfgkQ=="], + + "tsx/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.1", "", { "os": "linux", "cpu": "none" }, "sha512-nGfornQj4dzcq5Vp835oM/o21UMlXzn79KobKlcs3Wz9smwiifknLy4xDCLUU0BWp7b/houtdrgUz7nOGnfIYg=="], + + "tsx/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.1", "", { "os": "linux", "cpu": "none" }, "sha512-1osBbPEFYwIE5IVB/0g2X6i1qInZa1aIoj1TdL4AaAb55xIIgbg8Doq6a5BzYWgr+tEcDzYH67XVnTmUzL+nXg=="], + + "tsx/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-/6VBJOwUf3TdTvJZ82qF3tbLuWsscd7/1w+D9LH0W/SqUgM5/JJD0lrJ1fVIfZsqB6RFmLCe0Xz3fmZc3WtyVg=="], + + "tsx/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.1", "", { "os": "linux", "cpu": "none" }, "sha512-nSut/Mx5gnilhcq2yIMLMe3Wl4FK5wx/o0QuuCLMtmJn+WeWYoEGDN1ipcN72g1WHsnIbxGXd4i/MF0gTcuAjQ=="], + + "tsx/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-cEECeLlJNfT8kZHqLarDBQso9a27o2Zd2AQ8USAEoGtejOrCYHNtKP8XQhMDJMtthdF4GBmjR2au3x1udADQQQ=="], + + "tsx/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.1", "", { "os": "linux", "cpu": "x64" }, "sha512-xbfUhu/gnvSEg+EGovRc+kjBAkrvtk38RlerAzQxvMzlB4fXpCFCeUAYzJvrnhFtdeyVCDANSjJvOvGYoeKzFA=="], + + "tsx/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.1", "", { "os": "none", "cpu": "x64" }, "sha512-X53z6uXip6KFXBQ+Krbx25XHV/NCbzryM6ehOAeAil7X7oa4XIq+394PWGnwaSQ2WRA0KI6PUO6hTO5zeF5ijA=="], + + "tsx/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.1", "", { "os": "openbsd", "cpu": "x64" }, "sha512-T3H78X2h1tszfRSf+txbt5aOp/e7TAz3ptVKu9Oyir3IAOFPGV6O9c2naym5TOriy1l0nNf6a4X5UXRZSGX/dw=="], + + "tsx/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.1", "", { "os": "sunos", "cpu": "x64" }, "sha512-2H3RUvcmULO7dIE5EWJH8eubZAI4xw54H1ilJnRNZdeo8dTADEZ21w6J22XBkXqGJbe0+wnNJtw3UXRoLJnFEg=="], + + "tsx/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-GE7XvrdOzrb+yVKB9KsRMq+7a2U/K5Cf/8grVFRAGJmfADr/e/ODQ134RK2/eeHqYV5eQRFxb1hY7Nr15fv1NQ=="], + + "tsx/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-uOxSJCIcavSiT6UnBhBzE8wy3n0hOkJsBOzy7HDAuTDE++1DJMRRVCPGisULScHL+a/ZwdXPpXD3IyFKjA7K8A=="], + + "tsx/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.1", "", { "os": "win32", "cpu": "x64" }, "sha512-Y1EQdcfwMSeQN/ujR5VayLOJ1BHaK+ssyk0AEzPjC+t1lITgsnccPqFjb6V+LsTp/9Iov4ysfjxLaGJ9RPtkVg=="], + } +} diff --git a/drizzle.config.ts b/drizzle.config.ts new file mode 100644 index 0000000..7ad1070 --- /dev/null +++ b/drizzle.config.ts @@ -0,0 +1,11 @@ +import { defineConfig } from 'drizzle-kit'; + +export default defineConfig({ + dialect: 'postgresql', + schema: './src/db/schema/index.ts', + dbCredentials: { + url: process.env.DB_URL, + }, +}); + + diff --git a/env.d.ts b/env.d.ts new file mode 100644 index 0000000..7e2237e --- /dev/null +++ b/env.d.ts @@ -0,0 +1,9 @@ +declare namespace NodeJS { + interface ProcessEnv { + // readonly PORT: number; + readonly DB_URL: string; + readonly JWT_SECRET: string; + readonly JWT_EXPIRATION: string; + readonly HMAC_SECRET: string; + } +} diff --git a/package.json b/package.json index 8b2f0b2..43ad00d 100644 --- a/package.json +++ b/package.json @@ -1,15 +1,24 @@ { "name": "graff-mate-server", "version": "1.0.50", + "type": "module", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "dev": "bun run --watch src/index.ts" + "dev": "bun run --watch src/index.ts", + "build": "bun bun.build.ts" }, "dependencies": { - "elysia": "latest" + "@elysiajs/cors": "^1.2.0", + "drizzle-orm": "^0.40.0", + "elysia": "latest", + "jose": "^6.0.10", + "postgres": "^3.4.5" }, "devDependencies": { - "bun-types": "latest" + "@types/bun": "^1.2.5", + "bun-types": "latest", + "drizzle-kit": "^0.30.5", + "tsx": "^4.19.3" }, "module": "src/index.js" } \ No newline at end of file diff --git a/src/controllers/appsController.ts b/src/controllers/appsController.ts new file mode 100644 index 0000000..02e4971 --- /dev/null +++ b/src/controllers/appsController.ts @@ -0,0 +1,15 @@ +import Elysia, { t } from "elysia"; +import authMiddleware from "../middlewares/auth"; +import create from "../services/apps/create"; + +const appsController = new Elysia({ prefix: "/apps" }) + .use(authMiddleware) + .post("/", async ({ auth, body }) => await create(auth, body), { + body: t.Object({ + apps: t.Array(t.String()), + serverId: t.String(), + companyId: t.String(), + }), + }); + +export default appsController; diff --git a/src/controllers/authController.ts b/src/controllers/authController.ts new file mode 100644 index 0000000..b7708bb --- /dev/null +++ b/src/controllers/authController.ts @@ -0,0 +1,32 @@ +import { Elysia, t } from "elysia"; +import login from "../services/auth/login"; +import authMiddleware from "../middlewares/auth"; +import logout from "../services/auth/logout"; + +const authController = new Elysia({ prefix: "/auth" }) + .post("/login", async ({ body }) => await login(body), { + body: t.Object({ + email: t.String({ minLength: 1 }), + password: t.String({ minLength: 1 }), + }), + }) + // .post("/register", async ({}) => {}, { + // body: t.Object({ + // username: t.String({ minLength: 1 }), + // password: t.String({ minLength: 1 }), + // }), + // }) + .use(authMiddleware) + .get( + "/logout", + async ({ headers }) => { + const token = headers["authorization"].split(" ")[1]; + + return await logout(token); + }, + { + headers: t.Object({ authorization: t.String() }), + } + ); + +export default authController; diff --git a/src/controllers/clientsController.ts b/src/controllers/clientsController.ts new file mode 100644 index 0000000..bcdabf6 --- /dev/null +++ b/src/controllers/clientsController.ts @@ -0,0 +1,6 @@ +// import Elysia from "elysia"; +// import authMiddleware from "../middlewares/auth"; + +// export const clientsController = new Elysia({ prefix: "/clients" }) +// .use(authMiddleware) +// .get("/", async ({auth:{companyId}}) => {}, {}); diff --git a/src/controllers/serversController.ts b/src/controllers/serversController.ts new file mode 100644 index 0000000..abccad4 --- /dev/null +++ b/src/controllers/serversController.ts @@ -0,0 +1,18 @@ +import Elysia, { t } from "elysia"; +import getServers from "../services/servers/get"; +import authMiddleware from "../middlewares/auth"; +import createServer from "../services/servers/create"; + +const serversController = new Elysia({ prefix: "/servers" }) + .use(authMiddleware) + .get("/", async ({ auth, query }) => await getServers(auth, query)) + .post("/", async ({ auth, body }) => await createServer(auth, body), { + body: t.Object({ + hostname: t.String(), + name: t.String(), + location: t.String(), + companyId: t.String(), + }), + }); + +export default serversController; diff --git a/src/controllers/sessionsController.ts b/src/controllers/sessionsController.ts new file mode 100644 index 0000000..7000958 --- /dev/null +++ b/src/controllers/sessionsController.ts @@ -0,0 +1,62 @@ +import Elysia, { t } from "elysia"; +import authMiddleware from "../middlewares/auth"; +import createSession from "../services/sessions/create"; +import getSessions from "../services/sessions/get"; +import updateSession from "../services/sessions/update"; + +const sessionsController = new Elysia({ prefix: "/sessions" }) + .use(authMiddleware) + .get( + "/", + async ({ auth, query }) => { + return await getSessions(auth, query); + }, + { + query: t.Object({ limit: t.Optional(t.Number()) }), + } + ) + .post( + "/", + async ({ body, auth }) => { + return await createSession(auth, body); + }, + { + body: t.Object({ + appId: t.String(), + serverId: t.String(), + clientId: t.String(), + }), + } + ) + .put( + "/:id", + async ({ params, body }) => { + return await updateSession( + params.id, + body.status as + | "starting" + | "started" + | "restarting" + | "ending" + | "ended" + ); + }, + { + params: t.Object({ + id: t.String(), + }), + body: t.Object({ + status: t.Union([ + t.Literal("starting"), + t.Literal("started"), + t.Literal("restarting"), + t.Literal("ending"), + t.Literal("ended"), + t.Literal("null"), + t.Literal("undefined"), + ]), + }), + } + ); + +export default sessionsController; diff --git a/src/controllers/usersController.ts b/src/controllers/usersController.ts new file mode 100644 index 0000000..6220764 --- /dev/null +++ b/src/controllers/usersController.ts @@ -0,0 +1,18 @@ +import Elysia from "elysia"; +import authMiddleware from "../middlewares/auth"; +import me from "../services/user/me"; + +type AuthContext = { + auth: { + userId: string; + }; +}; + +const usersController = new Elysia({ prefix: "/users" }) + .use(authMiddleware) + .get("/me", async (context) => { + const userId = (context as AuthContext).auth.userId; + return await me(userId); + }); + +export default usersController; diff --git a/src/db/index.ts b/src/db/index.ts new file mode 100644 index 0000000..c1f4558 --- /dev/null +++ b/src/db/index.ts @@ -0,0 +1,8 @@ +import { drizzle } from "drizzle-orm/postgres-js"; +import postgres from "postgres"; +import * as schema from "./schema/index"; + +const client = postgres(process.env.DB_URL); +const db = drizzle({ client, schema }); + +export default db; diff --git a/src/db/schema/actions.ts b/src/db/schema/actions.ts new file mode 100644 index 0000000..f2d9525 --- /dev/null +++ b/src/db/schema/actions.ts @@ -0,0 +1,25 @@ +import { pgTable, timestamp, uuid, varchar } from "drizzle-orm/pg-core"; +import { serversTable } from "./servers"; +import { relations } from "drizzle-orm"; + +export const actionsTable = pgTable("actions", { + id: uuid("id").defaultRandom().primaryKey(), + name: varchar("name").notNull(), + serverId: uuid("server_id") + .notNull() + .references(() => serversTable.id), + createdAt: timestamp("created_at", { withTimezone: true }) + .notNull() + .defaultNow(), + updatedAt: timestamp("updated_at", { withTimezone: true }) + .notNull() + .defaultNow() + .$onUpdate(() => new Date()), +}); + +export const actionsRelations = relations(actionsTable, ({ one }) => ({ + server: one(serversTable, { + fields: [actionsTable.serverId], + references: [serversTable.id], + }), +})); diff --git a/src/db/schema/apps.ts b/src/db/schema/apps.ts new file mode 100644 index 0000000..55e6b50 --- /dev/null +++ b/src/db/schema/apps.ts @@ -0,0 +1,34 @@ +import { pgTable, timestamp, uuid, varchar } from "drizzle-orm/pg-core"; +import { companiesTable } from "./companies"; +import { relations } from "drizzle-orm"; +import { serversTable } from "./servers"; + +export const appsTable = pgTable("apps", { + id: uuid("id").defaultRandom().primaryKey(), + name: varchar("name").notNull(), + fileName: varchar("filename").notNull(), + serverId: uuid("server_id") + .notNull() + .references(() => serversTable.id), + companyId: uuid("company_id") + .notNull() + .references(() => companiesTable.id), + createdAt: timestamp("created_at", { withTimezone: true }) + .notNull() + .defaultNow(), + updatedAt: timestamp("updated_at", { withTimezone: true }) + .notNull() + .defaultNow() + .$onUpdate(() => new Date()), +}); + +export const appsRelations = relations(appsTable, ({ one }) => ({ + company: one(companiesTable, { + fields: [appsTable.companyId], + references: [companiesTable.id], + }), + server: one(serversTable, { + fields: [appsTable.serverId], + references: [serversTable.id], + }), +})); diff --git a/src/db/schema/clients.ts b/src/db/schema/clients.ts new file mode 100644 index 0000000..d473bda --- /dev/null +++ b/src/db/schema/clients.ts @@ -0,0 +1,29 @@ +import { pgTable, timestamp, uuid, varchar } from "drizzle-orm/pg-core"; +import { companiesTable } from "./companies"; +import { relations } from "drizzle-orm"; +import { sessionsTable } from "./sessions"; + +export const clientsTable = pgTable("clients", { + id: uuid("id").defaultRandom().primaryKey(), + fullname: varchar("fullname").notNull(), + email: varchar("email").notNull(), + phone: varchar("phone", { length: 15 }), + companyId: uuid("company_id") + .notNull() + .references(() => companiesTable.id), + createdAt: timestamp("created_at", { withTimezone: true }) + .notNull() + .defaultNow(), + updatedAt: timestamp("updated_at", { withTimezone: true }) + .notNull() + .defaultNow() + .$onUpdate(() => new Date()), +}); + +export const clientsRelations = relations(clientsTable, ({ one, many }) => ({ + company: one(companiesTable, { + fields: [clientsTable.companyId], + references: [companiesTable.id], + }), + sessions: many(sessionsTable), +})); diff --git a/src/db/schema/companies.ts b/src/db/schema/companies.ts new file mode 100644 index 0000000..b475dac --- /dev/null +++ b/src/db/schema/companies.ts @@ -0,0 +1,24 @@ +import { relations } from "drizzle-orm"; +import { pgTable, timestamp, uuid, varchar } from "drizzle-orm/pg-core"; +import { usersTable } from "./users"; +import { appsTable } from "./apps"; +import { serversTable } from "./servers"; + +export const companiesTable = pgTable("companies", { + id: uuid("id").defaultRandom().primaryKey(), + name: varchar("name").notNull(), + createdAt: timestamp("created_at", { withTimezone: true }) + .notNull() + .defaultNow(), + updatedAt: timestamp("updated_at", { withTimezone: true }) + .notNull() + .defaultNow() + .$onUpdate(() => new Date()), +}); + +export const companiesRelations = relations(companiesTable, ({ many }) => ({ + users: many(usersTable), + servers: many(serversTable), + apps: many(appsTable), + // actions: many(actionsTable), +})); diff --git a/src/db/schema/index.ts b/src/db/schema/index.ts new file mode 100644 index 0000000..b147edc --- /dev/null +++ b/src/db/schema/index.ts @@ -0,0 +1,8 @@ +export * from "./users"; +export * from "./tokens"; +export * from "./companies"; +export * from "./servers"; +export * from "./sessions"; +export * from "./clients"; +export * from "./apps"; +export * from "./actions"; diff --git a/src/db/schema/servers.ts b/src/db/schema/servers.ts new file mode 100644 index 0000000..655f076 --- /dev/null +++ b/src/db/schema/servers.ts @@ -0,0 +1,31 @@ +import { pgTable, timestamp, uuid, varchar } from "drizzle-orm/pg-core"; +import { companiesTable } from "./companies"; +import { actionsTable } from "./actions"; +import { relations } from "drizzle-orm"; +import { sessionsTable } from "./sessions"; + +export const serversTable = pgTable("servers", { + id: uuid("id").primaryKey().defaultRandom(), + hostname: varchar("hostname", { length: 15 }).unique().notNull(), + name: varchar("name").notNull(), + location: varchar("location").notNull(), + companyId: uuid("company_id") + .notNull() + .references(() => companiesTable.id), + createdAt: timestamp("created_at", { withTimezone: true }) + .notNull() + .defaultNow(), + updatedAt: timestamp("updated_at", { withTimezone: true }) + .notNull() + .defaultNow() + .$onUpdate(() => new Date()), +}); + +export const serversRelations = relations(serversTable, ({ one, many }) => ({ + company: one(companiesTable, { + fields: [serversTable.companyId], + references: [companiesTable.id], + }), + sessions: many(sessionsTable), + actions: many(actionsTable), +})); diff --git a/src/db/schema/sessions.ts b/src/db/schema/sessions.ts new file mode 100644 index 0000000..9b4a363 --- /dev/null +++ b/src/db/schema/sessions.ts @@ -0,0 +1,74 @@ +import { + pgTable, + timestamp, + uuid, + varchar, + uniqueIndex, +} from "drizzle-orm/pg-core"; +import { companiesTable } from "./companies"; +import { usersTable } from "./users"; +import { relations } from "drizzle-orm"; +import { serversTable } from "./servers"; +import { clientsTable } from "./clients"; +import { appsTable } from "./apps"; +import { sql } from "drizzle-orm"; + +export const sessionsTable = pgTable( + "sessions", + { + id: uuid("id").defaultRandom().primaryKey(), + status: varchar("status", { + enum: ["starting", "started", "restarting", "ending", "ended"], + }).notNull(), + appId: uuid("app_id") + .notNull() + .references(() => appsTable.id), + ownerId: uuid("owner_id") + .notNull() + .references(() => usersTable.id), + serverId: uuid("server_id") + .notNull() + .references(() => serversTable.id), + clientId: uuid("client_id") + .notNull() + .references(() => clientsTable.id), + companyId: uuid("company_id") + .notNull() + .references(() => companiesTable.id), + createdAt: timestamp("created_at", { withTimezone: true }) + .notNull() + .defaultNow(), + updatedAt: timestamp("updated_at", { withTimezone: true }) + .notNull() + .defaultNow() + .$onUpdate(() => new Date()), + }, + (table) => ({ + activeServerSessionIdx: uniqueIndex("active_server_session_idx") + .on(table.serverId, table.status) + .where(sql`${table.status} IN ('starting', 'started')`), + }) +); + +export const sessionsRelations = relations(sessionsTable, ({ one }) => ({ + owner: one(usersTable, { + fields: [sessionsTable.ownerId], + references: [usersTable.id], + }), + server: one(serversTable, { + fields: [sessionsTable.serverId], + references: [serversTable.id], + }), + company: one(companiesTable, { + fields: [sessionsTable.companyId], + references: [companiesTable.id], + }), + client: one(clientsTable, { + fields: [sessionsTable.clientId], + references: [clientsTable.id], + }), + app: one(appsTable, { + fields: [sessionsTable.appId], + references: [appsTable.id], + }), +})); diff --git a/src/db/schema/tokens.ts b/src/db/schema/tokens.ts new file mode 100644 index 0000000..3bda9b0 --- /dev/null +++ b/src/db/schema/tokens.ts @@ -0,0 +1,25 @@ +import { relations } from "drizzle-orm"; +import { pgTable, text, timestamp, uuid } from "drizzle-orm/pg-core"; +import { usersTable } from "./users"; + +export const tokensTable = pgTable("tokens", { + id: uuid("id").defaultRandom().primaryKey(), + token: text("token").notNull(), + userId: uuid("user_id") + .notNull() + .references(() => usersTable.id, { onDelete: "cascade" }), + createdAt: timestamp("created_at", { withTimezone: true }) + .notNull() + .defaultNow(), + updatedAt: timestamp("updated_at", { withTimezone: true }) + .notNull() + .defaultNow() + .$onUpdate(() => new Date()), +}); + +export const tokensRelations = relations(tokensTable, ({ one }) => ({ + user: one(usersTable, { + fields: [tokensTable.userId], + references: [usersTable.id], + }), +})); diff --git a/src/db/schema/users.ts b/src/db/schema/users.ts new file mode 100644 index 0000000..ce0999f --- /dev/null +++ b/src/db/schema/users.ts @@ -0,0 +1,30 @@ +import { relations } from "drizzle-orm"; +import { pgTable, text, timestamp, uuid, varchar } from "drizzle-orm/pg-core"; +import { tokensTable } from "./tokens"; +import { companiesTable } from "./companies"; + +export const usersTable = pgTable("users", { + id: uuid("id").defaultRandom().primaryKey(), + fullname: text("fullname"), + email: varchar("email").unique().notNull(), + password: varchar("password", { length: 72 }).notNull(), + // roles: text("roles").array().notNull(), + companyId: uuid("company_id") + .notNull() + .references(() => companiesTable.id), + createdAt: timestamp("created_at", { withTimezone: true }) + .notNull() + .defaultNow(), + updatedAt: timestamp("updated_at", { withTimezone: true }) + .notNull() + .defaultNow() + .$onUpdate(() => new Date()), +}); + +export const usersRelations = relations(usersTable, ({ one, many }) => ({ + company: one(companiesTable, { + fields: [usersTable.companyId], + references: [companiesTable.id], + }), + tokens: many(tokensTable), +})); diff --git a/src/index.ts b/src/index.ts index 9c1f7a1..60b32fb 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,25 @@ import { Elysia } from "elysia"; +import cors from "@elysiajs/cors"; +import authController from "./controllers/authController"; +import usersController from "./controllers/usersController"; +import sessionsController from "./controllers/sessionsController"; +import serversController from "./controllers/serversController"; +import appsController from "./controllers/appsController"; -const app = new Elysia().get("/", () => "Hello Elysia").listen(3000); +const app = new Elysia(); + +app.use( + cors({ + origin: "*", + }) +); +app.use(authController); +app.use(usersController); +app.use(serversController); +app.use(sessionsController); +app.use(appsController); + +app.listen(3000); console.log( `🦊 Elysia is running at ${app.server?.hostname}:${app.server?.port}` diff --git a/src/middlewares/auth.ts b/src/middlewares/auth.ts new file mode 100644 index 0000000..7772682 --- /dev/null +++ b/src/middlewares/auth.ts @@ -0,0 +1,83 @@ +import { eq } from "drizzle-orm"; +import Elysia, { error } from "elysia"; +import { jwtVerify } from "jose"; +import { createHmac } from "crypto"; +import db from "../db"; +import { usersTable } from "../db/schema"; + +export type AuthContext = { + userId: string; + companyId: string; +}; + +const authMiddleware = new Elysia() + .derive({ as: "scoped" }, async ({ headers, body }) => { + const type = headers["authorization"]?.split(" ")[0]; + + if (type === "Bearer") { + const accessToken = headers["authorization"]?.split(" ")[1]; + + if (!accessToken) { + return error(401); + } + + const secret = new TextEncoder().encode(process.env.JWT_SECRET); + + try { + const { + payload: { userId }, + } = await jwtVerify<{ userId: string }>(accessToken, secret); + + const user = await db.query.usersTable.findFirst({ + where: eq(usersTable.id, userId), + }); + + if (!user) { + return error(401); + } + + return { + auth: { + userId: user.id, + companyId: user.companyId, + }, + }; + } catch (err) { + return error(401); + } + } else if (type === "Hmac") { + const signature = headers["authorization"]?.split(" ")[1]; + + if (!signature) { + return error(401); + } + + const verified = createHmac("sha256", process.env.HMAC_SECRET) + .update(JSON.stringify(body)) + .digest("base64"); + + if (verified !== signature) { + return error(401); + } + + return { + auth: { + userId: "hmac-user", + companyId: "hmac-company", + }, + }; + } else { + return error(401); + } + }) + .onError({ as: "scoped" }, ({ error, set }) => { + if (set.status === 401) { + return { + error: "Unauthorized", + }; + } + + return error; + }); + +export default authMiddleware; diff --git a/src/services/apps/create.ts b/src/services/apps/create.ts new file mode 100644 index 0000000..f074397 --- /dev/null +++ b/src/services/apps/create.ts @@ -0,0 +1,45 @@ +import { error } from "elysia"; +import db from "../../db"; +import { appsTable, serversTable } from "../../db/schema"; +import { eq, inArray } from "drizzle-orm"; +import type { AuthContext } from "./../../middlewares/auth"; + +export default async function createApp( + auth: AuthContext, + body: { + apps: string[]; + serverId: string; + companyId: string; + } +) { + if (auth.userId !== "hmac-user") { + return error(403, "Forbidden"); + } + + try { + const existingApp = await db.query.appsTable.findMany({ + where: inArray(appsTable.name, body.apps), + }); + + if (existingApp.length) { + return error(400, "App with this name already exists"); + } + + const apps = await db + .insert(appsTable) + .values( + body.apps.map((app) => ({ + name: app, + fileName: app, + companyId: body.companyId, + serverId: body.serverId, + })) + ) + .returning(); + + return apps; + } catch (err) { + console.log((err as Error).message); + return error(500, "Internal Server Error"); + } +} diff --git a/src/services/apps/getByCompanyId.ts b/src/services/apps/getByCompanyId.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/services/auth/login.ts b/src/services/auth/login.ts new file mode 100644 index 0000000..06ab67c --- /dev/null +++ b/src/services/auth/login.ts @@ -0,0 +1,36 @@ +import { eq } from "drizzle-orm"; +import db from "../../db"; +import { tokensTable, usersTable } from "../../db/schema"; +import { error } from "elysia"; +import { generateToken } from "../../utils/generateToken"; + +export default async function login({ + email, + password, +}: { + email: string; + password: string; +}) { + try { + const user = await db.query.usersTable.findFirst({ + where: eq(usersTable.email, email), + }); + + if (!user || !Bun.password.verifySync(password, user.password)) + return error(401, { error: "Wrong credentials" }); + + const token = await generateToken(user.id); + + await db.insert(tokensTable).values({ + token, + userId: user.id, + }); + + return { + token, + }; + } catch (err) { + console.log((err as Error).message); + return error(500, "Internal Server Error"); + } +} diff --git a/src/services/auth/logout.ts b/src/services/auth/logout.ts new file mode 100644 index 0000000..653d800 --- /dev/null +++ b/src/services/auth/logout.ts @@ -0,0 +1,13 @@ +import { error } from "elysia"; +import { eq } from "drizzle-orm"; +import db from "../../db"; +import { tokensTable } from "../../db/schema"; + +export default async function logout(token: string) { + try { + await db.delete(tokensTable).where(eq(tokensTable.token, token)); + } catch (err) { + console.log((err as Error).message); + return error(500, "Internal Server Error"); + } +} diff --git a/src/services/auth/register.ts b/src/services/auth/register.ts new file mode 100644 index 0000000..6c69330 --- /dev/null +++ b/src/services/auth/register.ts @@ -0,0 +1,26 @@ +// import { error } from "elysia"; +// import { eq } from "drizzle-orm"; +// import db from "../../db"; +// import { usersTable } from "../../db/schema"; + +// export default async function register(payload: { +// username: string; +// password: string; +// companyId: string; +// }) { +// const { companyId, username } = payload; + +// try { +// const candidate = await db.query.usersTable.findFirst({ +// where: eq(usersTable.username, username), +// }); + +// if (candidate) return error(400, "user already exists"); + +// const password = Bun.hash(payload.password); + +// const user = await db +// .insert(usersTable) +// .values({ companyId, username, password }); +// } catch (error) {} +// } diff --git a/src/services/servers/create.ts b/src/services/servers/create.ts new file mode 100644 index 0000000..0ce9f2f --- /dev/null +++ b/src/services/servers/create.ts @@ -0,0 +1,41 @@ +import { error } from "elysia"; +import db from "../../db"; +import { serversTable } from "../../db/schema"; +import { eq } from "drizzle-orm"; +import type { AuthContext } from "./../../middlewares/auth"; + +export default async function createServer( + auth: AuthContext, + body: { + hostname: string; + name: string; + location: string; + companyId: string; + } +) { + if (auth.userId !== "hmac-user") { + return error(403, "Forbidden"); + } + + try { + const existingServer = await db.query.serversTable.findFirst({ + where: eq(serversTable.hostname, body.hostname), + }); + + if (existingServer) { + return error(400, "Server with this hostname already exists"); + } + + const server = await db + .insert(serversTable) + .values({ + ...body, + }) + .returning(); + + return server; + } catch (err) { + console.log((err as Error).message); + return error(500, "Internal Server Error"); + } +} diff --git a/src/services/servers/get.ts b/src/services/servers/get.ts new file mode 100644 index 0000000..9caa563 --- /dev/null +++ b/src/services/servers/get.ts @@ -0,0 +1,55 @@ +import { error } from "elysia"; +import db from "../../db"; +import { desc, eq } from "drizzle-orm"; +import { serversTable, sessionsTable } from "../../db/schema"; +import type { AuthContext } from "../../middlewares/auth"; + +export default async function getServers( + auth: AuthContext, + query?: { + withLastSession?: boolean; + with?: string; + } +) { + try { + const servers = await db.query.serversTable.findMany({ + where: eq(serversTable.companyId, auth.companyId), + with: { + ...(query?.with + ? Object.fromEntries( + JSON.parse(query.with).map((k: string) => [ + k, + { + orderBy: desc(sessionsTable.createdAt), + }, + ]) + ) + : query?.withLastSession + ? { + sessions: { + orderBy: desc(sessionsTable.createdAt), + limit: 1, + with: { + client: { + columns: { + fullname: true, + }, + }, + app: { + columns: { + name: true, + }, + }, + }, + }, + } + : undefined), + }, + }); + + return servers; + } catch (err) { + console.log((err as Error).message); + return error(500, "Internal Server Error"); + } +} diff --git a/src/services/sessions/create.ts b/src/services/sessions/create.ts new file mode 100644 index 0000000..f14c695 --- /dev/null +++ b/src/services/sessions/create.ts @@ -0,0 +1,53 @@ +import { and, eq, or } from "drizzle-orm"; +import db from "../../db"; +import { sessionsTable } from "../../db/schema"; +import { error } from "elysia"; + +async function createSession( + auth: { + userId: string; + companyId: string; + }, + body: { + appId: string; + serverId: string; + clientId: string; + } +) { + try { + // Check for existing session + const [existingSession] = await db + .select() + .from(sessionsTable) + .where( + and( + eq(sessionsTable.serverId, body.serverId), + or( + eq(sessionsTable.status, "starting"), + eq(sessionsTable.status, "started") + ) + ) + ); + + if (existingSession) { + return error(409, "Session already exists"); + } + + // Create new session + const [newSession] = await db + .insert(sessionsTable) + .values({ + ...body, + ownerId: auth.userId, + companyId: auth.companyId, + status: "starting", + }) + .returning(); + + return newSession; + } catch (err) { + return error(500, "Internal Server Error"); + } +} + +export default createSession; diff --git a/src/services/sessions/get.ts b/src/services/sessions/get.ts new file mode 100644 index 0000000..3e69ef0 --- /dev/null +++ b/src/services/sessions/get.ts @@ -0,0 +1,34 @@ +import db from "../../db"; +import { error } from "elysia"; +import { and, desc, eq } from "drizzle-orm"; +import { sessionsTable } from "../../db/schema"; +import type { AuthContext } from "../../middlewares/auth"; + +async function getSessions( + auth: AuthContext, + query?: { + limit?: number; + } +) { + try { + const sessions = await db.query.sessionsTable.findMany({ + where: and( + eq(sessionsTable.ownerId, auth.userId), + eq(sessionsTable.companyId, auth.companyId) + ), + with: { + client: true, + app: true, + server: true, + }, + limit: query?.limit, + orderBy: desc(sessionsTable.createdAt), + }); + + return sessions; + } catch (err) { + return error(500, "Internal Server Error"); + } +} + +export default getSessions; diff --git a/src/services/sessions/update.ts b/src/services/sessions/update.ts new file mode 100644 index 0000000..497da99 --- /dev/null +++ b/src/services/sessions/update.ts @@ -0,0 +1,23 @@ +import { eq } from "drizzle-orm"; +import db from "../../db"; +import { sessionsTable } from "../../db/schema"; +import { error } from "elysia"; + +async function updateSession( + sessionId: string, + status: "starting" | "started" | "restarting" | "ending" | "ended" +) { + try { + const session = await db + .update(sessionsTable) + .set({ status }) + .where(eq(sessionsTable.id, sessionId)) + .returning(); + + return session; + } catch (err) { + return error(500, "Internal Server Error"); + } +} + +export default updateSession; diff --git a/src/services/user/me.ts b/src/services/user/me.ts new file mode 100644 index 0000000..f15d9f3 --- /dev/null +++ b/src/services/user/me.ts @@ -0,0 +1,21 @@ +import { eq } from "drizzle-orm"; +import db from "../../db"; +import { usersTable } from "../../db/schema"; +import { error } from "elysia"; + +export default async function me(userId: string) { + try { + const user = await db.query.usersTable.findFirst({ + where: eq(usersTable.id, userId), + columns: { + id: true, + email: true, + fullname: true, + }, + }); + + return user; + } catch (err) { + return error(500, "Internal Server Error"); + } +} diff --git a/src/utils/generateToken.ts b/src/utils/generateToken.ts new file mode 100644 index 0000000..72bcdef --- /dev/null +++ b/src/utils/generateToken.ts @@ -0,0 +1,10 @@ +import { SignJWT } from "jose"; + +export async function generateToken(userId: string) { + return await new SignJWT({ + userId, + }) + .setProtectedHeader({ alg: "HS256" }) + .setExpirationTime(process.env.JWT_EXPIRATION) + .sign(new TextEncoder().encode(process.env.JWT_SECRET)); +} diff --git a/tsconfig.json b/tsconfig.json index 1ca2350..359c1d8 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,103 +1,136 @@ +// { +// "compilerOptions": { +// /* Visit https://aka.ms/tsconfig to read more about this file */ + +// /* Projects */ +// // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ +// // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ +// // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ +// // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ +// // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ +// // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + +// /* Language and Environment */ +// "target": "ESNext" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, +// // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ +// // "jsx": "preserve", /* Specify what JSX code is generated. */ +// // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ +// // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ +// // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ +// // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ +// // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ +// // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ +// // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ +// // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ +// // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + +// /* Modules */ +// "module": "ESNext" /* Specify what module code is generated. */, +// // "rootDir": "./", /* Specify the root folder within your source files. */ +// "moduleResolution": "bundler" /* Specify how TypeScript looks up a file from a given module specifier. */, +// // "baseUrl": "" /* Specify the base directory to resolve non-relative module names. */, +// // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ +// // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ +// // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ +// "types": [ +// "bun-types" +// ] /* Specify type package names to be included without being referenced in a source file. */, +// // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ +// // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ +// // "resolveJsonModule": true, /* Enable importing .json files. */ +// // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + +// /* JavaScript Support */ +// // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ +// // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ +// // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + +// /* Emit */ +// // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ +// // "declarationMap": true, /* Create sourcemaps for d.ts files. */ +// // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ +// // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ +// // "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. */ +// // "outDir": "./", /* Specify an output folder for all emitted files. */ +// // "removeComments": true, /* Disable emitting comments. */ +// // "noEmit": true, /* Disable emitting files from a compilation. */ +// // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ +// // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ +// // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ +// // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ +// // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ +// // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ +// // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ +// // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ +// // "newLine": "crlf", /* Set the newline character for emitting files. */ +// // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ +// // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ +// // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ +// // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ +// // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ +// // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + +// /* Interop Constraints */ +// // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ +// // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ +// "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, +// // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ +// "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, + +// /* Type Checking */ +// "strict": true /* Enable all strict type-checking options. */, +// // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ +// // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ +// // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ +// // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ +// // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ +// // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ +// // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ +// // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ +// // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ +// // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ +// // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ +// // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ +// // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ +// // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ +// // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ +// // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ +// // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ +// // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + +// /* Completeness */ +// // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ +// "skipLibCheck": true /* Skip type checking all .d.ts files. */ +// }, +// "include": ["./src/**/*.ts", "env.d.ts", "drizzle.config.ts"] +// } + { "compilerOptions": { - /* Visit https://aka.ms/tsconfig to read more about this file */ + // Enable latest features + "lib": ["ESNext"], + "target": "ESNext", + "module": "ESNext", + "moduleDetection": "force", + "jsx": "react-jsx", + "allowJs": true, - /* Projects */ - // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ - // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ - // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ - // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ - // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ - // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + // Bundler mode + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "noEmit": true, - /* Language and Environment */ - "target": "ES2021", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ - // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ - // "jsx": "preserve", /* Specify what JSX code is generated. */ - // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ - // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ - // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ - // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ - // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ - // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ - // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ - // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ - // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + // Best practices + "strict": true, + "skipLibCheck": true, + "noFallthroughCasesInSwitch": true, - /* Modules */ - "module": "ES2022", /* Specify what module code is generated. */ - // "rootDir": "./", /* Specify the root folder within your source files. */ - "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ - // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ - // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ - // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ - // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ - "types": ["bun-types"], /* Specify type package names to be included without being referenced in a source file. */ - // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ - // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ - // "resolveJsonModule": true, /* Enable importing .json files. */ - // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ - - /* JavaScript Support */ - // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ - // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ - // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ - - /* Emit */ - // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ - // "declarationMap": true, /* Create sourcemaps for d.ts files. */ - // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ - // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ - // "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. */ - // "outDir": "./", /* Specify an output folder for all emitted files. */ - // "removeComments": true, /* Disable emitting comments. */ - // "noEmit": true, /* Disable emitting files from a compilation. */ - // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ - // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ - // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ - // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ - // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ - // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ - // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ - // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ - // "newLine": "crlf", /* Set the newline character for emitting files. */ - // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ - // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ - // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ - // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ - // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ - // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ - - /* Interop Constraints */ - // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ - // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ - "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ - // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ - "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ - - /* Type Checking */ - "strict": true, /* Enable all strict type-checking options. */ - // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ - // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ - // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ - // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ - // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ - // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ - // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ - // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ - // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ - // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ - // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ - // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ - // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ - // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ - // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ - // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ - // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ - // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ - - /* Completeness */ - // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ - "skipLibCheck": true /* Skip type checking all .d.ts files. */ - } + // Some stricter flags + "noUnusedLocals": true, + "noUnusedParameters": true, + "noPropertyAccessFromIndexSignature": true + }, + "include": ["./src/**/*.ts", "env.d.ts", "drizzle.config.ts"], + "exclude": ["node_modules", "dist"] }