diff --git a/.env.example b/.env.example index c084912..ef16b33 100644 --- a/.env.example +++ b/.env.example @@ -9,10 +9,11 @@ # When adding additional environment variables, the schema in "/src/env.js" # should be updated accordingly. -# Prisma -# https://www.prisma.io/docs/reference/database-reference/connection-urls#env -POSTGRES_PRISMA_URL="postgresql://postgres:password@localhost:5432/mcc-tools" -POSTGRES_URL_NON_POOLING="postgresql://postgres:password@localhost:5432/mcc-tools" +# Drizzle +DATABASE_URL="file:./db.sqlite" +# If using `turso dev`, only required if we start using turso extensions +#DATABASE_URL="http://127.0.0.1:8080" +TURSO_AUTH_TOKEN="" # Next Auth # You can generate a new secret on the command line with: diff --git a/.github/workflows/print_info.yaml b/.github/workflows/print_info.yaml deleted file mode 100644 index ed00d5d..0000000 --- a/.github/workflows/print_info.yaml +++ /dev/null @@ -1,37 +0,0 @@ -name: Print out some useful information about the PR - -on: - pull_request: - types: - - opened - - reopened - - synchronize - - closed - -jobs: - setup: - outputs: - branch: ${{ steps.branch_name.outputs.current_branch }} - runs-on: ubuntu-latest - permissions: - contents: read - steps: - - name: Get branch name - id: branch_name - uses: tj-actions/branch-names@v8 - - when_open: - name: When open - needs: setup - if: | - github.event_name == 'pull_request' && ( - github.event.action == 'synchronize' - || github.event.action == 'opened' - || github.event.action == 'reopened') - runs-on: ubuntu-latest - steps: - - name: Print branch name - env: - CURRENT_BRANCH: ${{needs.setup.outputs.branch}} - run: | - echo "Branch name: $CURRENT_BRANCH" diff --git a/.github/workflows/turso_branching.yaml b/.github/workflows/turso_branching.yaml new file mode 100644 index 0000000..018cc2f --- /dev/null +++ b/.github/workflows/turso_branching.yaml @@ -0,0 +1,120 @@ +name: Automatically create and cleanup Turso DB branches for each PR + +on: + pull_request_target: + types: + - opened + - reopened + - synchronize + - closed + +jobs: + setup: + outputs: + branch_id: ${{ steps.branch_db_id.outputs.result }} + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: Get user permissions + id: permissions + uses: actions-cool/check-user-permission@v2 + with: + require: write + username: ${{ github.triggering_actor }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Check user permissions + if: steps.permissions.outputs.require-result == 'false' + run: | + echo "${{ github.triggering_actor }} does not have permissions on this repo." + echo "A user with write permissions should very carefully check the diff of this PR and then re-run the workflow if it is safe" + exit 1 + - name: Get branch name + id: branch_name + uses: tj-actions/branch-names@v8 + - name: Checkout + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} # This is dangerous without the first access check + - name: Generate branched DB ID + id: branch_db_id + uses: actions/github-script@v7 + with: + result-encoding: string + script: | + const { previewDbId } = await import("${{github.workspace}}/src/server/db/utils.js"); + const dbId = previewDbId(${{ github.event.number }}, "${{steps.branch_name.outputs.current_branch}}"); + console.log(`Branched DB ID: ${dbId}`); + return dbId; + + ensure_db_branch: + name: Ensure the DB branch exists and is up to date + needs: setup + if: | + github.event_name == 'pull_request' && ( + github.event.action == 'synchronize' + || github.event.action == 'opened' + || github.event.action == 'reopened') + runs-on: ubuntu-latest + steps: + - name: Create DB branch + id: create_db_branch + run: | + RESPONSE=$(curl -L -X POST \ + -H "Authorization: Bearer ${{ secrets.TURSO_API_TOKEN }}" \ + -H "Content-Type: application/json" \ + -d '{"name": "${{ needs.setup.outputs.branch_id }}", "group": "${{ secrets.TURSO_GROUP_NAME }}", "seed": {"type": "database", "name": "${{ secrets.TURSO_DATABASE_NAME }}"} }' \ + "https://api.turso.tech/v1/organizations/${{ secrets.TURSO_ORGANIZATION_NAME }}/databases") + + if [ $? -ne 0 ]; then + echo "Unable to create database, attempting to fetch the existing database instead" + RESPONSE=$(curl -L 'https://api.turso.tech/v1/organizations/${{ secrets.TURSO_ORGANIZATION_NAME }}/databases/${{ needs.setup.outputs.branch_id }}' \ + -H 'Authorization: Bearer ${{ secrets.TURSO_API_TOKEN }}') + + if [ $? -ne 0 ]; then + echo "Could not create or fetch database" + exit 1 + fi + fi + + HOSTNAME=$(echo $RESPONSE | jq -r '.database.Hostname') + if [ -z "$HOSTNAME" ]; then + echo "Hostname not found in response" + exit 1 + fi + + echo "hostname=$HOSTNAME" >> $GITHUB_OUTPUT + - name: Checkout + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} # This is dangerous without the first access check + - name: Run migrations + env: + DATABASE_URL: "libsql://${{ steps.create_db_branch.hostname }}" + TURSO_AUTH_TOKEN: ${{ secrets.TURSO_API_TOKEN }} + run: npm install && npm run db:generate && npm run db:migrate + delete_db_branch: + name: Delete DB branch and migrate prod + needs: setup + if: | + github.event_name == 'pull_request' && + github.event.action == 'closed' + runs-on: ubuntu-latest + steps: + - name: Delete DB branch + run: | + curl -L -X DELETE 'https://api.turso.tech/v1/organizations/${{ secrets.TURSO_ORGANIZATION_NAME }}/databases/${{ needs.setup.outputs.branch_id }}' \ + -H 'Authorization: Bearer ${{ secrets.TURSO_API_TOKEN }}' + # Migrate prod DB, hopefully faster than the vercel build, or at least before anyone tries to open the website + - name: Checkout + if: github.event.pull_request.merged == true + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} # This is dangerous without the first access check + - name: Apply migrations to production + if: github.event.pull_request.merged == true + env: + DATABASE_URL: "libsql://${{ secrets.TURSO_DATABASE_NAME }}" + TURSO_AUTH_TOKEN: ${{ secrets.TURSO_API_TOKEN }} + run: npm install && npm run db:generate && npm run db:migrate diff --git a/.gitignore b/.gitignore index 2971a0b..9d172b3 100644 --- a/.gitignore +++ b/.gitignore @@ -40,3 +40,7 @@ yarn-error.log* # typescript *.tsbuildinfo + +# local db +local.db* +db.sqlite \ No newline at end of file diff --git a/drizzle.config.ts b/drizzle.config.ts new file mode 100644 index 0000000..15e4e7b --- /dev/null +++ b/drizzle.config.ts @@ -0,0 +1,15 @@ +import { type Config } from "drizzle-kit"; +import "dotenv/config"; + +import { env } from "~/env"; + +export default { + schema: "./src/server/db/schema.ts", + out: "./src/server/db/migrations", + dialect: "turso", + dbCredentials: { + url: env.DATABASE_URL, + authToken: env.TURSO_AUTH_TOKEN, + }, + tablesFilter: ["mcc-gadgets_*"], +} satisfies Config; diff --git a/package-lock.json b/package-lock.json index 25aa156..f8a3e1f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,10 +7,10 @@ "": { "name": "mcc-tools", "version": "0.1.0", - "hasInstallScript": true, "dependencies": { - "@auth/prisma-adapter": "^1.6.0", + "@auth/drizzle-adapter": "^1.8.0", "@catppuccin/palette": "^1.7.1", + "@libsql/client": "^0.14.0", "@prisma/client": "^5.22.0", "@radix-ui/react-dialog": "^1.1.6", "@radix-ui/react-dropdown-menu": "^2.1.6", @@ -28,10 +28,12 @@ "@trpc/server": "next", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", + "dotenv": "^16.5.0", + "drizzle-orm": "^0.40.0", "html-react-parser": "^5.2.2", "lucide-react": "^0.454.0", "next": "15.2.0", - "next-auth": "^4.24.11", + "next-auth": "^5.0.0-beta.25", "next-themes": "^0.3.0", "react": "19.0.0", "react-dom": "19.0.0", @@ -55,12 +57,12 @@ "@types/sanitize-html": "^2.13.0", "@typescript-eslint/eslint-plugin": "^7.18.0", "@typescript-eslint/parser": "^7.18.0", + "drizzle-kit": "^0.30.5", "eslint": "^8.57.1", "eslint-config-next": "15.2.0", "postcss": "^8.5.3", "prettier": "^3.5.2", "prettier-plugin-tailwindcss": "^0.5.14", - "prisma": "^5.22.0", "tailwindcss": "^3.4.17", "typescript": "^5.8.2" } @@ -92,18 +94,16 @@ } }, "node_modules/@auth/core": { - "version": "0.34.2", - "resolved": "https://registry.npmjs.org/@auth/core/-/core-0.34.2.tgz", - "integrity": "sha512-KywHKRgLiF3l7PLyL73fjLSIBe1YNcA6sMeew4yMP6cfCWGXZrkkXd32AjRi1hlJ9nvovUBGZHvbn+LijO6ZeQ==", + "version": "0.37.2", + "resolved": "https://registry.npmjs.org/@auth/core/-/core-0.37.2.tgz", + "integrity": "sha512-kUvzyvkcd6h1vpeMAojK2y7+PAV5H+0Cc9+ZlKYDFhDY31AlvsB+GW5vNO4qE3Y07KeQgvNO9U0QUx/fN62kBw==", "license": "ISC", - "optional": true, - "peer": true, "dependencies": { - "@panva/hkdf": "^1.1.1", + "@panva/hkdf": "^1.2.1", "@types/cookie": "0.6.0", - "cookie": "0.6.0", - "jose": "^5.1.3", - "oauth4webapi": "^2.10.4", + "cookie": "0.7.1", + "jose": "^5.9.3", + "oauth4webapi": "^3.0.0", "preact": "10.11.3", "preact-render-to-string": "5.2.3" }, @@ -124,31 +124,26 @@ } } }, - "node_modules/@auth/prisma-adapter": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@auth/prisma-adapter/-/prisma-adapter-1.6.0.tgz", - "integrity": "sha512-PQU8/Oi5gfjzb0MkhMGVX0Dg877phPzsQdK54+C7ubukCeZPjyvuSAx1vVtWEYVWp2oQvjgG/C6QiDoeC7S10A==", + "node_modules/@auth/drizzle-adapter": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@auth/drizzle-adapter/-/drizzle-adapter-1.8.0.tgz", + "integrity": "sha512-cxApE0h5WcyDsgGix9hzmWmCz0qxvmMJexAOQmI6R/YXYxrZ/mKBKu0BlfgQBR6z2XvNWl4wbEGchwSenSCksQ==", "license": "ISC", "dependencies": { - "@auth/core": "0.29.0" - }, - "peerDependencies": { - "@prisma/client": ">=2.26.0 || >=3 || >=4 || >=5" + "@auth/core": "0.38.0" } }, - "node_modules/@auth/prisma-adapter/node_modules/@auth/core": { - "version": "0.29.0", - "resolved": "https://registry.npmjs.org/@auth/core/-/core-0.29.0.tgz", - "integrity": "sha512-MdfEjU6WRjUnPG1+XeBWrTIlAsLZU6V0imCIqVDDDPxLI6UZWldXVqAA2EsDazGofV78jqiCLHaN85mJITDqdg==", + "node_modules/@auth/drizzle-adapter/node_modules/@auth/core": { + "version": "0.38.0", + "resolved": "https://registry.npmjs.org/@auth/core/-/core-0.38.0.tgz", + "integrity": "sha512-ClHl44x4cY3wfJmHLpW+XrYqED0fZIzbHmwbExltzroCjR5ts3DLTWzADRba8mJFYZ8JIEJDa+lXnGl0E9Bl7Q==", "license": "ISC", "dependencies": { - "@panva/hkdf": "^1.1.1", - "@types/cookie": "0.6.0", - "cookie": "0.6.0", - "jose": "^5.1.3", - "oauth4webapi": "^2.4.0", - "preact": "10.11.3", - "preact-render-to-string": "5.2.3" + "@panva/hkdf": "^1.2.1", + "jose": "^6.0.6", + "oauth4webapi": "^3.3.0", + "preact": "10.24.3", + "preact-render-to-string": "6.5.11" }, "peerDependencies": { "@simplewebauthn/browser": "^9.0.1", @@ -167,6 +162,34 @@ } } }, + "node_modules/@auth/drizzle-adapter/node_modules/jose": { + "version": "6.0.9", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.0.9.tgz", + "integrity": "sha512-6HEy/G3IBiGwOeT0phvu19yt/zagFKSpQPpQ6YUIiCxBUPfThVkOv9wlwHGkatUqbHvkWHYPtJJil4U5jHwllw==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/@auth/drizzle-adapter/node_modules/preact": { + "version": "10.24.3", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.24.3.tgz", + "integrity": "sha512-Z2dPnBnMUfyQfSQ+GBdsGa16hz35YmLmtTLhM169uW944hYL6xzTYkJjC07j+Wosz733pMWx0fgON3JNw1jJQA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + } + }, + "node_modules/@auth/drizzle-adapter/node_modules/preact-render-to-string": { + "version": "6.5.11", + "resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-6.5.11.tgz", + "integrity": "sha512-ubnauqoGczeGISiOh6RjX0/cdaF8v/oDXIjO85XALCQjwQP+SB4RDXXtvZ6yTYSjG+PC1QRP2AhPgCEsM2EvUw==", + "license": "MIT", + "peerDependencies": { + "preact": ">=10" + } + }, "node_modules/@babel/code-frame": { "version": "7.26.2", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", @@ -1785,6 +1808,7 @@ "version": "7.26.9", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.9.tgz", "integrity": "sha512-aA63XwOkcl4xxQa3HjPMqOP6LiK0ZDv3mUPYEFXkpHbaFjtGggE1A61FjFzJnB+p7/oy2gA8E+rcBNl/zC1tMg==", + "dev": true, "license": "MIT", "dependencies": { "regenerator-runtime": "^0.14.0" @@ -1814,67 +1838,901 @@ "integrity": "sha512-ZYW7L+pL8ahU5fXmNbPF+iZFHCv5scFak7MZ9bwaRPLUhHh7QQEMjZUg0HevihoqCM5iSYHN61EyCoZvqC+bxg==", "dev": true, "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.26.2", - "@babel/generator": "^7.26.9", - "@babel/parser": "^7.26.9", - "@babel/template": "^7.26.9", - "@babel/types": "^7.26.9", - "debug": "^4.3.1", - "globals": "^11.1.0" - }, + "dependencies": { + "@babel/code-frame": "^7.26.2", + "@babel/generator": "^7.26.9", + "@babel/parser": "^7.26.9", + "@babel/template": "^7.26.9", + "@babel/types": "^7.26.9", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.26.9", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.9.tgz", + "integrity": "sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@catppuccin/palette": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@catppuccin/palette/-/palette-1.7.1.tgz", + "integrity": "sha512-aRc1tbzrevOTV7nFTT9SRdF26w/MIwT4Jwt4fDMc9itRZUDXCuEDBLyz4TQMlqO9ZP8mf5Hu4Jr6D03NLFc6Gw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/catppuccin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/catppuccin" + } + ], + "license": "MIT" + }, + "node_modules/@catppuccin/tailwindcss": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@catppuccin/tailwindcss/-/tailwindcss-0.1.6.tgz", + "integrity": "sha512-V+Y0AwZ5SSyvOVAcDl7Ng30xy+m82OKnEJ+9+kcZZ7lRyXuZrAb2GScdq9XR3v+ggt8qiZ/G4TvaC9cJ88AAXA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "tailwindcss": ">=3.0.0" + } + }, + "node_modules/@drizzle-team/brocli": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@drizzle-team/brocli/-/brocli-0.10.2.tgz", + "integrity": "sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@emnapi/runtime": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.3.1.tgz", + "integrity": "sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@esbuild-kit/core-utils": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@esbuild-kit/core-utils/-/core-utils-3.3.2.tgz", + "integrity": "sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==", + "deprecated": "Merged into tsx: https://tsx.is", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.18.20", + "source-map-support": "^0.5.21" + } + }, + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/android-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", + "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/android-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", + "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/android-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", + "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/darwin-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", + "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/darwin-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", + "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/freebsd-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", + "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/freebsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", + "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", + "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", + "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", + "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-loong64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", + "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-mips64el": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", + "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-ppc64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", + "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-riscv64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", + "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-s390x": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", + "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", + "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/netbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", + "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/openbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", + "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/sunos-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", + "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/win32-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", + "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/win32-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", + "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/win32-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", + "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild-kit/core-utils/node_modules/esbuild": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", + "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "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" + } + }, + "node_modules/@esbuild-kit/esm-loader": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/@esbuild-kit/esm-loader/-/esm-loader-2.6.5.tgz", + "integrity": "sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA==", + "deprecated": "Merged into tsx: https://tsx.is", + "dev": true, + "license": "MIT", + "dependencies": { + "@esbuild-kit/core-utils": "^3.3.2", + "get-tsconfig": "^4.7.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz", + "integrity": "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.12.tgz", + "integrity": "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz", + "integrity": "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.12.tgz", + "integrity": "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz", + "integrity": "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz", + "integrity": "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz", + "integrity": "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz", + "integrity": "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz", + "integrity": "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz", + "integrity": "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz", + "integrity": "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz", + "integrity": "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz", + "integrity": "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz", + "integrity": "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz", + "integrity": "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz", + "integrity": "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz", + "integrity": "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz", + "integrity": "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz", + "integrity": "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz", + "integrity": "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], "engines": { - "node": ">=6.9.0" + "node": ">=12" } }, - "node_modules/@babel/types": { - "version": "7.26.9", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.9.tgz", - "integrity": "sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw==", + "node_modules/@esbuild/win32-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz", + "integrity": "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9" - }, + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=6.9.0" + "node": ">=12" } }, - "node_modules/@catppuccin/palette": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@catppuccin/palette/-/palette-1.7.1.tgz", - "integrity": "sha512-aRc1tbzrevOTV7nFTT9SRdF26w/MIwT4Jwt4fDMc9itRZUDXCuEDBLyz4TQMlqO9ZP8mf5Hu4Jr6D03NLFc6Gw==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/catppuccin" - }, - { - "type": "github", - "url": "https://github.com/sponsors/catppuccin" - } + "node_modules/@esbuild/win32-ia32": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz", + "integrity": "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==", + "cpu": [ + "ia32" ], - "license": "MIT" - }, - "node_modules/@catppuccin/tailwindcss": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/@catppuccin/tailwindcss/-/tailwindcss-0.1.6.tgz", - "integrity": "sha512-V+Y0AwZ5SSyvOVAcDl7Ng30xy+m82OKnEJ+9+kcZZ7lRyXuZrAb2GScdq9XR3v+ggt8qiZ/G4TvaC9cJ88AAXA==", "dev": true, "license": "MIT", - "peerDependencies": { - "tailwindcss": ">=3.0.0" + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" } }, - "node_modules/@emnapi/runtime": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.3.1.tgz", - "integrity": "sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==", + "node_modules/@esbuild/win32-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz", + "integrity": "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==", + "cpu": [ + "x64" + ], + "dev": true, "license": "MIT", "optional": true, - "dependencies": { - "tslib": "^2.4.0" + "os": [ + "win32" + ], + "engines": { + "node": ">=12" } }, "node_modules/@eslint-community/eslint-utils": { @@ -2539,6 +3397,156 @@ "integrity": "sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==", "license": "Apache-2.0" }, + "node_modules/@libsql/client": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@libsql/client/-/client-0.14.0.tgz", + "integrity": "sha512-/9HEKfn6fwXB5aTEEoMeFh4CtG0ZzbncBb1e++OCdVpgKZ/xyMsIVYXm0w7Pv4RUel803vE6LwniB3PqD72R0Q==", + "license": "MIT", + "dependencies": { + "@libsql/core": "^0.14.0", + "@libsql/hrana-client": "^0.7.0", + "js-base64": "^3.7.5", + "libsql": "^0.4.4", + "promise-limit": "^2.7.0" + } + }, + "node_modules/@libsql/core": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@libsql/core/-/core-0.14.0.tgz", + "integrity": "sha512-nhbuXf7GP3PSZgdCY2Ecj8vz187ptHlZQ0VRc751oB2C1W8jQUXKKklvt7t1LJiUTQBVJuadF628eUk+3cRi4Q==", + "license": "MIT", + "dependencies": { + "js-base64": "^3.7.5" + } + }, + "node_modules/@libsql/darwin-arm64": { + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/@libsql/darwin-arm64/-/darwin-arm64-0.4.7.tgz", + "integrity": "sha512-yOL742IfWUlUevnI5PdnIT4fryY3LYTdLm56bnY0wXBw7dhFcnjuA7jrH3oSVz2mjZTHujxoITgAE7V6Z+eAbg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@libsql/darwin-x64": { + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/@libsql/darwin-x64/-/darwin-x64-0.4.7.tgz", + "integrity": "sha512-ezc7V75+eoyyH07BO9tIyJdqXXcRfZMbKcLCeF8+qWK5nP8wWuMcfOVywecsXGRbT99zc5eNra4NEx6z5PkSsA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@libsql/hrana-client": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@libsql/hrana-client/-/hrana-client-0.7.0.tgz", + "integrity": "sha512-OF8fFQSkbL7vJY9rfuegK1R7sPgQ6kFMkDamiEccNUvieQ+3urzfDFI616oPl8V7T9zRmnTkSjMOImYCAVRVuw==", + "license": "MIT", + "dependencies": { + "@libsql/isomorphic-fetch": "^0.3.1", + "@libsql/isomorphic-ws": "^0.1.5", + "js-base64": "^3.7.5", + "node-fetch": "^3.3.2" + } + }, + "node_modules/@libsql/isomorphic-fetch": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@libsql/isomorphic-fetch/-/isomorphic-fetch-0.3.1.tgz", + "integrity": "sha512-6kK3SUK5Uu56zPq/Las620n5aS9xJq+jMBcNSOmjhNf/MUvdyji4vrMTqD7ptY7/4/CAVEAYDeotUz60LNQHtw==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@libsql/isomorphic-ws": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@libsql/isomorphic-ws/-/isomorphic-ws-0.1.5.tgz", + "integrity": "sha512-DtLWIH29onUYR00i0GlQ3UdcTRC6EP4u9w/h9LxpUZJWRMARk6dQwZ6Jkd+QdwVpuAOrdxt18v0K2uIYR3fwFg==", + "license": "MIT", + "dependencies": { + "@types/ws": "^8.5.4", + "ws": "^8.13.0" + } + }, + "node_modules/@libsql/linux-arm64-gnu": { + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/@libsql/linux-arm64-gnu/-/linux-arm64-gnu-0.4.7.tgz", + "integrity": "sha512-WlX2VYB5diM4kFfNaYcyhw5y+UJAI3xcMkEUJZPtRDEIu85SsSFrQ+gvoKfcVh76B//ztSeEX2wl9yrjF7BBCA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@libsql/linux-arm64-musl": { + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/@libsql/linux-arm64-musl/-/linux-arm64-musl-0.4.7.tgz", + "integrity": "sha512-6kK9xAArVRlTCpWeqnNMCoXW1pe7WITI378n4NpvU5EJ0Ok3aNTIC2nRPRjhro90QcnmLL1jPcrVwO4WD1U0xw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@libsql/linux-x64-gnu": { + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/@libsql/linux-x64-gnu/-/linux-x64-gnu-0.4.7.tgz", + "integrity": "sha512-CMnNRCmlWQqqzlTw6NeaZXzLWI8bydaXDke63JTUCvu8R+fj/ENsLrVBtPDlxQ0wGsYdXGlrUCH8Qi9gJep0yQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@libsql/linux-x64-musl": { + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/@libsql/linux-x64-musl/-/linux-x64-musl-0.4.7.tgz", + "integrity": "sha512-nI6tpS1t6WzGAt1Kx1n1HsvtBbZ+jHn0m7ogNNT6pQHZQj7AFFTIMeDQw/i/Nt5H38np1GVRNsFe99eSIMs9XA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@libsql/win32-x64-msvc": { + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/@libsql/win32-x64-msvc/-/win32-x64-msvc-0.4.7.tgz", + "integrity": "sha512-7pJzOWzPm6oJUxml+PCDRzYQ4A1hTMHAciTAHfFK4fkbDZX33nWPVG7Y3vqdKtslcwAzwmrNDc6sXy2nwWnbiw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@neon-rs/load": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/@neon-rs/load/-/load-0.0.4.tgz", + "integrity": "sha512-kTPhdZyTQxB+2wpiRcFWrDcejc4JI6tkPuS7UZCG4l6Zvc5kU/gGQ/ozvHTh1XR5tS+UlfAfGuPajjzQjCiHCw==", + "license": "MIT" + }, "node_modules/@next/env": { "version": "15.2.0", "resolved": "https://registry.npmjs.org/@next/env/-/env-15.2.0.tgz", @@ -2737,6 +3745,13 @@ "url": "https://github.com/sponsors/panva" } }, + "node_modules/@petamoriken/float16": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@petamoriken/float16/-/float16-3.9.2.tgz", + "integrity": "sha512-VgffxawQde93xKxT3qap3OH+meZf7VaSB5Sqd4Rqc+FP5alWbpOyan/7tRbOAvynjpG3GpdtAuGU/NdhQpmrog==", + "devOptional": true, + "license": "MIT" + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -2769,16 +3784,18 @@ "version": "5.22.0", "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.22.0.tgz", "integrity": "sha512-AUt44v3YJeggO2ZU5BkXI7M4hu9BF2zzH2iF2V5pyXT/lRTyWiElZ7It+bRH1EshoMRxHgpYg4VB6rCM+mG5jQ==", - "devOptional": true, - "license": "Apache-2.0" + "license": "Apache-2.0", + "optional": true, + "peer": true }, "node_modules/@prisma/engines": { "version": "5.22.0", "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.22.0.tgz", "integrity": "sha512-UNjfslWhAt06kVL3CjkuYpHAWSO6L4kDCVPegV6itt7nD1kSJavd3vhgAEhjglLJJKEdJ7oIqDJ+yHk6qO8gPA==", - "devOptional": true, "hasInstallScript": true, "license": "Apache-2.0", + "optional": true, + "peer": true, "dependencies": { "@prisma/debug": "5.22.0", "@prisma/engines-version": "5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2", @@ -2790,15 +3807,17 @@ "version": "5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2", "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2.tgz", "integrity": "sha512-2PTmxFR2yHW/eB3uqWtcgRcgAbG1rwG9ZriSvQw+nnb7c4uCr3RAcGMb6/zfE88SKlC1Nj2ziUvc96Z379mHgQ==", - "devOptional": true, - "license": "Apache-2.0" + "license": "Apache-2.0", + "optional": true, + "peer": true }, "node_modules/@prisma/fetch-engine": { "version": "5.22.0", "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.22.0.tgz", "integrity": "sha512-bkrD/Mc2fSvkQBV5EpoFcZ87AvOgDxbG99488a5cexp5Ccny+UM6MAe/UFkUC0wLYD9+9befNOqGiIJhhq+HbA==", - "devOptional": true, "license": "Apache-2.0", + "optional": true, + "peer": true, "dependencies": { "@prisma/debug": "5.22.0", "@prisma/engines-version": "5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2", @@ -2809,8 +3828,9 @@ "version": "5.22.0", "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.22.0.tgz", "integrity": "sha512-pHhpQdr1UPFpt+zFfnPazhulaZYCUqeIcPpJViYoq9R+D/yw4fjE+CtnsnKzPYm0ddUbeXUzjGVGIRVgPDCk4Q==", - "devOptional": true, "license": "Apache-2.0", + "optional": true, + "peer": true, "dependencies": { "@prisma/debug": "5.22.0" } @@ -4129,7 +5149,6 @@ "version": "20.17.22", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.22.tgz", "integrity": "sha512-9RV2zST+0s3EhfrMZIhrz2bhuhBwxgkbHEwP2gtGWPjBzVQjifMzJ9exw7aDZhR1wbpj8zBrfp3bo8oJcGiUUw==", - "dev": true, "license": "MIT", "dependencies": { "undici-types": "~6.19.2" @@ -4171,6 +5190,15 @@ "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", "license": "MIT" }, + "node_modules/@types/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8svvI3hMyvN0kKCJMvTJP/x6Y/EoQbepff882wL+Sn5QsXb3etnamgrJq4isrBxSJj5L2AuXcI0+bgkoAXGUJw==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "7.18.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz", @@ -4842,6 +5870,13 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, "node_modules/busboy": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", @@ -5143,9 +6178,9 @@ "license": "MIT" }, "node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -5327,6 +6362,15 @@ "dev": true, "license": "BSD-2-Clause" }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, "node_modules/data-view-buffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", @@ -5385,7 +6429,7 @@ "version": "4.4.0", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -5593,6 +6637,156 @@ "tslib": "^2.0.3" } }, + "node_modules/dotenv": { + "version": "16.5.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.5.0.tgz", + "integrity": "sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/drizzle-kit": { + "version": "0.30.5", + "resolved": "https://registry.npmjs.org/drizzle-kit/-/drizzle-kit-0.30.5.tgz", + "integrity": "sha512-l6dMSE100u7sDaTbLczibrQZjA35jLsHNqIV+jmhNVO3O8jzM6kywMOmV9uOz9ZVSCMPQhAZEFjL/qDPVrqpUA==", + "dev": true, + "license": "MIT", + "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" + } + }, + "node_modules/drizzle-orm": { + "version": "0.40.0", + "resolved": "https://registry.npmjs.org/drizzle-orm/-/drizzle-orm-0.40.0.tgz", + "integrity": "sha512-7ptk/HQiMSrEZHnAsSlBESXWj52VwgMmyTEfoNmpNN2ZXpcz13LwHfXTIghsAEud7Z5UJhDOp8U07ujcqme7wg==", + "license": "Apache-2.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" + }, + "peerDependenciesMeta": { + "@aws-sdk/client-rds-data": { + "optional": true + }, + "@cloudflare/workers-types": { + "optional": true + }, + "@electric-sql/pglite": { + "optional": true + }, + "@libsql/client": { + "optional": true + }, + "@libsql/client-wasm": { + "optional": true + }, + "@neondatabase/serverless": { + "optional": true + }, + "@op-engineering/op-sqlite": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@planetscale/database": { + "optional": true + }, + "@prisma/client": { + "optional": true + }, + "@tidbcloud/serverless": { + "optional": true + }, + "@types/better-sqlite3": { + "optional": true + }, + "@types/pg": { + "optional": true + }, + "@types/sql.js": { + "optional": true + }, + "@vercel/postgres": { + "optional": true + }, + "@xata.io/client": { + "optional": true + }, + "better-sqlite3": { + "optional": true + }, + "bun-types": { + "optional": true + }, + "expo-sqlite": { + "optional": true + }, + "gel": { + "optional": true + }, + "knex": { + "optional": true + }, + "kysely": { + "optional": true + }, + "mysql2": { + "optional": true + }, + "pg": { + "optional": true + }, + "postgres": { + "optional": true + }, + "prisma": { + "optional": true + }, + "sql.js": { + "optional": true + }, + "sqlite3": { + "optional": true + } + } + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -5659,6 +6853,19 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/env-paths": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-3.0.0.tgz", + "integrity": "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -5843,6 +7050,58 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/esbuild": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz", + "integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=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" + } + }, + "node_modules/esbuild-register": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/esbuild-register/-/esbuild-register-3.6.0.tgz", + "integrity": "sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "peerDependencies": { + "esbuild": ">=0.12 <1" + } + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -6465,6 +7724,29 @@ "reusify": "^1.0.4" } }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -6561,6 +7843,18 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "license": "MIT", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -6622,6 +7916,66 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/gel": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/gel/-/gel-2.0.1.tgz", + "integrity": "sha512-gfem3IGvqKqXwEq7XseBogyaRwGsQGuE7Cw/yQsjLGdgiyqX92G1xENPCE0ltunPGcsJIa6XBOTx/PK169mOqw==", + "devOptional": true, + "license": "Apache-2.0", + "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" + }, + "engines": { + "node": ">= 18.0.0" + } + }, + "node_modules/gel/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "devOptional": true, + "license": "ISC", + "engines": { + "node": ">=16" + } + }, + "node_modules/gel/node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "devOptional": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/gel/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "devOptional": true, + "license": "ISC", + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -7661,6 +9015,12 @@ "url": "https://github.com/sponsors/panva" } }, + "node_modules/js-base64": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.7.tgz", + "integrity": "sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==", + "license": "BSD-3-Clause" + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -7795,6 +9155,44 @@ "node": ">= 0.8.0" } }, + "node_modules/libsql": { + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/libsql/-/libsql-0.4.7.tgz", + "integrity": "sha512-T9eIRCs6b0J1SHKYIvD8+KCJMcWZ900iZyxdnSCdqxN12Z1ijzT+jY5nrk72Jw4B0HGzms2NgpryArlJqvc3Lw==", + "cpu": [ + "x64", + "arm64", + "wasm32" + ], + "license": "MIT", + "os": [ + "darwin", + "linux", + "win32" + ], + "dependencies": { + "@neon-rs/load": "^0.0.4", + "detect-libc": "2.0.2" + }, + "optionalDependencies": { + "@libsql/darwin-arm64": "0.4.7", + "@libsql/darwin-x64": "0.4.7", + "@libsql/linux-arm64-gnu": "0.4.7", + "@libsql/linux-arm64-musl": "0.4.7", + "@libsql/linux-x64-gnu": "0.4.7", + "@libsql/linux-x64-musl": "0.4.7", + "@libsql/win32-x64-msvc": "0.4.7" + } + }, + "node_modules/libsql/node_modules/detect-libc": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", + "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, "node_modules/lilconfig": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", @@ -8086,7 +9484,7 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/mz": { @@ -8180,30 +9578,25 @@ } }, "node_modules/next-auth": { - "version": "4.24.11", - "resolved": "https://registry.npmjs.org/next-auth/-/next-auth-4.24.11.tgz", - "integrity": "sha512-pCFXzIDQX7xmHFs4KVH4luCjaCbuPRtZ9oBUjUhOk84mZ9WVPf94n87TxYI4rSRf9HmfHEF8Yep3JrYDVOo3Cw==", + "version": "5.0.0-beta.25", + "resolved": "https://registry.npmjs.org/next-auth/-/next-auth-5.0.0-beta.25.tgz", + "integrity": "sha512-2dJJw1sHQl2qxCrRk+KTQbeH+izFbGFPuJj5eGgBZFYyiYYtvlrBeUw1E/OJJxTRjuxbSYGnCTkUIRsIIW0bog==", "license": "ISC", "dependencies": { - "@babel/runtime": "^7.20.13", - "@panva/hkdf": "^1.0.2", - "cookie": "^0.7.0", - "jose": "^4.15.5", - "oauth": "^0.9.15", - "openid-client": "^5.4.0", - "preact": "^10.6.3", - "preact-render-to-string": "^5.1.19", - "uuid": "^8.3.2" + "@auth/core": "0.37.2" }, "peerDependencies": { - "@auth/core": "0.34.2", - "next": "^12.2.5 || ^13 || ^14 || ^15", + "@simplewebauthn/browser": "^9.0.1", + "@simplewebauthn/server": "^9.0.2", + "next": "^14.0.0-0 || ^15.0.0-0", "nodemailer": "^6.6.5", - "react": "^17.0.2 || ^18 || ^19", - "react-dom": "^17.0.2 || ^18 || ^19" + "react": "^18.2.0 || ^19.0.0-0" }, "peerDependenciesMeta": { - "@auth/core": { + "@simplewebauthn/browser": { + "optional": true + }, + "@simplewebauthn/server": { "optional": true }, "nodemailer": { @@ -8211,24 +9604,6 @@ } } }, - "node_modules/next-auth/node_modules/cookie": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", - "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/next-auth/node_modules/jose": { - "version": "4.15.9", - "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.9.tgz", - "integrity": "sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/panva" - } - }, "node_modules/next-themes": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.3.0.tgz", @@ -8278,6 +9653,43 @@ "tslib": "^2.0.3" } }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "license": "MIT", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, "node_modules/node-releases": { "version": "2.0.19", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", @@ -8307,16 +9719,10 @@ "url": "https://github.com/fb55/nth-check?sponsor=1" } }, - "node_modules/oauth": { - "version": "0.9.15", - "resolved": "https://registry.npmjs.org/oauth/-/oauth-0.9.15.tgz", - "integrity": "sha512-a5ERWK1kh38ExDEfoO6qUHJb32rd7aYmPHuyCu3Fta/cnICvYmgd2uhuKXvPD+PXB+gCEYYEaQdIRAjCOwAKNA==", - "license": "MIT" - }, "node_modules/oauth4webapi": { - "version": "2.17.0", - "resolved": "https://registry.npmjs.org/oauth4webapi/-/oauth4webapi-2.17.0.tgz", - "integrity": "sha512-lbC0Z7uzAFNFyzEYRIC+pkSVvDHJTbEW+dYlSBAlCYDe6RxUkJ26bClhk8ocBZip1wfI9uKTe0fm4Ib4RHn6uQ==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/oauth4webapi/-/oauth4webapi-3.3.1.tgz", + "integrity": "sha512-ZwX7UqYrP3Lr+Glhca3a1/nF2jqf7VVyJfhGuW5JtrfDUxt0u+IoBPzFjZ2dd7PJGkdM6CFPVVYzuDYKHv101A==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/panva" @@ -8331,15 +9737,6 @@ "node": ">=0.10.0" } }, - "node_modules/object-hash": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz", - "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==", - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, "node_modules/object-inspect": { "version": "1.13.4", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", @@ -8452,15 +9849,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/oidc-token-hash": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/oidc-token-hash/-/oidc-token-hash-5.1.0.tgz", - "integrity": "sha512-y0W+X7Ppo7oZX6eovsRkuzcSM40Bicg2JEJkDJ4irIt1wsYAP5MLSNv+QAogO8xivMffw/9OvV3um1pxXgt1uA==", - "license": "MIT", - "engines": { - "node": "^10.13.0 || >=12.0.0" - } - }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -8482,48 +9870,6 @@ "regex-recursion": "^6.0.2" } }, - "node_modules/openid-client": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/openid-client/-/openid-client-5.7.1.tgz", - "integrity": "sha512-jDBPgSVfTnkIh71Hg9pRvtJc6wTwqjRkN88+gCFtYWrlP4Yx2Dsrow8uPi3qLr/aeymPF3o2+dS+wOpglK04ew==", - "license": "MIT", - "dependencies": { - "jose": "^4.15.9", - "lru-cache": "^6.0.0", - "object-hash": "^2.2.0", - "oidc-token-hash": "^5.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/panva" - } - }, - "node_modules/openid-client/node_modules/jose": { - "version": "4.15.9", - "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.9.tgz", - "integrity": "sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/panva" - } - }, - "node_modules/openid-client/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/openid-client/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "license": "ISC" - }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -9039,9 +10385,10 @@ "version": "5.22.0", "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.22.0.tgz", "integrity": "sha512-vtpjW3XuYCSnMsNVBjLMNkTj6OZbudcPPTPYHqX0CJfpcdWciI1dM8uHETwmDxxiqEwCIE6WvXucWUetJgfu/A==", - "devOptional": true, "hasInstallScript": true, "license": "Apache-2.0", + "optional": true, + "peer": true, "dependencies": { "@prisma/engines": "5.22.0" }, @@ -9055,6 +10402,12 @@ "fsevents": "2.3.3" } }, + "node_modules/promise-limit": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/promise-limit/-/promise-limit-2.7.0.tgz", + "integrity": "sha512-7nJ6v5lnJsXwGprnGXga4wx6d1POjvi5Qmf1ivTRxTjH4Z/9Czja/UCMLVmB9N93GeWOU93XaFaEt6jbuoagNw==", + "license": "ISC" + }, "node_modules/prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", @@ -9278,6 +10631,7 @@ "version": "0.14.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "dev": true, "license": "MIT" }, "node_modules/regenerator-transform": { @@ -9690,6 +11044,19 @@ "node": ">=8" } }, + "node_modules/shell-quote": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.2.tgz", + "integrity": "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/shiki": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/shiki/-/shiki-3.1.0.tgz", @@ -9832,6 +11199,16 @@ "tslib": "^2.0.3" } }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -9841,6 +11218,17 @@ "node": ">=0.10.0" } }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, "node_modules/space-separated-tokens": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", @@ -10670,7 +12058,6 @@ "version": "6.19.8", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", - "dev": true, "license": "MIT" }, "node_modules/unicode-canonical-property-names-ecmascript": { @@ -10875,15 +12262,6 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "license": "MIT" }, - "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "license": "MIT", - "bin": { - "uuid": "dist/bin/uuid" - } - }, "node_modules/vfile": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", @@ -10912,6 +12290,15 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -11126,6 +12513,27 @@ "dev": true, "license": "ISC" }, + "node_modules/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", diff --git a/package.json b/package.json index 8a857ed..b9dfa6e 100644 --- a/package.json +++ b/package.json @@ -5,17 +5,25 @@ "type": "module", "scripts": { "build": "next build", - "vercel-build": "prisma migrate deploy && next build", - "db:push": "prisma db push", - "db:studio": "prisma studio", + "vercel-build": "next build", + "check": "next lint && tsc --noEmit", + "db:generate": "drizzle-kit generate", + "db:migrate": "drizzle-kit migrate", + "db:push": "drizzle-kit push", + "db:studio": "drizzle-kit studio", "dev": "next dev", - "postinstall": "prisma generate", + "format:check": "prettier --check \"**/*.{ts,tsx,js,jsx,mdx}\" --cache", + "format:write": "prettier --write \"**/*.{ts,tsx,js,jsx,mdx}\" --cache", "lint": "next lint", - "start": "next start" + "lint:fix": "next lint --fix", + "preview": "next build && next start", + "start": "next start", + "typecheck": "tsc --noEmit" }, "dependencies": { - "@auth/prisma-adapter": "^1.6.0", + "@auth/drizzle-adapter": "^1.8.0", "@catppuccin/palette": "^1.7.1", + "@libsql/client": "^0.14.0", "@prisma/client": "^5.22.0", "@radix-ui/react-dialog": "^1.1.6", "@radix-ui/react-dropdown-menu": "^2.1.6", @@ -33,10 +41,12 @@ "@trpc/server": "next", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", + "dotenv": "^16.5.0", + "drizzle-orm": "^0.40.0", "html-react-parser": "^5.2.2", "lucide-react": "^0.454.0", "next": "15.2.0", - "next-auth": "^4.24.11", + "next-auth": "^5.0.0-beta.25", "next-themes": "^0.3.0", "react": "19.0.0", "react-dom": "19.0.0", @@ -60,12 +70,12 @@ "@types/sanitize-html": "^2.13.0", "@typescript-eslint/eslint-plugin": "^7.18.0", "@typescript-eslint/parser": "^7.18.0", + "drizzle-kit": "^0.30.5", "eslint": "^8.57.1", "eslint-config-next": "15.2.0", "postcss": "^8.5.3", "prettier": "^3.5.2", "prettier-plugin-tailwindcss": "^0.5.14", - "prisma": "^5.22.0", "tailwindcss": "^3.4.17", "typescript": "^5.8.2" }, diff --git a/prisma/schema.prisma b/prisma/schema.prisma deleted file mode 100644 index eb616c5..0000000 --- a/prisma/schema.prisma +++ /dev/null @@ -1,79 +0,0 @@ -// This is your Prisma schema file, -// learn more about it in the docs: https://pris.ly/d/prisma-schema - -generator client { - provider = "prisma-client-js" -} - -datasource db { - provider = "postgresql" - // NOTE: When using mysql or sqlserver, uncomment the @db.Text annotations in model Account below - // Further reading: - // https://next-auth.js.org/adapters/prisma#create-the-prisma-schema - // https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference#string - - // Uses connection pooling - url = env("POSTGRES_PRISMA_URL") - - // Uses direct connection, ⚠️ make sure to keep this to `POSTGRES_URL_NON_POOLING` - // or you'll have dangling databases from migrations - directUrl = env("POSTGRES_URL_NON_POOLING") -} - -model Post { - id Int @id @default(autoincrement()) - name String - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - - createdBy User @relation(fields: [createdById], references: [id]) - createdById String - - @@index([name]) -} - -// Necessary for Next auth -model Account { - id String @id @default(cuid()) - userId String - type String - provider String - providerAccountId String - refresh_token String? // @db.Text - access_token String? // @db.Text - expires_at Int? - token_type String? - scope String? - id_token String? // @db.Text - session_state String? - user User @relation(fields: [userId], references: [id], onDelete: Cascade) - - @@unique([provider, providerAccountId]) -} - -model Session { - id String @id @default(cuid()) - sessionToken String @unique - userId String - expires DateTime - user User @relation(fields: [userId], references: [id], onDelete: Cascade) -} - -model User { - id String @id @default(cuid()) - name String? - email String? @unique - emailVerified DateTime? - image String? - accounts Account[] - sessions Session[] - posts Post[] -} - -model VerificationToken { - identifier String - token String @unique - expires DateTime - - @@unique([identifier, token]) -} diff --git a/src/app/about/advanced/page.tsx b/src/app/about/advanced/page.tsx index 8fad2a7..6758462 100644 --- a/src/app/about/advanced/page.tsx +++ b/src/app/about/advanced/page.tsx @@ -34,17 +34,27 @@ export default function AdvancedSiteInfo() { Key Value + Notes - + + This represents the name of the branch that this deployment is + produced from. Will be used for DB branching too + ); } -function EnvVarRow({ envVar }: { envVar: keyof typeof env }) { +function EnvVarRow({ + envVar, + children, +}: { + envVar: keyof typeof env; + children?: React.ReactNode; +}) { const value = env[envVar]; return ( @@ -52,6 +62,7 @@ function EnvVarRow({ envVar }: { envVar: keyof typeof env }) { {typeof value === "undefined" ? "undefined" : value} + {children} ); } diff --git a/src/app/api/auth/[...nextauth]/route.ts b/src/app/api/auth/[...nextauth]/route.ts index 7ef8967..8e8302c 100644 --- a/src/app/api/auth/[...nextauth]/route.ts +++ b/src/app/api/auth/[...nextauth]/route.ts @@ -1,7 +1,3 @@ -import NextAuth from "next-auth"; +import { handlers } from "~/server/auth"; -import { authOptions } from "~/server/auth"; - -// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -const handler = NextAuth(authOptions); -export { handler as GET, handler as POST }; +export const { GET, POST } = handlers; diff --git a/src/app/java/changelog/layout.tsx b/src/app/java/changelog/layout.tsx index 857eb58..430bbb5 100644 --- a/src/app/java/changelog/layout.tsx +++ b/src/app/java/changelog/layout.tsx @@ -33,7 +33,9 @@ export default async function ChangelogLayout({ Error loading version manifest - {fromError(maybeVersions.error).toString()} + {typeof maybeVersions.error === "string" + ? maybeVersions.error + : fromError(maybeVersions.error).toString()} diff --git a/src/app/page.tsx b/src/app/page.tsx index e0907f5..d03d4d9 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -5,7 +5,7 @@ import { SubredditLink } from "~/components/subreddit-link"; import { Badge } from "~/components/ui/badge"; // import { CreatePost } from "~/app/_components/create-post"; -// import { getServerAuthSession } from "~/server/auth"; +// import { auth } from "~/server/auth"; // import { api } from "~/trpc/server"; const SOCIALS = [ @@ -15,10 +15,10 @@ const SOCIALS = [ export default async function Home() { // const hello = await api.post.hello({ text: "from tRPC" }); - // const session = await getServerAuthSession(); + // const session = await auth(); return ( -
+

