diff --git a/Dockerfile_website b/Dockerfile_website index 823df38e9..194ebfc2a 100644 --- a/Dockerfile_website +++ b/Dockerfile_website @@ -3,7 +3,7 @@ FROM node:24-alpine AS base WORKDIR /app -COPY website/package.json website/package-lock.json website/patches ./ +COPY website/package.json website/package-lock.json ./ FROM base AS prod-deps RUN npm clean-install --omit=dev diff --git a/website/astro.config.mjs b/website/astro.config.mjs index 9c321540f..947bdb7c5 100644 --- a/website/astro.config.mjs +++ b/website/astro.config.mjs @@ -1,12 +1,11 @@ import { defineConfig } from 'astro/config'; import react from '@astrojs/react'; import node from '@astrojs/node'; -import auth from 'auth-astro'; import tailwindcss from '@tailwindcss/vite'; // https://astro.build/config export default defineConfig({ - integrations: [react(), auth({ configFile: './src/auth.config' })], + integrations: [react()], output: 'server', adapter: node({ mode: 'standalone', diff --git a/website/package-lock.json b/website/package-lock.json index 0ed3a17a2..fec4326c8 100644 --- a/website/package-lock.json +++ b/website/package-lock.json @@ -7,19 +7,16 @@ "": { "name": "dashboards", "version": "0.0.1", - "hasInstallScript": true, "dependencies": { "@astrojs/node": "^9.5.3", - "@auth/core": "^0.37.4", "@genspectrum/dashboard-components": "^1.17.0", "@tanstack/react-query": "^5.100.5", "astro": "^5.18.1", - "auth-astro": "^4.2.0", "axios": "^1.15.2", + "better-auth": "^1.6.9", "cookie": "^1.1.1", "dayjs": "^1.11.20", "katex": "^0.16.45", - "patch-package": "^8.0.1", "react": "^19.2.5", "react-dom": "^19.2.5", "react-katex": "^3.1.0", @@ -286,35 +283,6 @@ "yaml": "^2.8.2" } }, - "node_modules/@auth/core": { - "version": "0.37.4", - "resolved": "https://registry.npmjs.org/@auth/core/-/core-0.37.4.tgz", - "integrity": "sha512-HOXJwXWXQRhbBDHlMU0K/6FT1v+wjtzdKhsNg0ZN7/gne6XPsIrjZ4daMcFnbq0Z/vsAbYBinQhhua0d77v7qw==", - "license": "ISC", - "dependencies": { - "@panva/hkdf": "^1.2.1", - "jose": "^5.9.6", - "oauth4webapi": "^3.1.1", - "preact": "10.24.3", - "preact-render-to-string": "6.5.11" - }, - "peerDependencies": { - "@simplewebauthn/browser": "^9.0.1", - "@simplewebauthn/server": "^9.0.2", - "nodemailer": "^6.8.0" - }, - "peerDependenciesMeta": { - "@simplewebauthn/browser": { - "optional": true - }, - "@simplewebauthn/server": { - "optional": true - }, - "nodemailer": { - "optional": true - } - } - }, "node_modules/@babel/code-frame": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", @@ -622,6 +590,147 @@ "node": ">=6.9.0" } }, + "node_modules/@better-auth/core": { + "version": "1.6.9", + "resolved": "https://registry.npmjs.org/@better-auth/core/-/core-1.6.9.tgz", + "integrity": "sha512-ADFk5pwmLybmc+LvYvXJ6M1x2oY/EyYLkwLuH0x28FUq12DfjL0wnE7g+WRDf3yozDO+qIxTpFGXDGwLKbfz0w==", + "license": "MIT", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.39.0", + "@standard-schema/spec": "^1.1.0", + "zod": "^4.3.6" + }, + "peerDependencies": { + "@better-auth/utils": "0.4.0", + "@better-fetch/fetch": "1.1.21", + "@cloudflare/workers-types": ">=4", + "@opentelemetry/api": "^1.9.0", + "better-call": "1.3.5", + "jose": "^6.1.0", + "kysely": "^0.28.5", + "nanostores": "^1.0.1" + }, + "peerDependenciesMeta": { + "@cloudflare/workers-types": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + } + } + }, + "node_modules/@better-auth/core/node_modules/zod": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.1.tgz", + "integrity": "sha512-a6ENMBBGZBsnlSebQ/eKCguSBeGKSf4O7BPnqVPmYGtpBYI7VSqoVqw+QcB7kPRjbqPwhYTpFbVj/RqNz/CT0Q==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/@better-auth/drizzle-adapter": { + "version": "1.6.9", + "resolved": "https://registry.npmjs.org/@better-auth/drizzle-adapter/-/drizzle-adapter-1.6.9.tgz", + "integrity": "sha512-Lcco5hOGrMgc4XKAkvB6x72eQm4wCcya8IevMg4wBHY9W9GVg8pu23rpRX6VsVQSO4Ux13S7lFwUWtF7/r9aKw==", + "license": "MIT", + "peerDependencies": { + "@better-auth/core": "^1.6.9", + "@better-auth/utils": "0.4.0", + "drizzle-orm": "^0.45.2" + }, + "peerDependenciesMeta": { + "drizzle-orm": { + "optional": true + } + } + }, + "node_modules/@better-auth/kysely-adapter": { + "version": "1.6.9", + "resolved": "https://registry.npmjs.org/@better-auth/kysely-adapter/-/kysely-adapter-1.6.9.tgz", + "integrity": "sha512-gyjuuxJtZ4o9G9z9q4kqn24X2kvMSp7F+KHogYxF03SnXY/2WleAcuj57iC4wP3e9mGDbjPOrnM5K6Kr3Ktdpw==", + "license": "MIT", + "peerDependencies": { + "@better-auth/core": "^1.6.9", + "@better-auth/utils": "0.4.0", + "kysely": "^0.28.14" + }, + "peerDependenciesMeta": { + "kysely": { + "optional": true + } + } + }, + "node_modules/@better-auth/memory-adapter": { + "version": "1.6.9", + "resolved": "https://registry.npmjs.org/@better-auth/memory-adapter/-/memory-adapter-1.6.9.tgz", + "integrity": "sha512-XmIG4tUnOXZ+KEcWjHUjOI9Z5donD09dC2t/AQTXifAUIqx7cySg86w0KTM09ArzAxRx1fCqO36Wkt5nULnrkQ==", + "license": "MIT", + "peerDependencies": { + "@better-auth/core": "^1.6.9", + "@better-auth/utils": "0.4.0" + } + }, + "node_modules/@better-auth/mongo-adapter": { + "version": "1.6.9", + "resolved": "https://registry.npmjs.org/@better-auth/mongo-adapter/-/mongo-adapter-1.6.9.tgz", + "integrity": "sha512-h+AiRJ/TsBSi+ZDjySASBpbJ/9QCXBre34PSKgCz7QmTHrFM9Cg2EM4AM7LjR5lPXipEE+2rWPBc9wfnUBjhcw==", + "license": "MIT", + "peerDependencies": { + "@better-auth/core": "^1.6.9", + "@better-auth/utils": "0.4.0", + "mongodb": "^6.0.0 || ^7.0.0" + }, + "peerDependenciesMeta": { + "mongodb": { + "optional": true + } + } + }, + "node_modules/@better-auth/prisma-adapter": { + "version": "1.6.9", + "resolved": "https://registry.npmjs.org/@better-auth/prisma-adapter/-/prisma-adapter-1.6.9.tgz", + "integrity": "sha512-XHks01ntK20orqK/jICq8wmEbJ/zT6dct49Fk8zTQKN9QNGDc+Ix5+7z/Kvui0DXGFf790GfvRozquzaLtXa8Q==", + "license": "MIT", + "peerDependencies": { + "@better-auth/core": "^1.6.9", + "@better-auth/utils": "0.4.0", + "@prisma/client": "^5.0.0 || ^6.0.0 || ^7.0.0", + "prisma": "^5.0.0 || ^6.0.0 || ^7.0.0" + }, + "peerDependenciesMeta": { + "@prisma/client": { + "optional": true + }, + "prisma": { + "optional": true + } + } + }, + "node_modules/@better-auth/telemetry": { + "version": "1.6.9", + "resolved": "https://registry.npmjs.org/@better-auth/telemetry/-/telemetry-1.6.9.tgz", + "integrity": "sha512-0u5zkhSCAQFoN3DHvUkLHOF6MBbVTDAa6mU8mhPwiysdz1x21vMzhzfaAKN/ZGWaQ09v91/F+2qu42G/bhUV4A==", + "license": "MIT", + "peerDependencies": { + "@better-auth/core": "^1.6.9", + "@better-auth/utils": "0.4.0", + "@better-fetch/fetch": "1.1.21" + } + }, + "node_modules/@better-auth/utils": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@better-auth/utils/-/utils-0.4.0.tgz", + "integrity": "sha512-RpMtLUIQAEWMgdPLNVbIF5ON2mm+CH0U3rCdUCU1VyeAUui4m38DyK7/aXMLZov2YDjG684pS1D0MBllrmgjQA==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "^2.0.1" + } + }, + "node_modules/@better-fetch/fetch": { + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/@better-fetch/fetch/-/fetch-1.1.21.tgz", + "integrity": "sha512-/ImESw0sskqlVR94jB+5+Pxjf+xBwDZF/N5+y2/q4EqD7IARUTSpPfIo8uf39SYpCxyOCtbyYpUrZ3F/k0zT4A==" + }, "node_modules/@capsizecss/unpack": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@capsizecss/unpack/-/unpack-4.0.0.tgz", @@ -2146,6 +2255,30 @@ "node": ">=18" } }, + "node_modules/@noble/ciphers": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-2.2.0.tgz", + "integrity": "sha512-Z6pjIZ/8IJcCGzb2S/0Px5J81yij85xASuk1teLNeg75bfT07MV3a/O2Mtn1I2se43k3lkVEcFaR10N4cgQcZA==", + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/hashes": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.2.0.tgz", + "integrity": "sha512-IYqDGiTXab6FniAgnSdZwgWbomxpy9FtYvLKs7wCUs2a8RkITG+DFGO1DM9cr+E3/RgADRpFjrKVaJ1z6sjtEg==", + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -2209,21 +2342,21 @@ "dev": true, "license": "MIT" }, + "node_modules/@opentelemetry/semantic-conventions": { + "version": "1.40.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.40.0.tgz", + "integrity": "sha512-cifvXDhcqMwwTlTK04GBNeIe7yyo28Mfby85QXFe1Yk8nmi36Ab/5UQwptOx84SsoGNRg+EVSjwzfSZMy6pmlw==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, "node_modules/@oslojs/encoding": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@oslojs/encoding/-/encoding-1.1.0.tgz", "integrity": "sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==", "license": "MIT" }, - "node_modules/@panva/hkdf": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@panva/hkdf/-/hkdf-1.2.1.tgz", - "integrity": "sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/panva" - } - }, "node_modules/@pkgr/core": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", @@ -2672,6 +2805,12 @@ "node": ">=18" } }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "license": "MIT" + }, "node_modules/@tailwindcss/node": { "version": "4.2.4", "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.2.4.tgz", @@ -3301,7 +3440,7 @@ "version": "24.5.2", "resolved": "https://registry.npmjs.org/@types/node/-/node-24.5.2.tgz", "integrity": "sha512-FYxk1I7wPv3K2XBaoyH2cTnocQEu8AOZ60hPbsyukMPLv5/5qr7V1i8PLHdl6Zf87I+xZXFvPCXYjiTFq+YSDQ==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "undici-types": "~7.12.0" @@ -3911,12 +4050,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@yarnpkg/lockfile": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", - "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", - "license": "BSD-2-Clause" - }, "node_modules/acorn": { "version": "8.16.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", @@ -4010,6 +4143,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -5007,22 +5141,6 @@ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "license": "MIT" }, - "node_modules/auth-astro": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/auth-astro/-/auth-astro-4.2.0.tgz", - "integrity": "sha512-Jx0dFAvwJ5UJ6E/2J6rqPNhXzTX6Fj18sIq12U7n+J15TV7etpXSHFPPcQdAmfDmX3RCURp253Vxe4l/keNW1g==", - "license": "MIT", - "dependencies": { - "set-cookie-parser": "^2.5.1" - }, - "engines": { - "node": ">=17.4" - }, - "peerDependencies": { - "@auth/core": "^0.37.3", - "astro": ">=4.0.0" - } - }, "node_modules/available-typed-arrays": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", @@ -5082,6 +5200,155 @@ "integrity": "sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==", "license": "MIT" }, + "node_modules/better-auth": { + "version": "1.6.9", + "resolved": "https://registry.npmjs.org/better-auth/-/better-auth-1.6.9.tgz", + "integrity": "sha512-EBFURtglyiEZxbx4NJBoqUD8J65dX24yC+6I9AUbIXNgUkt76mshzGbHkxZ3n/lB7Dwq3kBC+hHt0hUQsnL7HA==", + "license": "MIT", + "dependencies": { + "@better-auth/core": "1.6.9", + "@better-auth/drizzle-adapter": "1.6.9", + "@better-auth/kysely-adapter": "1.6.9", + "@better-auth/memory-adapter": "1.6.9", + "@better-auth/mongo-adapter": "1.6.9", + "@better-auth/prisma-adapter": "1.6.9", + "@better-auth/telemetry": "1.6.9", + "@better-auth/utils": "0.4.0", + "@better-fetch/fetch": "1.1.21", + "@noble/ciphers": "^2.1.1", + "@noble/hashes": "^2.0.1", + "better-call": "1.3.5", + "defu": "^6.1.4", + "jose": "^6.1.3", + "kysely": "^0.28.14", + "nanostores": "^1.1.1", + "zod": "^4.3.6" + }, + "peerDependencies": { + "@lynx-js/react": "*", + "@prisma/client": "^5.0.0 || ^6.0.0 || ^7.0.0", + "@sveltejs/kit": "^2.0.0", + "@tanstack/react-start": "^1.0.0", + "@tanstack/solid-start": "^1.0.0", + "better-sqlite3": "^12.0.0", + "drizzle-kit": ">=0.31.4", + "drizzle-orm": "^0.45.2", + "mongodb": "^6.0.0 || ^7.0.0", + "mysql2": "^3.0.0", + "next": "^14.0.0 || ^15.0.0 || ^16.0.0", + "pg": "^8.0.0", + "prisma": "^5.0.0 || ^6.0.0 || ^7.0.0", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0", + "solid-js": "^1.0.0", + "svelte": "^4.0.0 || ^5.0.0", + "vitest": "^2.0.0 || ^3.0.0 || ^4.0.0", + "vue": "^3.0.0" + }, + "peerDependenciesMeta": { + "@lynx-js/react": { + "optional": true + }, + "@prisma/client": { + "optional": true + }, + "@sveltejs/kit": { + "optional": true + }, + "@tanstack/react-start": { + "optional": true + }, + "@tanstack/solid-start": { + "optional": true + }, + "better-sqlite3": { + "optional": true + }, + "drizzle-kit": { + "optional": true + }, + "drizzle-orm": { + "optional": true + }, + "mongodb": { + "optional": true + }, + "mysql2": { + "optional": true + }, + "next": { + "optional": true + }, + "pg": { + "optional": true + }, + "prisma": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "solid-js": { + "optional": true + }, + "svelte": { + "optional": true + }, + "vitest": { + "optional": true + }, + "vue": { + "optional": true + } + } + }, + "node_modules/better-auth/node_modules/jose": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.3.tgz", + "integrity": "sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/better-auth/node_modules/zod": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.1.tgz", + "integrity": "sha512-a6ENMBBGZBsnlSebQ/eKCguSBeGKSf4O7BPnqVPmYGtpBYI7VSqoVqw+QcB7kPRjbqPwhYTpFbVj/RqNz/CT0Q==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/better-call": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/better-call/-/better-call-1.3.5.tgz", + "integrity": "sha512-kOFJkBP7utAQLEYrobZm3vkTH8mXq5GNgvjc5/XEST1ilVHaxXUXfeDeFlqoETMtyqS4+3/h4ONX2i++ebZrvA==", + "license": "MIT", + "dependencies": { + "@better-auth/utils": "^0.4.0", + "@better-fetch/fetch": "^1.1.21", + "rou3": "^0.7.12", + "set-cookie-parser": "^3.0.1" + }, + "peerDependencies": { + "zod": "^4.0.0" + }, + "peerDependenciesMeta": { + "zod": { + "optional": true + } + } + }, + "node_modules/better-call/node_modules/set-cookie-parser": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-3.1.0.tgz", + "integrity": "sha512-kjnC1DXBHcxaOaOXBHBeRtltsDG2nUiUni+jP92M9gYdW12rsmx92UsfpH7o5tDRs7I1ZZPSQJQGv3UaRfCiuw==", + "license": "MIT" + }, "node_modules/boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", @@ -5149,6 +5416,7 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, "license": "MIT", "dependencies": { "fill-range": "^7.1.1" @@ -5204,6 +5472,7 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.0", @@ -5235,6 +5504,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", @@ -5321,6 +5591,7 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", @@ -5554,6 +5825,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "devOptional": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -5566,6 +5838,7 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "devOptional": true, "license": "MIT" }, "node_modules/color-string": { @@ -5663,6 +5936,7 @@ "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -5986,6 +6260,7 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", @@ -7259,6 +7534,7 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" @@ -7284,15 +7560,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/find-yarn-workspace-root": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz", - "integrity": "sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ==", - "license": "Apache-2.0", - "dependencies": { - "micromatch": "^4.0.2" - } - }, "node_modules/flat-cache": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", @@ -7417,20 +7684,6 @@ "node": ">= 0.8" } }, - "node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/fsevents": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", @@ -7637,6 +7890,7 @@ "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, "license": "ISC" }, "node_modules/graphql": { @@ -7692,6 +7946,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -7701,6 +7956,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, "license": "MIT", "dependencies": { "es-define-property": "^1.0.0" @@ -8367,6 +8623,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.12.0" @@ -8577,12 +8834,14 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, "license": "MIT" }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, "license": "ISC" }, "node_modules/iterator.prototype": { @@ -8607,16 +8866,16 @@ "version": "2.6.1", "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", - "devOptional": true, + "dev": true, "license": "MIT", "bin": { "jiti": "lib/jiti-cli.mjs" } }, "node_modules/jose": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/jose/-/jose-5.10.0.tgz", - "integrity": "sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==", + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.3.tgz", + "integrity": "sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/panva" @@ -8667,25 +8926,6 @@ "dev": true, "license": "MIT" }, - "node_modules/json-stable-stringify": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.2.1.tgz", - "integrity": "sha512-Lp6HbbBgosLmJbjx0pBLbgvx68FaFU1sdkmBuckmhhJ88kL13OA51CDtR2yJB50eCNMH9wRqtQNNiAqQH4YXnA==", - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "isarray": "^2.0.5", - "jsonify": "^0.0.1", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", @@ -8713,27 +8953,6 @@ "dev": true, "license": "MIT" }, - "node_modules/jsonfile": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", - "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", - "license": "MIT", - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/jsonify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.1.tgz", - "integrity": "sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==", - "license": "Public Domain", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/jsx-ast-utils": { "version": "3.3.5", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", @@ -8785,15 +9004,6 @@ "json-buffer": "3.0.1" } }, - "node_modules/klaw-sync": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz", - "integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==", - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.1.11" - } - }, "node_modules/kleur": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", @@ -8810,6 +9020,15 @@ "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==", "license": "MIT" }, + "node_modules/kysely": { + "version": "0.28.16", + "resolved": "https://registry.npmjs.org/kysely/-/kysely-0.28.16.tgz", + "integrity": "sha512-3i5pmOiZvMDj00qhrIVbH0AnioVTx22DMP7Vn5At4yJO46iy+FM8Y/g61ltenLVSo3fiO8h8Q3QOFgf/gQ72ww==", + "license": "MIT", + "engines": { + "node": ">=20.0.0" + } + }, "node_modules/leaflet": { "version": "1.9.4", "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.4.tgz", @@ -8834,7 +9053,7 @@ "version": "1.32.0", "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", - "devOptional": true, + "dev": true, "license": "MPL-2.0", "dependencies": { "detect-libc": "^2.0.3" @@ -8867,6 +9086,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -8887,6 +9107,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -8907,6 +9128,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -8927,6 +9149,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -8947,6 +9170,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -8967,6 +9191,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -8987,6 +9212,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -9007,6 +9233,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -9027,6 +9254,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -9047,6 +9275,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -9067,6 +9296,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -10059,6 +10289,7 @@ "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, "license": "MIT", "dependencies": { "braces": "^3.0.3", @@ -10072,6 +10303,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, "license": "MIT", "engines": { "node": ">=8.6" @@ -10131,6 +10363,7 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -10286,6 +10519,21 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/nanostores": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/nanostores/-/nanostores-1.3.0.tgz", + "integrity": "sha512-XPUa/jz+P1oJvN9VBxw4L9MtdFfaH3DAryqPssqhb2kXjmb9npz0dly6rCsgFWOPr4Yg9mTfM3MDZgZZ+7A3lA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "engines": { + "node": "^20.0.0 || >=22.0.0" + } + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -10355,15 +10603,6 @@ "url": "https://github.com/fb55/nth-check?sponsor=1" } }, - "node_modules/oauth4webapi": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/oauth4webapi/-/oauth4webapi-3.3.0.tgz", - "integrity": "sha512-ZlozhPlFfobzh3hB72gnBFLjXpugl/dljz1fJSRdqaV2r3D5dmi5lg2QWI0LmUYuazmE+b5exsloEv6toUtw9g==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/panva" - } - }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -10399,6 +10638,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -10549,49 +10789,6 @@ "regex-recursion": "^6.0.2" } }, - "node_modules/open": { - "version": "7.4.2", - "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", - "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", - "license": "MIT", - "dependencies": { - "is-docker": "^2.0.0", - "is-wsl": "^2.1.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/open/node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "license": "MIT", - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/open/node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "license": "MIT", - "dependencies": { - "is-docker": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -10784,50 +10981,6 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/patch-package": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/patch-package/-/patch-package-8.0.1.tgz", - "integrity": "sha512-VsKRIA8f5uqHQ7NGhwIna6Bx6D9s/1iXlA1hthBVBEbkq+t4kXD0HHt+rJhf/Z+Ci0F/HCB2hvn0qLdLG+Qxlw==", - "license": "MIT", - "dependencies": { - "@yarnpkg/lockfile": "^1.1.0", - "chalk": "^4.1.2", - "ci-info": "^3.7.0", - "cross-spawn": "^7.0.3", - "find-yarn-workspace-root": "^2.0.0", - "fs-extra": "^10.0.0", - "json-stable-stringify": "^1.0.2", - "klaw-sync": "^6.0.0", - "minimist": "^1.2.6", - "open": "^7.4.2", - "semver": "^7.5.3", - "slash": "^2.0.0", - "tmp": "^0.2.4", - "yaml": "^2.2.2" - }, - "bin": { - "patch-package": "index.js" - }, - "engines": { - "node": ">=14", - "npm": ">5" - } - }, - "node_modules/patch-package/node_modules/ci-info": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", - "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/path-browserify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", @@ -10849,6 +11002,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -11015,15 +11169,6 @@ "url": "https://opencollective.com/preact" } }, - "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/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -11782,6 +11927,12 @@ "fsevents": "~2.3.2" } }, + "node_modules/rou3": { + "version": "0.7.12", + "resolved": "https://registry.npmjs.org/rou3/-/rou3-0.7.12.tgz", + "integrity": "sha512-iFE4hLDuloSWcD7mjdCDhx2bKcIsYbtOTpfH5MHHLSKMOUyjqQXTeZVa289uuwEGEKFoE/BAPbhaU4B774nceg==", + "license": "MIT" + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -11991,16 +12142,11 @@ "integrity": "sha512-rb+9B5YBIEzYcD6x2VKidaa+cqYBJQKnU4oe4E3ANwRRN56yk/ua1YCJT1n21NTS8w6CcOclAKNP3PhdCXKYtQ==", "license": "ISC" }, - "node_modules/set-cookie-parser": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", - "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==", - "license": "MIT" - }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", @@ -12098,6 +12244,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -12110,6 +12257,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -12258,15 +12406,6 @@ "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", "license": "MIT" }, - "node_modules/slash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/smol-toml": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.6.1.tgz", @@ -12586,6 +12725,7 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -12784,19 +12924,11 @@ "dev": true, "license": "MIT" }, - "node_modules/tmp": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz", - "integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==", - "license": "MIT", - "engines": { - "node": ">=14.14" - } - }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, "license": "MIT", "dependencies": { "is-number": "^7.0.0" @@ -13059,6 +13191,7 @@ "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -13143,7 +13276,7 @@ "version": "7.12.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.12.0.tgz", "integrity": "sha512-goOacqME2GYyOZZfb5Lgtu+1IDmAlAEu5xnD3+xTzS10hT0vzpf0SPjkXwAw9Jm+4n/mQGDP3LO8CPbYROeBfQ==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/unified": { @@ -13299,15 +13432,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "license": "MIT", - "engines": { - "node": ">= 10.0.0" - } - }, "node_modules/until-async": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/until-async/-/until-async-3.0.2.tgz", @@ -13921,6 +14045,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" diff --git a/website/package.json b/website/package.json index 676792286..4c778354f 100644 --- a/website/package.json +++ b/website/package.json @@ -14,7 +14,6 @@ "check-types": "astro sync && tsc --noEmit", "check-astro": "astro check", "check-lint": "eslint .", - "postinstall": "patch-package", "test": "vitest", "test:node": "vitest --project node", "test:headed": "vitest --browser.headless false", @@ -26,16 +25,14 @@ }, "dependencies": { "@astrojs/node": "^9.5.3", - "@auth/core": "^0.37.4", "@genspectrum/dashboard-components": "^1.17.0", "@tanstack/react-query": "^5.100.5", "astro": "^5.18.1", - "auth-astro": "^4.2.0", "axios": "^1.15.2", + "better-auth": "^1.6.9", "cookie": "^1.1.1", "dayjs": "^1.11.20", "katex": "^0.16.45", - "patch-package": "^8.0.1", "react": "^19.2.5", "react-dom": "^19.2.5", "react-katex": "^3.1.0", diff --git a/website/patches/auth-astro+4.2.0.patch b/website/patches/auth-astro+4.2.0.patch deleted file mode 100644 index 1e24bd246..000000000 --- a/website/patches/auth-astro+4.2.0.patch +++ /dev/null @@ -1,78 +0,0 @@ -diff --git a/node_modules/auth-astro/client.ts b/node_modules/auth-astro/client.ts -index 8a30c9e..d853a86 100644 ---- a/node_modules/auth-astro/client.ts -+++ b/node_modules/auth-astro/client.ts -@@ -1,11 +1,43 @@ --import type { -- LiteralUnion, -- SignInOptions, -- SignInAuthorizationParams, -- SignOutParams, --} from 'next-auth/react' - import type { BuiltInProviderType, RedirectableProviderType } from '@auth/core/providers' - -+// manually imported from next-auth/react to get the proper type without installing the dependency ourselves -+// from https://github.com/nextauthjs/next-auth/blob/9411046efb21f83218df4d7d7da6639e100adb2a/packages/next-auth/src/lib/client.ts -+export interface SignInOptions -+ extends Record { -+ /** @deprecated Use `redirectTo` instead. */ -+ callbackUrl?: string -+ /** -+ * Specify where the user should be redirected to after a successful signin. -+ * -+ * By default, it is the page the sign-in was initiated from. -+ */ -+ redirectTo?: string -+ /** -+ * You might want to deal with the signin response on the same page, instead of redirecting to another page. -+ * For example, if an error occurs (like wrong credentials given by the user), you might want to show an inline error message on the input field. -+ * -+ * For this purpose, you can set this to option `redirect: false`. -+ */ -+ redirect?: Redirect -+} -+export interface SignOutParams { -+ /** @deprecated Use `redirectTo` instead. */ -+ callbackUrl?: string -+ /** -+ * If you pass `redirect: false`, the page will not reload. -+ * The session will be deleted, and `useSession` is notified, so any indication about the user will be shown as logged out automatically. -+ * It can give a very nice experience for the user. -+ */ -+ redirectTo?: string -+ /** [Documentation](https://next-auth.js.org/getting-started/client#using-the-redirect-false-option-1 */ -+ redirect?: Redirect -+} -+export type SignInAuthorizationParams = -+ | string -+ | string[][] -+ | Record -+ | URLSearchParams -+ - interface AstroSignInOptions extends SignInOptions { - /** The base path for authentication (default: /api/auth) */ - prefix?: string -@@ -24,9 +56,7 @@ interface AstroSignOutParams extends SignOutParams { - * [Documentation](https://authjs.dev/reference/utilities/#signin) - */ - export async function signIn

( -- providerId?: LiteralUnion< -- P extends RedirectableProviderType ? P | BuiltInProviderType : BuiltInProviderType -- >, -+ providerId?: BuiltInProviderType, - options?: AstroSignInOptions, - authorizationParams?: SignInAuthorizationParams - ) { -diff --git a/node_modules/auth-astro/src/integration.ts b/node_modules/auth-astro/src/integration.ts -index 04262ae..5b19bc6 100644 ---- a/node_modules/auth-astro/src/integration.ts -+++ b/node_modules/auth-astro/src/integration.ts -@@ -34,7 +34,7 @@ export default (config: AstroAuthConfig = {}): AstroIntegration => ({ - logger.error('No Adapter found, please make sure you provide one in your Astro config') - } - const edge = ['@astrojs/vercel/edge', '@astrojs/cloudflare'].includes( -- astroConfig.adapter.name -+ astroConfig.adapter!.name - ) - - if ( diff --git a/website/src/auth.config.mjs b/website/src/auth.config.mjs deleted file mode 100644 index 49ca9c167..000000000 --- a/website/src/auth.config.mjs +++ /dev/null @@ -1,32 +0,0 @@ -import GitHub from '@auth/core/providers/github'; -import { defineConfig } from 'auth-astro'; - -import { getGitHubClientId, getGitHubClientSecret } from './config'; - -export default defineConfig({ - secret: process.env.AUTH_SECRET, - callbacks: { - session: async ({ session, token }) => { - session.user.id = token.userIdFromProvider; - return session; - }, - jwt: ({ profile, token }) => { - if (!profile) { - return token; - } - - // This step in necessary, since @auth/core overwrites the id from the provider with a random UUID - // The id is then extracted in the session callback and assigned to the user object - return { - ...token, - userIdFromProvider: profile.id, - }; - }, - }, - providers: [ - GitHub({ - clientId: getGitHubClientId(), - clientSecret: getGitHubClientSecret(), - }), - ], -}); diff --git a/website/src/auth.ts b/website/src/auth.ts new file mode 100644 index 000000000..83f1d0a86 --- /dev/null +++ b/website/src/auth.ts @@ -0,0 +1,38 @@ +import { betterAuth } from 'better-auth'; + +import { getGitHubClientId, getGitHubClientSecret } from './config'; + +export const auth = betterAuth({ + // TODO - maybe we can check again if this is read automatically? Should be, according to the docs. + secret: process.env.AUTH_SECRET, + session: { + cookieCache: { + enabled: true, + maxAge: 60 * 60, + strategy: 'jwe', + }, + }, + user: { + additionalFields: { + githubId: { + type: 'string', + input: false, + }, + }, + }, + socialProviders: { + github: { + clientId: getGitHubClientId(), + clientSecret: getGitHubClientSecret(), + // store the GitHub user ID (i.e. 45882389) in the 'user' object, + // which is easy to access from context later on. + // the 'id' property cannot be overwritten. + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-conversion -- profile.id is typed as string but GitHub returns a number at runtime; String() ensures it's always stored as a string for consistent ownership checks + mapProfileToUser: (profile) => ({ githubId: String(profile.id) }), + }, + }, + advanced: { + trustedProxyHeaders: true, + cookiePrefix: 'gen-spectrum', + }, +}); diff --git a/website/src/auth/logout.ts b/website/src/auth/logout.ts index 2796b3d46..5e08da10e 100644 --- a/website/src/auth/logout.ts +++ b/website/src/auth/logout.ts @@ -1,11 +1,5 @@ -import { Auth, raw, skipCSRFCheck } from '@auth/core'; -import type { ResponseInternal } from '@auth/core/types'; -import authConfig from 'auth:config'; - -export type LogoutResponse = Required>; +import { auth } from '../auth'; export async function logout(request: Request) { - const url = new URL(`${authConfig.prefix}/signout`, request.url); - const authRequest = new Request(url, { headers: request.headers, method: 'POST' }); - return (await Auth(authRequest, { ...authConfig, raw, skipCSRFCheck })) as LogoutResponse; + return auth.api.signOut({ headers: request.headers, asResponse: true }); } diff --git a/website/src/backendApi/backendProxy.ts b/website/src/backendApi/backendProxy.ts index 0cb6ab975..c6ec6923f 100644 --- a/website/src/backendApi/backendProxy.ts +++ b/website/src/backendApi/backendProxy.ts @@ -1,4 +1,4 @@ -import { getSession } from 'auth-astro/server'; +import type { APIContext } from 'astro'; import { getBackendHost } from '../config.ts'; import { getInstanceLogger } from '../logger.ts'; @@ -14,21 +14,21 @@ const API_PATHNAME_LENGTH = '/api'.length; * This proxying through the frontend server is used, so we do the user login handling * in here, instead of in the backend. */ -export async function proxyToBackend({ request }: { request: Request }): Promise { - const session = await getSession(request); +export async function proxyToBackend(context: APIContext): Promise { + const userId = context.locals.user?.githubId; - if (session?.user?.id === undefined) { - return getUnauthorizedResponse(request.url); + if (userId === undefined) { + return getUnauthorizedResponse(context.request.url); } - return proxyRequest(request, session.user.id); + return proxyRequest(context.request, userId); } /** * Proxies the request to the backend without any user ID, regardless of login state. */ -export async function proxyToBackendNoAuth({ request }: { request: Request }): Promise { - return proxyRequest(request, undefined); +export async function proxyToBackendNoAuth(context: APIContext): Promise { + return proxyRequest(context.request, undefined); } async function proxyRequest(request: Request, userId: string | undefined): Promise { diff --git a/website/src/components/auth/LoginButton.tsx b/website/src/components/auth/LoginButton.tsx index be35bb329..542849c44 100644 --- a/website/src/components/auth/LoginButton.tsx +++ b/website/src/components/auth/LoginButton.tsx @@ -1,10 +1,11 @@ -import { signIn } from 'auth-astro/client'; +import { createAuthClient } from 'better-auth/client'; import { getClientLogger } from '../../clientLogger.ts'; import { getErrorLogMessage } from '../../util/getErrorLogMessage.ts'; import { useErrorToast } from '../ErrorReportInstruction.tsx'; const logger = getClientLogger('LoginButton'); +const authClient = createAuthClient(); export function LoginButton() { const { showErrorToast } = useErrorToast(logger); @@ -13,13 +14,18 @@ export function LoginButton() { const callbackUrlThatDoesNotImmediatelyLogoutAgain = new URL(window.location.href).pathname.endsWith('/logout') ? new URL('/', window.location.href).toString() : undefined; - signIn('github', { callbackUrl: callbackUrlThatDoesNotImmediatelyLogoutAgain }).catch((error: unknown) => { - showErrorToast({ - error: error instanceof Error ? error : new Error(String(error)), - logMessage: `Login failed: ${getErrorLogMessage(error)}`, - errorToastMessages: ['Login failed. Please try again.'], + authClient.signIn + .social({ + provider: 'github', + callbackURL: callbackUrlThatDoesNotImmediatelyLogoutAgain, + }) + .catch((error: unknown) => { + showErrorToast({ + error: error instanceof Error ? error : new Error(String(error)), + logMessage: `Login failed: ${getErrorLogMessage(error)}`, + errorToastMessages: ['Login failed. Please try again.'], + }); }); - }); }; return ( diff --git a/website/src/components/auth/LoginState.astro b/website/src/components/auth/LoginState.astro index eabed68c2..992c4a6c6 100644 --- a/website/src/components/auth/LoginState.astro +++ b/website/src/components/auth/LoginState.astro @@ -1,6 +1,4 @@ --- -import { getSession } from 'auth-astro/server'; - import { LoginButton } from './LoginButton'; import UserDropdown from './UserDropdown.astro'; @@ -10,13 +8,13 @@ interface Props { const { forceLoggedOutState = false } = Astro.props; -const session = await getSession(Astro.request); -const showLoggedInState = !forceLoggedOutState && session?.user !== undefined; +const user = Astro.locals.user; +const showLoggedInState = !forceLoggedOutState && user !== null; --- { - showLoggedInState ? ( - + showLoggedInState && user ? ( + ) : (

diff --git a/website/src/components/auth/UserDropdown.astro b/website/src/components/auth/UserDropdown.astro index 7722d01ee..3b27971f0 100644 --- a/website/src/components/auth/UserDropdown.astro +++ b/website/src/components/auth/UserDropdown.astro @@ -1,10 +1,8 @@ --- -import type { Session } from '@auth/core/types'; - import { isStaging } from '../../config'; interface Props { - session: Session; + session: { user: { name: string | null } }; } const { session } = Astro.props; diff --git a/website/src/env.d.ts b/website/src/env.d.ts index 48c2d463e..c104ca02b 100644 --- a/website/src/env.d.ts +++ b/website/src/env.d.ts @@ -1,8 +1,16 @@ /// /// -// declare module 'set-cookie-parser' is added, because tsc checks our dependency auth-astro/server, -// which uses set-cookie-parser, and it doesn't have types. -declare module 'set-cookie-parser'; + +declare namespace App { + // Note: 'import {} from ""' syntax does not work in .d.ts files. + // We derive the User type from the auth config so that additionalFields (e.g. githubId) are included. + type AuthUser = NonNullable>>['user']; + + interface Locals { + user: AuthUser | null; + session: import('better-auth').Session | null; + } +} interface ImportMetaEnv { // eslint-disable-next-line @typescript-eslint/naming-convention diff --git a/website/src/layouts/base/header/HamburgerMenu.astro b/website/src/layouts/base/header/HamburgerMenu.astro index 25333f21a..b814e76cd 100644 --- a/website/src/layouts/base/header/HamburgerMenu.astro +++ b/website/src/layouts/base/header/HamburgerMenu.astro @@ -1,6 +1,4 @@ --- -import { getSession } from 'auth-astro/server'; - import HamburgerMenuItem from './HamburgerMenuItem.astro'; import HamburgerMenuSection from './HamburgerMenuSection.astro'; import { getPathogenMegaMenuSections } from './getPathogenMegaMenuSections'; @@ -16,8 +14,7 @@ const { forceLoggedOutState } = Astro.props; const pathogenMegaMenuSections = Object.values(getPathogenMegaMenuSections()); -const session = await getSession(Astro.request); -const showLoggedInState = !forceLoggedOutState && session?.user !== undefined; +const showLoggedInState = !forceLoggedOutState && Astro.locals.user !== null; const showSubscriptions = isStaging(); --- @@ -44,7 +41,7 @@ const showSubscriptions = isStaging(); showLoggedInState ? ( { + const session = await auth.api.getSession({ headers: context.request.headers }); + + if (session) { + context.locals.user = session.user; + context.locals.session = session.session; + } else { + context.locals.user = null; + context.locals.session = null; + } + + return next(); +}); diff --git a/website/src/pages/api/auth/[...all].ts b/website/src/pages/api/auth/[...all].ts new file mode 100644 index 000000000..27c01830c --- /dev/null +++ b/website/src/pages/api/auth/[...all].ts @@ -0,0 +1,5 @@ +import type { APIRoute } from 'astro'; + +import { auth } from '../../../auth'; + +export const ALL: APIRoute = ({ request }) => auth.handler(request); diff --git a/website/src/pages/collections/[organism]/[id]/edit.astro b/website/src/pages/collections/[organism]/[id]/edit.astro index 89a8b903b..f981da0d2 100644 --- a/website/src/pages/collections/[organism]/[id]/edit.astro +++ b/website/src/pages/collections/[organism]/[id]/edit.astro @@ -1,6 +1,4 @@ --- -import { getSession } from 'auth-astro/server'; - import { BackendError, BackendService } from '../../../../backendApi/backendService.ts'; import NotLoggedIn from '../../../../components/auth/NotLoggedIn.astro'; import { CollectionEdit } from '../../../../components/collections/edit/CollectionEdit'; @@ -26,14 +24,14 @@ if (id === undefined) { } const orgConfig = organismConfig[parsedOrganism.data]; -const session = await getSession(Astro.request); +const currentUserId = Astro.locals.user?.githubId; const config = getDashboardsConfig(); let collection; -if (session?.user?.id !== undefined) { +if (currentUserId !== undefined) { try { collection = await new BackendService(getBackendHost()).getCollection({ id }); - if (String(session.user.id) !== collection.ownedBy) { + if (currentUserId !== collection.ownedBy) { return Astro.redirect('/404'); } } catch (error) { @@ -59,7 +57,7 @@ const collectionTitle = collection !== undefined ? `#${id} ${collection.name}` : ]} > { - session?.user?.id !== undefined ? ( + currentUserId !== undefined ? ( { - session?.user?.id !== undefined ? ( + Astro.locals.user !== null ? ( ) : ( diff --git a/website/src/pages/collections/[organism]/index.astro b/website/src/pages/collections/[organism]/index.astro index 7357ef53d..bb98bb7ba 100644 --- a/website/src/pages/collections/[organism]/index.astro +++ b/website/src/pages/collections/[organism]/index.astro @@ -1,6 +1,4 @@ --- -import { getSession } from 'auth-astro/server'; - import { CollectionsOverview } from '../../../components/collections/overview/CollectionsOverview'; import { isStaging } from '../../../config'; import { defaultBreadcrumbs } from '../../../layouts/Breadcrumbs'; @@ -21,8 +19,7 @@ if (!parsedOrganism.success) { } const orgConfig = organismConfig[parsedOrganism.data]; -const session = await getSession(Astro.request); -const isLoggedIn = session?.user?.id !== undefined; +const isLoggedIn = Astro.locals.user !== null; --- - {session?.user?.id !== undefined ? : } + {Astro.locals.user !== null ? : } diff --git a/website/src/pages/subscriptions/index.astro b/website/src/pages/subscriptions/index.astro index 38947dcd8..19c7a7e62 100644 --- a/website/src/pages/subscriptions/index.astro +++ b/website/src/pages/subscriptions/index.astro @@ -1,6 +1,4 @@ --- -import { getSession } from 'auth-astro/server'; - import NotLoggedIn from '../../components/auth/NotLoggedIn.astro'; import { Subscriptions } from '../../components/subscriptions/overview/Subscriptions'; import { defaultBreadcrumbs } from '../../layouts/Breadcrumbs'; @@ -8,8 +6,6 @@ import SubscriptionPageLayout from '../../layouts/ContaineredPage/ContaineredPag import { organismsSchema } from '../../types/Organism'; import { Page } from '../../types/pages'; -const session = await getSession(Astro.request); - const organisms = organismsSchema.parse(Astro.url.searchParams.getAll('organism')); const breadcrumbs = [ @@ -22,5 +18,5 @@ const breadcrumbs = [ --- - {session?.user?.id !== undefined ? : } + {Astro.locals.user !== null ? : } diff --git a/website/tests/collections/collectionForm.spec.ts b/website/tests/collections/collectionForm.spec.ts index 39c2c73c9..386bdffa0 100644 --- a/website/tests/collections/collectionForm.spec.ts +++ b/website/tests/collections/collectionForm.spec.ts @@ -1,9 +1,10 @@ import { expect } from '@playwright/test'; import { test } from '../e2e.fixture.ts'; +import { E2E_GITHUB_ID } from '../helpers/auth.ts'; const BACKEND_URL = process.env.BACKEND_URL ?? 'http://localhost:8080'; -const USER_ID = 'e2e-test'; +const USER_ID = E2E_GITHUB_ID; const ORGANISM = 'covid'; const SEED_COLLECTION = { diff --git a/website/tests/helpers/auth.ts b/website/tests/helpers/auth.ts index b053d2704..95db5f140 100644 --- a/website/tests/helpers/auth.ts +++ b/website/tests/helpers/auth.ts @@ -1,28 +1,83 @@ -import { encode } from '@auth/core/jwt'; -import { type Page } from '@playwright/test'; +import type { Cookie, Page } from '@playwright/test'; +import { makeSignature, symmetricEncodeJWT } from 'better-auth/crypto'; -const COOKIE_NAME = 'authjs.session-token'; +// NOTE: for getSession to use the session_data cookie (bypassing the in-memory store lookup), +// cookieCache must be enabled in auth.ts: +// session: { cookieCache: { enabled: true, maxAge: 60 * 60, strategy: 'jwe' } } -export async function setupAuthCookie(page: Page, userId: string) { - const authSecret = process.env.AUTH_SECRET; - if (authSecret === undefined) { - throw new Error('AUTH_SECRET environment variable is not set'); - } +export const E2E_GITHUB_ID = '1234567'; - const token = await encode({ - token: { userIdFromProvider: userId, name: userId }, - secret: authSecret, - salt: COOKIE_NAME, - }); +const SECRET = process.env.AUTH_SECRET ?? ''; +const COOKIE_PREFIX = 'gen-spectrum'; +const DOMAIN = 'localhost'; - await page.context().addCookies([ +const COOKIE_BASE = { + domain: DOMAIN, + path: '/', + httpOnly: true, + secure: false, + sameSite: 'Lax' as const, + expires: -1, +}; + +export async function createAuthCookies( + accountPayload: Record, + sessionPayload: Record, +): Promise { + const token = crypto.randomUUID(); + const signedToken = `${token}.${await makeSignature(token, SECRET)}`; + const accountData = await symmetricEncodeJWT(accountPayload, SECRET, 'better-auth-account'); + const sessionData = await symmetricEncodeJWT(sessionPayload, SECRET, 'better-auth-session'); + + return [ + { ...COOKIE_BASE, name: `${COOKIE_PREFIX}.session_token`, value: signedToken }, + { ...COOKIE_BASE, name: `${COOKIE_PREFIX}.account_data`, value: accountData }, + { ...COOKIE_BASE, name: `${COOKIE_PREFIX}.session_data`, value: sessionData }, + ]; +} + +export async function setupAuthCookie(page: Page, name: string): Promise { + const now = new Date(); + const expiresAt = new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000); + const userId = crypto.randomUUID(); + const sessionToken = crypto.randomUUID(); + + const cookies = await createAuthCookies( + { + id: crypto.randomUUID(), + providerId: 'github', + accountId: '1234567', + userId, + accessToken: 'e2e-test-access-token', + scope: 'read:user,user:email', + createdAt: now.toISOString(), + updatedAt: now.toISOString(), + }, { - name: COOKIE_NAME, - value: token, - domain: 'localhost', - path: '/', - httpOnly: true, - sameSite: 'Lax', + session: { + id: crypto.randomUUID(), + userId, + token: sessionToken, + expiresAt: expiresAt.toISOString(), + createdAt: now.toISOString(), + updatedAt: now.toISOString(), + ipAddress: null, + userAgent: null, + }, + user: { + id: userId, + name, + email: 'e2e@test.local', + emailVerified: true, + image: null, + createdAt: now.toISOString(), + updatedAt: now.toISOString(), + githubId: '1234567', + }, + updatedAt: now.getTime(), + version: '1', }, - ]); + ); + + await page.context().addCookies(cookies); }