Welcome to MCC Gadgets!

Tools for the Minecraft Commands community

diff --git a/src/components/java/patch-notes.tsx b/src/components/java/patch-notes.tsx index db7c9c0..3aabe3a 100644 --- a/src/components/java/patch-notes.tsx +++ b/src/components/java/patch-notes.tsx @@ -10,7 +10,7 @@ import parseHtml, { import Image from "next/image"; import { createElement, Suspense, type JSX } from "react"; import sanitizeHtml from "sanitize-html"; -import { fromError, isZodErrorLike } from "zod-validation-error"; +import { fromError } from "zod-validation-error"; import { PublishDate } from "~/components/java/publish-date"; import { Alert, AlertDescription, AlertTitle } from "~/components/ui/alert"; import { textContent } from "~/lib/element"; @@ -63,7 +63,7 @@ async function PatchNotesImpl({ if (!maybePatchNotes.success) { let msg: string; - if (isZodErrorLike(maybePatchNotes.error)) { + if (maybePatchNotes.error instanceof Error) { msg = fromError(maybePatchNotes.error).toString(); } else { msg = maybePatchNotes.error; diff --git a/src/env.js b/src/env.js index a06f9b9..d11757c 100644 --- a/src/env.js +++ b/src/env.js @@ -1,5 +1,18 @@ import { createEnv } from "@t3-oss/env-nextjs"; import { z } from "zod"; +/** + * @import { type ZodType } from "zod" + */ + +/** + * @template {ZodType} T + * @param {T} validator + */ +function optionalInDev(validator) { + return process.env.NODE_ENV === "production" + ? validator + : validator.optional(); +} export const env = createEnv({ /** @@ -7,15 +20,13 @@ export const env = createEnv({ * isn't built with invalid env vars. */ server: { - POSTGRES_PRISMA_URL: z.string().url(), - POSTGRES_URL_NON_POOLING: z.string().url(), + DATABASE_URL: z.string().url(), + TURSO_AUTH_TOKEN: optionalInDev(z.string()), + TURSO_ORG_SLUG: optionalInDev(z.string()), NODE_ENV: z .enum(["development", "test", "production"]) .default("development"), - NEXTAUTH_SECRET: - process.env.NODE_ENV === "production" - ? z.string() - : z.string().optional(), + NEXTAUTH_SECRET: optionalInDev(z.string()), NEXTAUTH_URL: z.preprocess( // This makes Vercel deployments not fail if you don't set NEXTAUTH_URL // Since NextAuth.js automatically uses the VERCEL_URL if present. @@ -23,9 +34,10 @@ export const env = createEnv({ // VERCEL_URL doesn't include `https` so it cant be validated as a URL process.env.VERCEL ? z.string() : z.string().url() ), - DISCORD_CLIENT_ID: z.string(), - DISCORD_CLIENT_SECRET: z.string(), + DISCORD_CLIENT_ID: optionalInDev(z.string()), + DISCORD_CLIENT_SECRET: optionalInDev(z.string()), VERCEL_GIT_COMMIT_REF: z.string().optional(), + VERCEL_GIT_PULL_REQUEST_ID: z.number().int().optional(), }, /** @@ -42,14 +54,16 @@ export const env = createEnv({ * middlewares) or client-side so we need to destruct manually. */ runtimeEnv: { - POSTGRES_PRISMA_URL: process.env.POSTGRES_PRISMA_URL, - POSTGRES_URL_NON_POOLING: process.env.POSTGRES_URL_NON_POOLING, + DATABASE_URL: process.env.DATABASE_URL, + TURSO_AUTH_TOKEN: process.env.TURSO_AUTH_TOKEN, + TURSO_ORG_SLUG: process.env.TURSO_ORG_SLUG, NODE_ENV: process.env.NODE_ENV, NEXTAUTH_SECRET: process.env.NEXTAUTH_SECRET, NEXTAUTH_URL: process.env.NEXTAUTH_URL, DISCORD_CLIENT_ID: process.env.DISCORD_CLIENT_ID, DISCORD_CLIENT_SECRET: process.env.DISCORD_CLIENT_SECRET, VERCEL_GIT_COMMIT_REF: process.env.VERCEL_GIT_COMMIT_REF, + VERCEL_GIT_PULL_REQUEST_ID: process.env.VERCEL_GIT_PULL_REQUEST_ID, }, /** * Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially diff --git a/src/lib/fetch.ts b/src/lib/fetch.ts index 7f26e2d..e137b03 100644 --- a/src/lib/fetch.ts +++ b/src/lib/fetch.ts @@ -1,6 +1,14 @@ import { unstable_cache } from "next/cache"; import SuperJSON from "superjson"; -import { ZodError } from "zod"; +import { ZodError, type z, type ZodType } from "zod"; +import { + err, + type Err, + type Ok, + type ParseResult, + type Result, +} from "./result"; +import { fromError } from "zod-validation-error"; SuperJSON.registerClass(ZodError); @@ -27,3 +35,76 @@ export function cache Promise>( return deserialized; } + +async function parseJson(res: Response, schema: T) { + try { + const body = (await res.json()) as unknown; + return await schema.safeParseAsync(body); + } catch (error) { + return err(error as TypeError); + } +} + +export type FetchAndParseResult< + TSchema extends ZodType, + ESchema extends ZodType = never, +> = ParseResult< + TSchema, + TypeError | ([ESchema] extends [never] ? string : ParseResult) +>; + +export function fetchAndParseErrToString< + // eslint-disable-next-line @typescript-eslint/no-explicit-any + TErr extends Err>, +>( + result: TErr, + ...[errResultToString]: TErr extends Err + ? TOuter extends Ok + ? [(value: TInner) => string] + : never + : [] +) { + const e = result.error; + if (typeof e === "string") { + return e; + } else if (e instanceof Error) { + return fromError(e).toString(); + } else if (e.success) { + return errResultToString(e.data); + } else { + return fromError(e.error).toString(); + } +} + +export async function fetchAndParse( + url: string, + schema: TSchema, + options?: RequestInit, +): Promise>; +export async function fetchAndParse< + TSchema extends ZodType, + ESchema extends ZodType, +>( + url: string, + schema: TSchema, + options: RequestInit, + errorSchema: ESchema, +): Promise>; +export async function fetchAndParse< + TSchema extends ZodType, + ESchema extends ZodType = never, +>( + url: string, + schema: TSchema, + options: RequestInit = {}, + errorSchema?: ESchema, +): Promise | TypeError | string>> { + const res = await fetch(url, options); + if (res.ok) { + return await parseJson(res, schema); + } else if (errorSchema) { + return await parseJson(res, errorSchema); + } else { + return err(res.statusText); + } +} diff --git a/src/lib/result.ts b/src/lib/result.ts new file mode 100644 index 0000000..726adb1 --- /dev/null +++ b/src/lib/result.ts @@ -0,0 +1,40 @@ +import type { z, ZodError, ZodType } from "zod"; + +export type Ok = { + success: true; + data: T; + error?: never; +}; + +export function ok(data: T): Ok { + return { + success: true, + data, + }; +} + +export type Err = { + success: false; + data?: never; + error: T; +}; + +export function err(error: T): Err { + return { + success: false, + error, + }; +} + +/** + * A general success/failure that is structurally compatible with the result of Zod's safeParse + */ +export type Result = Ok | Err; + +export type ParseResult = Result< + z.infer, + ZodError> | TErr +>; + +export type ErrType = T extends Err ? E : never; +export type OkType = T extends Ok ? V : never; diff --git a/src/lib/utils.ts b/src/lib/utils.ts index be4904c..6d45093 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -20,3 +20,6 @@ export function capitalise(str: string): string { export type Modify = Omit & R; export type WithCn = Modify; + +// eslint-disable-next-line @typescript-eslint/ban-types +export type FuzzyAutocomplete = T | (string & {}); diff --git a/src/server/api/routers/post.ts b/src/server/api/routers/post.ts index 3994691..7a296c9 100644 --- a/src/server/api/routers/post.ts +++ b/src/server/api/routers/post.ts @@ -1,42 +1,39 @@ -import { z } from "zod"; +// import { z } from "zod"; -import { - createTRPCRouter, - protectedProcedure, - publicProcedure, -} from "~/server/api/trpc"; +// import { +// createTRPCRouter, +// protectedProcedure, +// publicProcedure, +// } from "~/server/api/trpc"; +// import { posts } from "~/server/db/schema"; -export const postRouter = createTRPCRouter({ - hello: publicProcedure - .input(z.object({ text: z.string() })) - .query(({ input }) => { - return { - greeting: `Hello ${input.text}`, - }; - }), +// export const postRouter = createTRPCRouter({ +// hello: publicProcedure +// .input(z.object({ text: z.string() })) +// .query(({ input }) => { +// return { +// greeting: `Hello ${input.text}`, +// }; +// }), - create: protectedProcedure - .input(z.object({ name: z.string().min(1) })) - .mutation(async ({ ctx, input }) => { - // simulate a slow db call - await new Promise((resolve) => setTimeout(resolve, 1000)); +// create: protectedProcedure +// .input(z.object({ name: z.string().min(1) })) +// .mutation(async ({ ctx, input }) => { +// await ctx.db.insert(posts).values({ +// name: input.name, +// createdById: ctx.session.user.id, +// }); +// }), - return ctx.db.post.create({ - data: { - name: input.name, - createdBy: { connect: { id: ctx.session.user.id } }, - }, - }); - }), +// getLatest: protectedProcedure.query(async ({ ctx }) => { +// const post = await ctx.db.query.posts.findFirst({ +// orderBy: (posts, { desc }) => [desc(posts.createdAt)], +// }); - getLatest: protectedProcedure.query(({ ctx }) => { - return ctx.db.post.findFirst({ - orderBy: { createdAt: "desc" }, - where: { createdBy: { id: ctx.session.user.id } }, - }); - }), +// return post ?? null; +// }), - getSecretMessage: protectedProcedure.query(() => { - return "you can now see this secret message!"; - }), -}); +// getSecretMessage: protectedProcedure.query(() => { +// return "you can now see this secret message!"; +// }), +// }); diff --git a/src/server/api/trpc.ts b/src/server/api/trpc.ts index 486a816..00d924f 100644 --- a/src/server/api/trpc.ts +++ b/src/server/api/trpc.ts @@ -11,7 +11,7 @@ import { initTRPC, TRPCError } from "@trpc/server"; import superjson from "superjson"; import { ZodError } from "zod"; -import { getServerAuthSession } from "~/server/auth"; +import { auth } from "~/server/auth"; import { db } from "~/server/db"; /** @@ -27,7 +27,7 @@ import { db } from "~/server/db"; * @see https://trpc.io/docs/server/context */ export const createTRPCContext = async (opts: { headers: Headers }) => { - const session = await getServerAuthSession(); + const session = await auth(); return { db, @@ -78,6 +78,29 @@ export const createCallerFactory = t.createCallerFactory; */ export const createTRPCRouter = t.router; +/** + * Middleware for timing procedure execution and adding an artificial delay in development. + * + * You can remove this if you don't like it, but it can help catch unwanted waterfalls by simulating + * network latency that would occur in production but not in local development. + */ +const timingMiddleware = t.middleware(async ({ next, path }) => { + const start = Date.now(); + + if (t._config.isDev) { + // artificial delay in dev + const waitMs = Math.floor(Math.random() * 400) + 100; + await new Promise((resolve) => setTimeout(resolve, waitMs)); + } + + const result = await next(); + + const end = Date.now(); + console.log(`[TRPC] ${path} took ${end - start}ms to execute`); + + return result; +}); + /** * Public (unauthenticated) procedure * @@ -85,7 +108,7 @@ export const createTRPCRouter = t.router; * guarantee that a user querying is authorized, but you can still access user session data if they * are logged in. */ -export const publicProcedure = t.procedure; +export const publicProcedure = t.procedure.use(timingMiddleware); /** * Protected (authenticated) procedure @@ -95,14 +118,16 @@ export const publicProcedure = t.procedure; * * @see https://trpc.io/docs/procedures */ -export const protectedProcedure = t.procedure.use(({ ctx, next }) => { - if (!ctx.session || !ctx.session.user) { - throw new TRPCError({ code: "UNAUTHORIZED" }); - } - return next({ - ctx: { - // infers the `session` as non-nullable - session: { ...ctx.session, user: ctx.session.user }, - }, +export const protectedProcedure = t.procedure + .use(timingMiddleware) + .use(({ ctx, next }) => { + if (!ctx.session || !ctx.session.user) { + throw new TRPCError({ code: "UNAUTHORIZED" }); + } + return next({ + ctx: { + // infers the `session` as non-nullable + session: { ...ctx.session, user: ctx.session.user }, + }, + }); }); -}); diff --git a/src/server/auth.ts b/src/server/auth/config.ts similarity index 73% rename from src/server/auth.ts rename to src/server/auth/config.ts index 117984c..3ae1675 100644 --- a/src/server/auth.ts +++ b/src/server/auth/config.ts @@ -1,14 +1,15 @@ -import { PrismaAdapter } from "@auth/prisma-adapter"; -import { - getServerSession, - type DefaultSession, - type NextAuthOptions, -} from "next-auth"; -import { type Adapter } from "next-auth/adapters"; +import { DrizzleAdapter } from "@auth/drizzle-adapter"; +import { type DefaultSession, type NextAuthConfig } from "next-auth"; import DiscordProvider from "next-auth/providers/discord"; import { env } from "~/env"; import { db } from "~/server/db"; +import { + accounts, + sessions, + users, + verificationTokens, +} from "~/server/db/schema"; /** * Module augmentation for `next-auth` types. Allows us to add custom properties to the `session` @@ -36,7 +37,7 @@ declare module "next-auth" { * * @see https://next-auth.js.org/configuration/options */ -export const authOptions: NextAuthOptions = { +export const authConfig = { callbacks: { session: ({ session, user }) => ({ ...session, @@ -46,7 +47,12 @@ export const authOptions: NextAuthOptions = { }, }), }, - adapter: PrismaAdapter(db) as Adapter, + adapter: DrizzleAdapter(db, { + usersTable: users, + accountsTable: accounts, + sessionsTable: sessions, + verificationTokensTable: verificationTokens, + }), providers: [ DiscordProvider({ clientId: env.DISCORD_CLIENT_ID, @@ -62,11 +68,4 @@ export const authOptions: NextAuthOptions = { * @see https://next-auth.js.org/providers/github */ ], -}; - -/** - * Wrapper for `getServerSession` so that you don't need to import the `authOptions` in every file. - * - * @see https://next-auth.js.org/configuration/nextjs - */ -export const getServerAuthSession = () => getServerSession(authOptions); +} satisfies NextAuthConfig; diff --git a/src/server/auth/index.ts b/src/server/auth/index.ts new file mode 100644 index 0000000..76c146d --- /dev/null +++ b/src/server/auth/index.ts @@ -0,0 +1,10 @@ +import NextAuth from "next-auth"; +import { cache } from "react"; + +import { authConfig } from "./config"; + +const { auth: uncachedAuth, handlers, signIn, signOut } = NextAuth(authConfig); + +const auth = cache(uncachedAuth); + +export { auth, handlers, signIn, signOut }; diff --git a/src/server/db.ts b/src/server/db.ts deleted file mode 100644 index 07dc027..0000000 --- a/src/server/db.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { PrismaClient } from "@prisma/client"; - -import { env } from "~/env"; - -const createPrismaClient = () => - new PrismaClient({ - log: - env.NODE_ENV === "development" ? ["query", "error", "warn"] : ["error"], - }); - -const globalForPrisma = globalThis as unknown as { - prisma: ReturnType | undefined; -}; - -export const db = globalForPrisma.prisma ?? createPrismaClient(); - -if (env.NODE_ENV !== "production") globalForPrisma.prisma = db; diff --git a/src/server/db/index.ts b/src/server/db/index.ts new file mode 100644 index 0000000..a46035f --- /dev/null +++ b/src/server/db/index.ts @@ -0,0 +1,58 @@ +import { createClient, type Client } from "@libsql/client"; +import { drizzle } from "drizzle-orm/libsql"; + +import { env } from "~/env"; +import * as schema from "./schema"; +import { retrieveDatabase } from "./turso"; +import { previewDbId } from "./utils"; +import { fetchAndParseErrToString } from "~/lib/fetch"; + +/** + * Cache the database connection in development. This avoids creating a new connection on every HMR + * update. + */ +const globalForDb = globalThis as unknown as { + client: Client | undefined; +}; + +export async function getDbCredentials(): Promise<{ + url: string; + authToken?: string; +}> { + const { + VERCEL_GIT_PULL_REQUEST_ID: prNum, + VERCEL_GIT_COMMIT_REF: branchName, + NODE_ENV, + DATABASE_URL, + TURSO_AUTH_TOKEN, + } = env; + + if ( + NODE_ENV !== "production" || + typeof prNum === "undefined" || + !branchName || + branchName === "main" + ) { + return { + url: DATABASE_URL, + authToken: TURSO_AUTH_TOKEN, + }; + } + + // Fetch hostname for the preview database from the Turso platform API + const dbInfo = await retrieveDatabase(previewDbId(prNum, branchName)); + if (!dbInfo.success) { + throw new Error(fetchAndParseErrToString(dbInfo, (e) => e.error)); + } + + return { + url: `https://${dbInfo.data.Hostname}`, + authToken: TURSO_AUTH_TOKEN, + }; +} + +export const client = + globalForDb.client ?? createClient(await getDbCredentials()); +if (env.NODE_ENV !== "production") globalForDb.client = client; + +export const db = drizzle(client, { schema }); diff --git a/src/server/db/migrations/0000_gigantic_carmella_unuscione.sql b/src/server/db/migrations/0000_gigantic_carmella_unuscione.sql new file mode 100644 index 0000000..ba4d740 --- /dev/null +++ b/src/server/db/migrations/0000_gigantic_carmella_unuscione.sql @@ -0,0 +1,40 @@ +CREATE TABLE `mcc-gadgets_account` ( + `user_id` text(255) NOT NULL, + `type` text(255) NOT NULL, + `provider` text(255) NOT NULL, + `provider_account_id` text(255) NOT NULL, + `refresh_token` text, + `access_token` text, + `expires_at` integer, + `token_type` text(255), + `scope` text(255), + `id_token` text, + `session_state` text(255), + PRIMARY KEY(`provider`, `provider_account_id`), + FOREIGN KEY (`user_id`) REFERENCES `mcc-gadgets_user`(`id`) ON UPDATE no action ON DELETE cascade +); +--> statement-breakpoint +CREATE INDEX `account_user_id_idx` ON `mcc-gadgets_account` (`user_id`);--> statement-breakpoint +CREATE TABLE `mcc-gadgets_session` ( + `session_token` text(255) PRIMARY KEY NOT NULL, + `userId` text(255) NOT NULL, + `expires` integer NOT NULL, + FOREIGN KEY (`userId`) REFERENCES `mcc-gadgets_user`(`id`) ON UPDATE no action ON DELETE cascade +); +--> statement-breakpoint +CREATE INDEX `session_userId_idx` ON `mcc-gadgets_session` (`userId`);--> statement-breakpoint +CREATE TABLE `mcc-gadgets_user` ( + `id` text(255) PRIMARY KEY NOT NULL, + `name` text(255), + `email` text(255), + `email_verified` integer, + `image` text(255) +); +--> statement-breakpoint +CREATE UNIQUE INDEX `mcc-gadgets_user_email_unique` ON `mcc-gadgets_user` (`email`);--> statement-breakpoint +CREATE TABLE `mcc-gadgets_verification_token` ( + `identifier` text(255) NOT NULL, + `token` text(255) NOT NULL, + `expires` integer NOT NULL, + PRIMARY KEY(`identifier`, `token`) +); diff --git a/src/server/db/migrations/meta/0000_snapshot.json b/src/server/db/migrations/meta/0000_snapshot.json new file mode 100644 index 0000000..f0315fd --- /dev/null +++ b/src/server/db/migrations/meta/0000_snapshot.json @@ -0,0 +1,280 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "1682405c-0786-4808-b6b1-d39dfe2f487d", + "prevId": "00000000-0000-0000-0000-000000000000", + "tables": { + "mcc-gadgets_account": { + "name": "mcc-gadgets_account", + "columns": { + "user_id": { + "name": "user_id", + "type": "text(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "provider": { + "name": "provider", + "type": "text(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "provider_account_id": { + "name": "provider_account_id", + "type": "text(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "token_type": { + "name": "token_type", + "type": "text(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "scope": { + "name": "scope", + "type": "text(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "session_state": { + "name": "session_state", + "type": "text(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "account_user_id_idx": { + "name": "account_user_id_idx", + "columns": [ + "user_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "mcc-gadgets_account_user_id_mcc-gadgets_user_id_fk": { + "name": "mcc-gadgets_account_user_id_mcc-gadgets_user_id_fk", + "tableFrom": "mcc-gadgets_account", + "tableTo": "mcc-gadgets_user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "mcc-gadgets_account_provider_provider_account_id_pk": { + "columns": [ + "provider", + "provider_account_id" + ], + "name": "mcc-gadgets_account_provider_provider_account_id_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "mcc-gadgets_session": { + "name": "mcc-gadgets_session", + "columns": { + "session_token": { + "name": "session_token", + "type": "text(255)", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "userId": { + "name": "userId", + "type": "text(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires": { + "name": "expires", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "session_userId_idx": { + "name": "session_userId_idx", + "columns": [ + "userId" + ], + "isUnique": false + } + }, + "foreignKeys": { + "mcc-gadgets_session_userId_mcc-gadgets_user_id_fk": { + "name": "mcc-gadgets_session_userId_mcc-gadgets_user_id_fk", + "tableFrom": "mcc-gadgets_session", + "tableTo": "mcc-gadgets_user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "mcc-gadgets_user": { + "name": "mcc-gadgets_user", + "columns": { + "id": { + "name": "id", + "type": "text(255)", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "email_verified": { + "name": "email_verified", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "image": { + "name": "image", + "type": "text(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "mcc-gadgets_user_email_unique": { + "name": "mcc-gadgets_user_email_unique", + "columns": [ + "email" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "mcc-gadgets_verification_token": { + "name": "mcc-gadgets_verification_token", + "columns": { + "identifier": { + "name": "identifier", + "type": "text(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires": { + "name": "expires", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "mcc-gadgets_verification_token_identifier_token_pk": { + "columns": [ + "identifier", + "token" + ], + "name": "mcc-gadgets_verification_token_identifier_token_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} \ No newline at end of file diff --git a/src/server/db/migrations/meta/_journal.json b/src/server/db/migrations/meta/_journal.json new file mode 100644 index 0000000..4a76a0a --- /dev/null +++ b/src/server/db/migrations/meta/_journal.json @@ -0,0 +1,13 @@ +{ + "version": "7", + "dialect": "sqlite", + "entries": [ + { + "idx": 0, + "version": "6", + "when": 1745979267601, + "tag": "0000_gigantic_carmella_unuscione", + "breakpoints": true + } + ] +} \ No newline at end of file diff --git a/src/server/db/schema.ts b/src/server/db/schema.ts new file mode 100644 index 0000000..eafc1c3 --- /dev/null +++ b/src/server/db/schema.ts @@ -0,0 +1,110 @@ +import { relations } from "drizzle-orm"; +import { + index, + int, + primaryKey, + sqliteTableCreator, + text, +} from "drizzle-orm/sqlite-core"; +import { type AdapterAccount } from "next-auth/adapters"; + +/** + * This is an example of how to use the multi-project schema feature of Drizzle ORM. Use the same + * database instance for multiple projects. + * + * @see https://orm.drizzle.team/docs/goodies#multi-project-schema + */ +export const createTable = sqliteTableCreator((name) => `mcc-gadgets_${name}`); + +// export const posts = createTable( +// "post", +// { +// id: int("id", { mode: "number" }).primaryKey({ autoIncrement: true }), +// name: text("name", { length: 256 }), +// createdById: text("created_by", { length: 255 }) +// .notNull() +// .references(() => users.id), +// createdAt: int("created_at", { mode: "timestamp" }) +// .default(sql`(unixepoch())`) +// .notNull(), +// updatedAt: int("updated_at", { mode: "timestamp" }).$onUpdate( +// () => new Date(), +// ), +// }, +// (example) => [ +// index("created_by_idx").on(example.createdById), +// index("name_idx").on(example.name), +// ], +// ); + +export const users = createTable("user", { + id: text("id", { length: 255 }) + .notNull() + .primaryKey() + .$defaultFn(() => crypto.randomUUID()), + name: text("name", { length: 255 }), + email: text("email", { length: 255 }).unique(), + emailVerified: int("email_verified", { mode: "timestamp_ms" }), + image: text("image", { length: 255 }), +}); + +export const usersRelations = relations(users, ({ many }) => ({ + accounts: many(accounts), +})); + +export const accounts = createTable( + "account", + { + userId: text("user_id", { length: 255 }) + .notNull() + .references(() => users.id, { onDelete: "cascade" }), + type: text("type", { length: 255 }) + .$type() + .notNull(), + provider: text("provider", { length: 255 }).notNull(), + providerAccountId: text("provider_account_id", { length: 255 }).notNull(), + refresh_token: text("refresh_token"), + access_token: text("access_token"), + expires_at: int("expires_at"), + token_type: text("token_type", { length: 255 }), + scope: text("scope", { length: 255 }), + id_token: text("id_token"), + session_state: text("session_state", { length: 255 }), + }, + (account) => [ + primaryKey({ + columns: [account.provider, account.providerAccountId], + }), + index("account_user_id_idx").on(account.userId), + ], +); + +export const accountsRelations = relations(accounts, ({ one }) => ({ + user: one(users, { fields: [accounts.userId], references: [users.id] }), +})); + +export const sessions = createTable( + "session", + { + sessionToken: text("session_token", { length: 255 }).notNull().primaryKey(), + userId: text("userId", { length: 255 }) + .notNull() + .references(() => users.id, { onDelete: "cascade" }), + expires: int("expires", { mode: "timestamp_ms" }).notNull(), + }, + (session) => [index("session_userId_idx").on(session.userId)], +); + +export const sessionsRelations = relations(sessions, ({ one }) => ({ + user: one(users, { fields: [sessions.userId], references: [users.id] }), +})); + +export const verificationTokens = createTable( + "verification_token", + { + identifier: text("identifier", { length: 255 }).notNull(), + token: text("token", { length: 255 }).notNull(), + expires: int("expires", { mode: "timestamp_ms" }).notNull(), + }, + (vt) => [primaryKey({ columns: [vt.identifier, vt.token] })], +); diff --git a/src/server/db/turso/index.ts b/src/server/db/turso/index.ts new file mode 100644 index 0000000..7f4c1a9 --- /dev/null +++ b/src/server/db/turso/index.ts @@ -0,0 +1,33 @@ +import type { ZodType } from "zod"; +import { env } from "~/env"; +import { fetchAndParse, type FetchAndParseResult } from "~/lib/fetch"; +import { err, type Err } from "~/lib/result"; +import { DATABASE_INFO_SCHEMA, ERROR_RESPONSE_SCHEMA } from "./schemas"; + +async function tursoFetch( + path: string, + schema: TSchema, +): Promise< + FetchAndParseResult | Err +> { + const { TURSO_ORG_SLUG, TURSO_AUTH_TOKEN } = env; + if (!TURSO_ORG_SLUG || !TURSO_AUTH_TOKEN) { + return err("No Turso info, are you running in development?"); + } + + return await fetchAndParse( + `https://api.turso.tech/v1/organizations/${TURSO_ORG_SLUG}/${path}`, + schema, + { + method: "get", + headers: new Headers({ + Authorization: `Bearer ${TURSO_AUTH_TOKEN}`, + }), + }, + ERROR_RESPONSE_SCHEMA, + ); +} + +export async function retrieveDatabase(dbName: string) { + return tursoFetch(`databases/${dbName}`, DATABASE_INFO_SCHEMA); +} diff --git a/src/server/db/turso/schemas.ts b/src/server/db/turso/schemas.ts new file mode 100644 index 0000000..0a8f3e0 --- /dev/null +++ b/src/server/db/turso/schemas.ts @@ -0,0 +1,34 @@ +import { z } from "zod"; + +export const DATABASE_INFO_SCHEMA = z.object({ + Name: z.string(), + DbId: z.string().uuid(), + Hostname: z.string(), // hostname doesn't have the URL scheme, so can't be validated as url + block_reads: z.boolean(), + block_writes: z.boolean(), + allow_attach: z.boolean(), + regions: z.string().array(), + primaryRegion: z.string(), + type: z.string().default("logical"), + version: z.string(), + group: z.string(), + is_schema: z.boolean(), + schema: z.string(), + archived: z.boolean(), +}); + +export type DatabaseInfo = z.infer; + +export const RETRIEVE_DATABASE_RESPONSE_SCHEMA = z.object({ + database: DATABASE_INFO_SCHEMA, +}); + +export type RetrieveDatabaseResponse = z.infer< + typeof RETRIEVE_DATABASE_RESPONSE_SCHEMA +>; + +export const ERROR_RESPONSE_SCHEMA = z.object({ + error: z.string(), +}); + +export type ErrorResponse = z.infer; diff --git a/src/server/db/utils.js b/src/server/db/utils.js new file mode 100644 index 0000000..6ef9811 --- /dev/null +++ b/src/server/db/utils.js @@ -0,0 +1,9 @@ +// This file is intentionally .js instead of .ts, and doesn't import from anywhere else in the project so it can easily be called from github actions + +/** + * @param {number | undefined} prNum + * @param {string} branchName + */ +export function previewDbId(prNum, branchName) { + return `pr-${prNum}-${branchName}`.toLowerCase().replace(/\W/g, "").substring(0, 64); +} diff --git a/src/server/java/versions.ts b/src/server/java/versions.ts index 442c9fa..c3b7537 100644 --- a/src/server/java/versions.ts +++ b/src/server/java/versions.ts @@ -1,5 +1,7 @@ -import { cache } from "~/lib/fetch"; +import { cache, fetchAndParse, type FetchAndParseResult } from "~/lib/fetch"; import { type ZodError, z } from "zod"; +import { err, ok, type Result } from "~/lib/result"; +import type { FuzzyAutocomplete } from "~/lib/utils"; const VERSION_MANIFEST_ENTRY_SCHEMA = z.object({ title: z.string(), @@ -44,18 +46,11 @@ export const BASE_ASSET_URL = "https://launchercontent.mojang.com"; const BASE_URL = BASE_ASSET_URL + "/v2/"; export const getVersionManifest = cache( - async (): Promise< - | { success: true; data: VersionManifest } - | { - success: false; - error: VersionManifestZodError; - } - > => { - const versionsRes = await fetch(BASE_URL + "javaPatchNotes.json"); - const versions = VERSIONS_MANIFEST_SCHEMA.safeParse( - await versionsRes.json(), + async (): Promise> => { + const versions = await fetchAndParse( + BASE_URL + "javaPatchNotes.json", + VERSIONS_MANIFEST_SCHEMA, ); - if (versions.success) { versions.data.entries.sort((a, b) => (a.date < b.date ? 1 : -1)); } @@ -75,18 +70,11 @@ export type PatchNote = VersionManifestEntry & z.infer; export type PatchNoteZodError = ZodError>; -export enum PatchNotesError { - VersionNotFound = "Version not found", -} - export type PatchNotesQuery = string | { latest: string[] | string | true }; export async function getPartialVersion( version: PatchNotesQuery = { latest: true }, -): Promise< - | { success: true; data: VersionManifestEntry } - | { success: false; error: VersionManifestZodError | PatchNotesError } -> { +): Promise> { const versions = await getVersionManifest(); if (!versions.success) return versions; @@ -104,21 +92,19 @@ export async function getPartialVersion( partialVersion = versions.data.entries.find((v) => includes(v.type)); } - if (!partialVersion) - return { success: false, error: PatchNotesError.VersionNotFound }; + if (!partialVersion) return err("Version not found"); - return { success: true, data: partialVersion }; + return ok(partialVersion); } export const getPatchNotes = cache( async ( version: PatchNotesQuery = { latest: true }, ): Promise< - | { success: true; data: PatchNote } - | { - success: false; - error: PatchNotesError | PatchNoteZodError | VersionManifestZodError; - } + Result< + PatchNote, + PatchNoteZodError | VersionManifestZodError | TypeError | string + > > => { const maybePartialVersion = await getPartialVersion(version); if (!maybePartialVersion.success) return maybePartialVersion; @@ -128,10 +114,7 @@ export const getPatchNotes = cache( const patch = PATCH_NOTE_SCHEMA.safeParse(await patchRes.json()); if (!patch.success) return patch; - return { - success: true, - data: { ...partialVersion, ...patch.data }, - }; + return ok({ ...partialVersion, ...patch.data }); }, ["java", "patch_note"], { revalidate: 2 /* m */ * 60 /* s/m */ }, diff --git a/start-database.sh b/start-database.sh deleted file mode 100644 index b9fd0f6..0000000 --- a/start-database.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/env bash -# Use this script to start a docker container for a local development database - -# TO RUN ON WINDOWS: -# 1. Install WSL (Windows Subsystem for Linux) - https://learn.microsoft.com/en-us/windows/wsl/install -# 2. Install Docker Desktop for Windows - https://docs.docker.com/docker-for-windows/install/ -# 3. Open WSL - `wsl` -# 4. Run this script - `./start-database.sh` - -# On Linux and macOS you can run this script directly - `./start-database.sh` - -DB_CONTAINER_NAME="mcc-tools-postgres" - -if ! [ -x "$(command -v docker)" ]; then - echo -e "Docker is not installed. Please install docker and try again.\nDocker install guide: https://docs.docker.com/engine/install/" - exit 1 -fi - -if [ "$(docker ps -q -f name=$DB_CONTAINER_NAME)" ]; then - echo "Database container '$DB_CONTAINER_NAME' already running" - exit 0 -fi - -if [ "$(docker ps -q -a -f name=$DB_CONTAINER_NAME)" ]; then - docker start "$DB_CONTAINER_NAME" - echo "Existing database container '$DB_CONTAINER_NAME' started" - exit 0 -fi - -# import env variables from .env -set -a -source .env - -DB_PASSWORD=$(echo "$POSTGRES_PRISMA_URL" | awk -F':' '{print $3}' | awk -F'@' '{print $1}') - -if [ "$DB_PASSWORD" = "password" ]; then - echo "You are using the default database password" - read -p "Should we generate a random password for you? [y/N]: " -r REPLY - if ! [[ $REPLY =~ ^[Yy]$ ]]; then - echo "Please set a password in the .env file and try again" - exit 1 - fi - # Generate a random URL-safe password - DB_PASSWORD=$(openssl rand -base64 12 | tr '+/' '-_') - sed -i -e "s#:password@#:$DB_PASSWORD@#" .env -fi - -docker run -d \ - --name $DB_CONTAINER_NAME \ - -e POSTGRES_PASSWORD="$DB_PASSWORD" \ - -e POSTGRES_DB=mcc-tools \ - -p 5432:5432 \ - docker.io/postgres && echo "Database container '$DB_CONTAINER_NAME' was successfully created"