Fix: Add testing

This commit is contained in:
Aron Malcher 2024-03-01 20:50:11 +01:00
parent d022d9fcf6
commit ed6195e1e2
Signed by: aronmal
GPG key ID: 816B7707426FC612
22 changed files with 338 additions and 87 deletions

27
.github/workflows/playwright.yml vendored Normal file
View file

@ -0,0 +1,27 @@
name: Playwright Tests
on:
push:
branches: [main, master]
pull_request:
branches: [main, master]
jobs:
test:
timeout-minutes: 60
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 18
- name: Install dependencies
run: npm install -g pnpm && pnpm install
- name: Install Playwright Browsers
run: pnpm exec playwright install --with-deps
- name: Run Playwright tests
run: pnpm exec playwright test
- uses: actions/upload-artifact@v3
if: always()
with:
name: playwright-report
path: playwright-report/
retention-days: 30

6
.gitignore vendored
View file

@ -27,3 +27,9 @@ gitignore
# System Files
.DS_Store
Thumbs.db
# Playwright
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/

View file

@ -49,7 +49,7 @@ To get started with li'l Judd, follow the instructions below.
VITE_DISCORD_CLIENT_ID=your_discord_client_id
VITE_DISCORD_CLIENT_SECRET=your_discord_client_secret
VITE_DISCORD_BOT_TOKEN=your_discord_bot_token
VITE_DISCORD_BOT_PERMISSIONS=18977581952080
VITE_DISCORD_OAUTH2_PERMISSIONS=18977581952080
VITE_AUTH_SECRET=your_auth_secret

View file

@ -3,6 +3,11 @@ Authorization: Bearer {{$dotenv DISCORD_ACCESS_TOKEN}}
###
GET https://discord.com/api/users/@me
Authorization: Bot {{$dotenv DISCORD_BOT_TOKEN}}
###
GET https://discord.com/api/users/@me/guilds
Authorization: Bearer {{$dotenv DISCORD_ACCESS_TOKEN}}

122
e2e/auth.spec.ts Normal file
View file

@ -0,0 +1,122 @@
import { createId } from "@paralleldrive/cuid2";
import { expect, test, type BrowserContext, type Page } from "@playwright/test";
import { Lucia, type Cookie } from "lucia";
import createClient from "openapi-fetch";
import * as schema from "~/drizzle/schema";
import { paths } from "~/types/discord";
import { DrizzlePostgreSQLAdapter } from "@lucia-auth/adapter-drizzle";
import "dotenv/config";
import { drizzle } from "drizzle-orm/postgres-js";
import postgres from "postgres";
const queryClient = postgres(process.env.DATABASE_URL!);
const db = drizzle(queryClient, {
schema,
});
const adapter = new DrizzlePostgreSQLAdapter(db, schema.sessions, schema.users);
export const lucia = new Lucia(adapter, {
getUserAttributes: (attributes) => attributes,
});
let context: BrowserContext;
let page: Page;
let sessionCookie: Cookie | undefined;
test.describe.serial("User auth process", () => {
test.beforeAll(async ({ browser }) => {
context = await browser.newContext();
page = await context.newPage();
});
test.beforeEach(async () => {
if (!sessionCookie) return;
const sameSiteProps = {
lax: "Lax",
strict: "Strict",
none: "None",
} as const;
const expires = sessionCookie.attributes.expires
? sessionCookie.attributes.expires.getTime() / 1000
: undefined;
const sameSite = sessionCookie.attributes.sameSite
? sameSiteProps[sessionCookie.attributes.sameSite]
: undefined;
await context.addCookies([
{
name: sessionCookie.name,
value: sessionCookie.value,
...sessionCookie.attributes,
sameSite,
expires,
secure: false,
domain: "localhost",
path: "/",
},
]);
});
test.afterAll(async () => {
await context.close();
});
test("Landing page", async () => {
await page.goto("/");
await page.waitForLoadState("load");
expect(await page.screenshot()).toMatchSnapshot("landing_page.png");
});
test("Unauthorized Access Redirect Test", async () => {
await page.goto("/config");
await page.waitForURL("/");
});
test("Generate auth session for further tests", async () => {
const { GET } = createClient<paths>({
baseUrl: "https://discord.com/api/v10",
});
const discordUserResponse = await GET("/users/@me", {
headers: {
Authorization: `Bot ${process.env.DISCORD_BOT_TOKEN}`,
},
});
if (discordUserResponse.error) throw discordUserResponse.error;
const discordUser = discordUserResponse.data;
const userId = createId();
await db.insert(schema.users).values({
id: userId,
discord_id: discordUser.id,
name: discordUser.global_name,
image: discordUser.avatar,
});
const session = await lucia.createSession(
userId,
{},
{ sessionId: createId() },
);
sessionCookie = lucia.createSessionCookie(session.id);
await db
.insert(schema.discordTokens)
.values({
userId,
accessToken: "tokens.accessToken",
expiresAt: sessionCookie.attributes.expires ?? new Date(),
refreshToken: "tokens.refreshToken",
})
.returning()
.execute();
});
test("Landing page when logged in", async () => {
await page.goto("/");
await page.waitForLoadState("load");
expect(await page.screenshot()).toMatchSnapshot(
"landing_page_logged_in.png",
);
});
});

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 328 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 331 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 716 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 710 KiB

View file

@ -10,7 +10,9 @@
"discord-openapi-gen": "openapi-typescript https://raw.githubusercontent.com/discord/discord-api-spec/main/specs/openapi.json -o ./src/types/discord.d.ts",
"liljudd-openapi-gen": "openapi-typescript ./public/api/specs/liljudd.json -o ./src/types/liljudd.d.ts",
"typecheck": "tsc --noEmit --checkJs false --skipLibCheck --preserveSymLinks",
"drizzle-studio": "drizzle-kit studio"
"drizzle-studio": "drizzle-kit studio",
"test": "pnpm exec playwright test",
"test-ui": "pnpm exec playwright test --ui"
},
"dependencies": {
"@fortawesome/fontawesome-svg-core": "^6.5.1",
@ -38,7 +40,9 @@
"vinxi": "^0.3.4"
},
"devDependencies": {
"@playwright/test": "^1.42.0",
"@types/json-stable-stringify": "^1.0.36",
"@types/node": "^20.11.22",
"@types/object-hash": "^3.0.6",
"@typescript-eslint/eslint-plugin": "^7.1.0",
"dotenv": "^16.4.5",

77
playwright.config.ts Normal file
View file

@ -0,0 +1,77 @@
import { defineConfig, devices } from "@playwright/test";
/**
* Read environment variables from file.
* https://github.com/motdotla/dotenv
*/
// require('dotenv').config();
/**
* See https://playwright.dev/docs/test-configuration.
*/
export default defineConfig({
testDir: "./e2e",
/* Run tests in files in parallel */
fullyParallel: true,
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: !!process.env.CI,
/* Retry on CI only */
retries: process.env.CI ? 2 : 0,
/* Opt out of parallel tests on CI. */
workers: process.env.CI ? 1 : undefined,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: "html",
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
/* Base URL to use in actions like `await page.goto('/')`. */
baseURL: "http://localhost:3000",
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: "on-first-retry",
},
/* Configure projects for major browsers */
projects: [
{
name: "chromium",
use: { ...devices["Desktop Chrome"] },
},
{
name: "firefox",
use: { ...devices["Desktop Firefox"] },
},
{
name: "webkit",
use: { ...devices["Desktop Safari"] },
},
/* Test against mobile viewports. */
// {
// name: 'Mobile Chrome',
// use: { ...devices['Pixel 5'] },
// },
// {
// name: 'Mobile Safari',
// use: { ...devices['iPhone 12'] },
// },
/* Test against branded browsers. */
// {
// name: 'Microsoft Edge',
// use: { ...devices['Desktop Edge'], channel: 'msedge' },
// },
// {
// name: 'Google Chrome',
// use: { ...devices['Desktop Chrome'], channel: 'chrome' },
// },
],
/* Run your local dev server before starting the tests */
webServer: {
command: "pnpm start",
url: "http://localhost:3000",
reuseExistingServer: !process.env.CI,
},
});

View file

@ -73,12 +73,18 @@ dependencies:
version: 1.8.15
vinxi:
specifier: ^0.3.4
version: 0.3.4(preact@10.19.6)(sass@1.71.1)
version: 0.3.4(@types/node@20.11.22)(preact@10.19.6)(sass@1.71.1)
devDependencies:
'@playwright/test':
specifier: ^1.42.0
version: 1.42.0
'@types/json-stable-stringify':
specifier: ^1.0.36
version: 1.0.36
'@types/node':
specifier: ^20.11.22
version: 20.11.22
'@types/object-hash':
specifier: ^3.0.6
version: 3.0.6
@ -316,7 +322,6 @@ packages:
/@babel/parser@7.24.0:
resolution: {integrity: sha512-QuP/FxEAzMSjXygs8v4N9dvdXzEHN4W1oF3PxuWAtPo08UdM17u89RDMgjLn/mlc56iM0HlLmVkO/wgR+rDgHg==}
engines: {node: '>=6.0.0'}
hasBin: true
dependencies:
'@babel/types': 7.24.0
dev: false
@ -988,7 +993,6 @@ packages:
/@mapbox/node-pre-gyp@1.0.11:
resolution: {integrity: sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==}
hasBin: true
dependencies:
detect-libc: 2.0.2
https-proxy-agent: 5.0.1
@ -1508,6 +1512,13 @@ packages:
'@parcel/watcher-win32-x64': 2.4.1
dev: false
/@playwright/test@1.42.0:
resolution: {integrity: sha512-2k1HzC28Fs+HiwbJOQDUwrWMttqSLUVdjCqitBOjdCD0svWOMQUVqrXX6iFD7POps6xXAojsX/dGBpKnjZctLA==}
engines: {node: '>=16'}
dependencies:
playwright: 1.42.0
dev: true
/@polka/url@1.0.0-next.24:
resolution: {integrity: sha512-2LuNTFBIO0m7kKIQvvPHN6UE63VjpmL9rnEEaOOaiSPbZK+zUOYIzBAWcED+3XYzhYsd/0mD57VdxAEqqV52CQ==}
dev: false
@ -1529,7 +1540,7 @@ packages:
magic-string: 0.30.5
node-html-parser: 6.1.12
resolve: 1.22.8
vite: 5.1.1(sass@1.71.1)
vite: 5.1.1(@types/node@20.11.22)(sass@1.71.1)
transitivePeerDependencies:
- preact
- supports-color
@ -1563,7 +1574,7 @@ packages:
'@prefresh/utils': 1.2.0
'@rollup/pluginutils': 4.2.1
preact: 10.19.6
vite: 5.1.1(sass@1.71.1)
vite: 5.1.1(@types/node@20.11.22)(sass@1.71.1)
transitivePeerDependencies:
- supports-color
dev: false
@ -1947,7 +1958,6 @@ packages:
resolution: {integrity: sha512-/G+IxWxma6V3E+pqK1tSl2Fo1kl41pK1yeCyDsgkF9WlVAme4j5ISYM2zR11bgLFJGLN5sVK40T4RJNuiZbEjA==}
dependencies:
undici-types: 5.26.5
dev: false
/@types/object-hash@3.0.6:
resolution: {integrity: sha512-fOBV8C1FIu2ELinoILQ+ApxcUKz4ngq+IWUYrxSGjXzzjUALijilampwkMgEtJ+h2njAW3pi853QpzNVCHB73w==}
@ -2176,7 +2186,6 @@ packages:
/@vercel/nft@0.24.4:
resolution: {integrity: sha512-KjYAZty7boH5fi5udp6p+lNu6nawgs++pHW+3koErMgbRkkHuToGX/FwjN5clV1FcaM3udfd4zW/sUapkMgpZw==}
engines: {node: '>=16'}
hasBin: true
dependencies:
'@mapbox/node-pre-gyp': 1.0.11
'@rollup/pluginutils': 4.2.1
@ -2218,7 +2227,6 @@ packages:
/@vinxi/listhen@1.5.6:
resolution: {integrity: sha512-WSN1z931BtasZJlgPp704zJFnQFRg7yzSjkm3MzAWQYe4uXFXlFr1hc5Ac2zae5/HDOz5x1/zDM5Cb54vTCnWw==}
hasBin: true
dependencies:
'@parcel/watcher': 2.4.1
'@parcel/watcher-wasm': 2.3.0
@ -2255,7 +2263,7 @@ packages:
magicast: 0.2.11
recast: 0.23.4
tslib: 2.6.2
vinxi: 0.3.4(preact@10.19.6)(sass@1.71.1)
vinxi: 0.3.4(@types/node@20.11.22)(preact@10.19.6)(sass@1.71.1)
dev: false
/@vinxi/server-components@0.3.0(vinxi@0.3.4):
@ -2270,7 +2278,7 @@ packages:
astring: 1.8.6
magicast: 0.2.11
recast: 0.23.4
vinxi: 0.3.4(preact@10.19.6)(sass@1.71.1)
vinxi: 0.3.4(@types/node@20.11.22)(preact@10.19.6)(sass@1.71.1)
dev: false
/@vinxi/server-functions@0.3.0(vinxi@0.3.4):
@ -2285,7 +2293,7 @@ packages:
astring: 1.8.6
magicast: 0.2.11
recast: 0.23.4
vinxi: 0.3.4(preact@10.19.6)(sass@1.71.1)
vinxi: 0.3.4(@types/node@20.11.22)(preact@10.19.6)(sass@1.71.1)
dev: false
/abbrev@1.1.1:
@ -2317,7 +2325,6 @@ packages:
/acorn@8.11.3:
resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==}
engines: {node: '>=0.4.0'}
hasBin: true
/agent-base@6.0.2:
resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}
@ -2451,7 +2458,6 @@ packages:
/astring@1.8.6:
resolution: {integrity: sha512-ISvCdHdlTDlH5IpxQJIex7BWBywFWgjJSVdwst+/iQCoEYnyOaQ95+X1JGshuBjGp6nxKUy1jMgE3zPqN7fQdg==}
hasBin: true
dev: false
/async-sema@3.1.1:
@ -2576,7 +2582,6 @@ packages:
/browserslist@4.23.0:
resolution: {integrity: sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==}
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
hasBin: true
dependencies:
caniuse-lite: 1.0.30001591
electron-to-chromium: 1.4.686
@ -2754,7 +2759,6 @@ packages:
/color-support@1.1.3:
resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==}
hasBin: true
dev: false
/commander@2.20.3:
@ -2816,7 +2820,6 @@ packages:
/crc-32@1.2.2:
resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==}
engines: {node: '>=0.8'}
hasBin: true
dev: false
/crc32-stream@5.0.0:
@ -2981,7 +2984,6 @@ packages:
/detect-libc@1.0.3:
resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==}
engines: {node: '>=0.10'}
hasBin: true
dev: false
/detect-libc@2.0.2:
@ -3056,7 +3058,6 @@ packages:
/drizzle-kit@0.20.14:
resolution: {integrity: sha512-0fHv3YIEaUcSVPSGyaaBfOi9bmpajjhbJNdPsRMIUvYdLVxBu9eGjH8mRc3Qk7HVmEidFc/lhG1YyJhoXrn5yA==}
hasBin: true
dependencies:
'@drizzle-team/studio': 0.0.39
'@esbuild-kit/esm-loader': 2.6.5
@ -3162,7 +3163,6 @@ packages:
/dts-buddy@0.2.5:
resolution: {integrity: sha512-66HTWHyXS3JwgpRwcu88rsDyZfPUb0oPYmiNg5f4BgCAFTVorJXpygf339QyXOXX1PuqHpvB+qo7O+8Ni1vXUQ==}
hasBin: true
dependencies:
'@jridgewell/source-map': 0.3.5
'@jridgewell/sourcemap-codec': 1.4.15
@ -3290,7 +3290,6 @@ packages:
/esbuild@0.18.20:
resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==}
engines: {node: '>=12'}
hasBin: true
requiresBuild: true
optionalDependencies:
'@esbuild/android-arm': 0.18.20
@ -3319,7 +3318,6 @@ packages:
/esbuild@0.19.12:
resolution: {integrity: sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==}
engines: {node: '>=12'}
hasBin: true
requiresBuild: true
optionalDependencies:
'@esbuild/aix-ppc64': 0.19.12
@ -3372,7 +3370,6 @@ packages:
/eslint-config-prettier@9.1.0(eslint@8.57.0):
resolution: {integrity: sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==}
hasBin: true
peerDependencies:
eslint: '>=7.0.0'
dependencies:
@ -3412,7 +3409,6 @@ packages:
/eslint@8.57.0:
resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
hasBin: true
dependencies:
'@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
'@eslint-community/regexpp': 4.10.0
@ -3478,7 +3474,6 @@ packages:
/esprima@4.0.1:
resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
engines: {node: '>=4'}
hasBin: true
dev: false
/esquery@1.5.0:
@ -3649,7 +3644,6 @@ packages:
/flat@5.0.2:
resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==}
hasBin: true
dev: false
/flatted@3.3.1:
@ -3696,6 +3690,14 @@ packages:
/fs.realpath@1.0.0:
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
/fsevents@2.3.2:
resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin]
requiresBuild: true
dev: true
optional: true
/fsevents@2.3.3:
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
@ -3770,7 +3772,6 @@ packages:
/giget@1.2.1:
resolution: {integrity: sha512-4VG22mopWtIeHwogGSy1FViXVo0YT+m6BrqZfz0JJFwbSsePsCdOzdLIIli5BtMp7Xe8f/o2OmBpQX2NBOC24g==}
hasBin: true
dependencies:
citty: 0.1.6
consola: 3.2.3
@ -3963,7 +3964,6 @@ packages:
/he@1.2.0:
resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==}
hasBin: true
dev: false
/heap@0.2.7:
@ -4136,13 +4136,11 @@ packages:
/is-docker@2.2.1:
resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==}
engines: {node: '>=8'}
hasBin: true
dev: false
/is-docker@3.0.0:
resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
hasBin: true
dev: false
/is-extglob@2.1.1:
@ -4177,7 +4175,6 @@ packages:
/is-inside-container@1.0.0:
resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==}
engines: {node: '>=14.16'}
hasBin: true
dependencies:
is-docker: 3.0.0
dev: false
@ -4278,7 +4275,6 @@ packages:
/jiti@1.21.0:
resolution: {integrity: sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==}
hasBin: true
dev: false
/js-tokens@4.0.0:
@ -4287,14 +4283,12 @@ packages:
/js-yaml@4.1.0:
resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
hasBin: true
dependencies:
argparse: 2.0.1
/jsesc@2.5.2:
resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==}
engines: {node: '>=4'}
hasBin: true
dev: false
/json-buffer@3.0.1:
@ -4303,7 +4297,6 @@ packages:
/json-diff@0.9.0:
resolution: {integrity: sha512-cVnggDrVkAAA3OvFfHpFEhOnmcsUpleEKq4d4O8sQWWSH40MBrWstKigVB1kGrgLWzuom+7rRdaCsnBD6VyObQ==}
hasBin: true
dependencies:
cli-color: 2.0.3
difflib: 0.2.4
@ -4331,7 +4324,6 @@ packages:
/json5@2.2.3:
resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
engines: {node: '>=6'}
hasBin: true
dev: false
/jsonc-parser@3.2.1:
@ -4399,7 +4391,6 @@ packages:
/listhen@1.7.2:
resolution: {integrity: sha512-7/HamOm5YD9Wb7CFgAZkKgVPA96WwhcTQoqtm2VTZGVbVVn3IWKRBTgrU7cchA3Q8k9iCsG8Osoi9GX4JsGM9g==}
hasBin: true
dependencies:
'@parcel/watcher': 2.4.1
'@parcel/watcher-wasm': 2.4.1
@ -4558,13 +4549,11 @@ packages:
/mime@1.6.0:
resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==}
engines: {node: '>=4'}
hasBin: true
dev: false
/mime@3.0.0:
resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==}
engines: {node: '>=10.0.0'}
hasBin: true
/mimic-fn@2.1.0:
resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
@ -4624,7 +4613,6 @@ packages:
/mkdirp@1.0.4:
resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==}
engines: {node: '>=10'}
hasBin: true
dev: false
/mlly@1.6.1:
@ -4670,7 +4658,6 @@ packages:
/nanoid@3.3.7:
resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true
dev: false
/natural-compare@1.4.0:
@ -4684,7 +4671,6 @@ packages:
/nitropack@2.8.1:
resolution: {integrity: sha512-pODv2kEEzZSDQR+1UMXbGyNgMedUDq/qUomtiAnQKQvLy52VGlecXO1xDfH3i0kP1yKEcKTnWsx1TAF5gHM7xQ==}
engines: {node: ^16.11.0 || >=17.0.0}
hasBin: true
peerDependencies:
xml2js: ^0.6.2
peerDependenciesMeta:
@ -4800,7 +4786,6 @@ packages:
/node-gyp-build@4.8.0:
resolution: {integrity: sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og==}
hasBin: true
dev: false
/node-html-parser@6.1.12:
@ -4817,7 +4802,6 @@ packages:
/nopt@5.0.0:
resolution: {integrity: sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==}
engines: {node: '>=6'}
hasBin: true
dependencies:
abbrev: 1.1.1
dev: false
@ -4858,7 +4842,6 @@ packages:
/nypm@0.3.6:
resolution: {integrity: sha512-2CATJh3pd6CyNfU5VZM7qSwFu0ieyabkEdnogE30Obn1czrmOYiZ8DOZLe1yBdLKWoyD3Mcy2maUs+0MR3yVjQ==}
engines: {node: ^14.16.0 || >=16.10.0}
hasBin: true
dependencies:
citty: 0.1.6
execa: 8.0.1
@ -4967,7 +4950,6 @@ packages:
/openapi-typescript@6.7.4:
resolution: {integrity: sha512-EZyeW9Wy7UDCKv0iYmKrq2pVZtquXiD/YHiUClAKqiMi42nodx/EQH11K6fLqjt1IZlJmVokrAsExsBMM2RROQ==}
hasBin: true
dependencies:
ansi-colors: 4.1.3
fast-glob: 3.3.2
@ -5139,6 +5121,20 @@ packages:
pathe: 1.1.2
dev: false
/playwright-core@1.42.0:
resolution: {integrity: sha512-0HD9y8qEVlcbsAjdpBaFjmaTHf+1FeIddy8VJLeiqwhcNqGCBe4Wp2e8knpqiYbzxtxarxiXyNDw2cG8sCaNMQ==}
engines: {node: '>=16'}
dev: true
/playwright@1.42.0:
resolution: {integrity: sha512-Ko7YRUgj5xBHbntrgt4EIw/nE//XBHOKVKnBjO1KuZkmkhlbgyggTe5s9hjqQ1LpN+Xg+kHsQyt5Pa0Bw5XpvQ==}
engines: {node: '>=16'}
dependencies:
playwright-core: 1.42.0
optionalDependencies:
fsevents: 2.3.2
dev: true
/possible-typed-array-names@1.0.0:
resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==}
engines: {node: '>= 0.4'}
@ -5204,7 +5200,6 @@ packages:
/prettier@3.2.5:
resolution: {integrity: sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==}
engines: {node: '>=14'}
hasBin: true
dev: true
/pretty-bytes@6.1.1:
@ -5331,7 +5326,6 @@ packages:
/resolve@1.22.8:
resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==}
hasBin: true
dependencies:
is-core-module: 2.13.1
path-parse: 1.0.7
@ -5344,14 +5338,12 @@ packages:
/rimraf@3.0.2:
resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
hasBin: true
dependencies:
glob: 7.2.3
/rollup-plugin-visualizer@5.12.0(rollup@4.12.0):
resolution: {integrity: sha512-8/NU9jXcHRs7Nnj07PF2o4gjxmm9lXIrZ8r175bT9dK8qoLlvKTwRMArRCMgpMGlq8CTLugRvEmyMeMXIU2pNQ==}
engines: {node: '>=14'}
hasBin: true
peerDependencies:
rollup: 2.x || 3.x || 4.x
peerDependenciesMeta:
@ -5368,7 +5360,6 @@ packages:
/rollup@4.12.0:
resolution: {integrity: sha512-wz66wn4t1OHIJw3+XU7mJJQV/2NAfw5OAk6G6Hoo3zcvz/XOfQ52Vgi+AN4Uxoxi0KBBwk2g8zPrTDA4btSB/Q==}
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
hasBin: true
dependencies:
'@types/estree': 1.0.5
optionalDependencies:
@ -5418,7 +5409,6 @@ packages:
/sass@1.71.1:
resolution: {integrity: sha512-wovtnV2PxzteLlfNzbgm1tFXPLoZILYAMJtvoXXkD7/+1uP41eKkIt1ypWq5/q2uT94qHjXehEYfmjKOvjL9sg==}
engines: {node: '>=14.0.0'}
hasBin: true
dependencies:
chokidar: 3.6.0
immutable: 4.3.5
@ -5430,13 +5420,11 @@ packages:
/semver@6.3.1:
resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
hasBin: true
dev: false
/semver@7.6.0:
resolution: {integrity: sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==}
engines: {node: '>=10'}
hasBin: true
dependencies:
lru-cache: 6.0.0
@ -5795,7 +5783,6 @@ packages:
/terser@5.28.1:
resolution: {integrity: sha512-wM+bZp54v/E9eRRGXb5ZFDvinrJIOaTapx3WUokyVGZu5ucVCK55zEgGd5Dl2fSr3jUo5sDiERErUWLY6QPFyA==}
engines: {node: '>=10'}
hasBin: true
dependencies:
'@jridgewell/source-map': 0.3.5
acorn: 8.11.3
@ -5906,13 +5893,11 @@ packages:
/typescript@5.0.4:
resolution: {integrity: sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==}
engines: {node: '>=12.20'}
hasBin: true
dev: false
/typescript@5.3.3:
resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==}
engines: {node: '>=14.17'}
hasBin: true
dev: true
/ufo@1.4.0:
@ -5932,7 +5917,6 @@ packages:
/undici-types@5.26.5:
resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
dev: false
/undici-types@5.28.3:
resolution: {integrity: sha512-VJD0un4i6M1/lFOJPhacHdq6FadtlkdhKBed2W6yBqmrAr/W58oqENaOIX031stDVFwz9AemOLkIj/2AXAMLCg==}
@ -6056,7 +6040,6 @@ packages:
/untun@0.1.3:
resolution: {integrity: sha512-4luGP9LMYszMRZwsvyUd9MrxgEGZdZuZgpVQHEEX0lCYFESasVRvZd0EYpCkOIbJKHMuv0LskpXc/8Un+MJzEQ==}
hasBin: true
dependencies:
citty: 0.1.6
consola: 3.2.3
@ -6065,7 +6048,6 @@ packages:
/update-browserslist-db@1.0.13(browserslist@4.23.0):
resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==}
hasBin: true
peerDependencies:
browserslist: '>= 4.21.0'
dependencies:
@ -6106,9 +6088,8 @@ packages:
resolution: {integrity: sha512-hGdgQozCsQJMyfK5urgFcWEqsSSrK63Awe0t/IMR0bZ0QMtnuaiHzThW81guu3qx9abLi99NEuiaN6P9gVYsNg==}
dev: false
/vinxi@0.3.4(preact@10.19.6)(sass@1.71.1):
/vinxi@0.3.4(@types/node@20.11.22)(preact@10.19.6)(sass@1.71.1):
resolution: {integrity: sha512-WAQbutVIX9zE2U5jraq+uvW2ytzb59HtX+/KVKqZSgjfQQpCHyi3XNxRkf46WTM5gASDEDFaG0l5ZHunmf7/cw==}
hasBin: true
dependencies:
'@babel/core': 7.24.0
'@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.24.0)
@ -6153,7 +6134,7 @@ packages:
unenv: 1.9.0
unimport: 3.7.1(rollup@4.12.0)
unstorage: 1.10.1
vite: 5.1.1(sass@1.71.1)
vite: 5.1.1(@types/node@20.11.22)(sass@1.71.1)
ws: 8.16.0
zod: 3.22.4
transitivePeerDependencies:
@ -6207,7 +6188,7 @@ packages:
open: 9.1.0
picocolors: 1.0.0
sirv: 2.0.4
vite: 5.1.1(sass@1.71.1)
vite: 5.1.1(@types/node@20.11.22)(sass@1.71.1)
transitivePeerDependencies:
- rollup
- supports-color
@ -6231,7 +6212,7 @@ packages:
open: 9.1.0
picocolors: 1.0.0
sirv: 2.0.4
vite: 5.1.4(sass@1.71.1)
vite: 5.1.4(@types/node@20.11.22)(sass@1.71.1)
transitivePeerDependencies:
- rollup
- supports-color
@ -6253,7 +6234,7 @@ packages:
merge-anything: 5.1.7
solid-js: 1.8.15
solid-refresh: 0.6.3(solid-js@1.8.15)
vite: 5.1.1(sass@1.71.1)
vite: 5.1.1(@types/node@20.11.22)(sass@1.71.1)
vitefu: 0.2.5(vite@5.1.1)
transitivePeerDependencies:
- supports-color
@ -6275,16 +6256,15 @@ packages:
merge-anything: 5.1.7
solid-js: 1.8.15
solid-refresh: 0.6.3(solid-js@1.8.15)
vite: 5.1.4(sass@1.71.1)
vite: 5.1.4(@types/node@20.11.22)(sass@1.71.1)
vitefu: 0.2.5(vite@5.1.4)
transitivePeerDependencies:
- supports-color
dev: false
/vite@5.1.1(sass@1.71.1):
/vite@5.1.1(@types/node@20.11.22)(sass@1.71.1):
resolution: {integrity: sha512-wclpAgY3F1tR7t9LL5CcHC41YPkQIpKUGeIuT8MdNwNZr6OqOTLs7JX5vIHAtzqLWXts0T+GDrh9pN2arneKqg==}
engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true
peerDependencies:
'@types/node': ^18.0.0 || >=20.0.0
less: '*'
@ -6309,6 +6289,7 @@ packages:
terser:
optional: true
dependencies:
'@types/node': 20.11.22
esbuild: 0.19.12
postcss: 8.4.35
rollup: 4.12.0
@ -6317,7 +6298,7 @@ packages:
fsevents: 2.3.3
dev: false
/vite@5.1.4(sass@1.71.1):
/vite@5.1.4(@types/node@20.11.22)(sass@1.71.1):
resolution: {integrity: sha512-n+MPqzq+d9nMVTKyewqw6kSt+R3CkvF9QAKY8obiQn8g1fwTscKxyfaYnC632HtBXAQGc1Yjomphwn1dtwGAHg==}
engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true
@ -6345,6 +6326,7 @@ packages:
terser:
optional: true
dependencies:
'@types/node': 20.11.22
esbuild: 0.19.12
postcss: 8.4.35
rollup: 4.12.0
@ -6361,7 +6343,7 @@ packages:
vite:
optional: true
dependencies:
vite: 5.1.1(sass@1.71.1)
vite: 5.1.1(@types/node@20.11.22)(sass@1.71.1)
dev: false
/vitefu@0.2.5(vite@5.1.4):
@ -6372,7 +6354,7 @@ packages:
vite:
optional: true
dependencies:
vite: 5.1.4(sass@1.71.1)
vite: 5.1.4(@types/node@20.11.22)(sass@1.71.1)
dev: false
/webidl-conversions@3.0.1:
@ -6409,14 +6391,12 @@ packages:
/which@2.0.2:
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
engines: {node: '>= 8'}
hasBin: true
dependencies:
isexe: 2.0.0
/which@4.0.0:
resolution: {integrity: sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==}
engines: {node: ^16.13.0 || >=18.0.0}
hasBin: true
dependencies:
isexe: 3.1.1
dev: false

View file

@ -4,6 +4,12 @@ import "../styles/components/NavBar.scss";
import { FontAwesomeIcon } from "./FontAwesomeIcon";
import NavUser from "./NavUser";
if (typeof import.meta.env.VITE_DISCORD_CLIENT_ID === "undefined")
throw new Error("No env VITE_DISCORD_CLIENT_ID found!");
if (typeof import.meta.env.VITE_DISCORD_OAUTH2_PERMISSIONS === "undefined")
throw new Error("No env VITE_DISCORD_OAUTH2_PERMISSIONS found!");
export function Li(props: {
href: string;
rel?: string;
@ -36,7 +42,7 @@ function NavBar() {
</ul>
<ul class="flex-row responsive thick">
<Li
href={`https://discord.com/api/oauth2/authorize?client_id=${import.meta.env.VITE_DISCORD_CLIENT_ID}&permissions=${import.meta.env.VITE_DISCORD_BOT_PERMISSIONS}&scope=bot`}
href={`https://discord.com/api/oauth2/authorize?client_id=${import.meta.env.VITE_DISCORD_CLIENT_ID}&permissions=${import.meta.env.VITE_DISCORD_OAUTH2_PERMISSIONS}&scope=bot`}
name="Invite to your server"
>
<FontAwesomeIcon class="lower" icon={faCirclePlus} size="xl" />

View file

@ -2,7 +2,10 @@ import { drizzle } from "drizzle-orm/postgres-js";
import postgres from "postgres";
import * as schema from "./schema";
const queryClient = postgres(import.meta.env.VITE_DATABASE_URL ?? "");
if (typeof import.meta.env.VITE_DATABASE_URL === "undefined")
throw new Error("No env VITE_DATABASE_URL found!");
const queryClient = postgres(import.meta.env.VITE_DATABASE_URL);
const db = drizzle(queryClient, {
schema,
});

View file

@ -4,6 +4,18 @@ import { Lucia } from "lucia";
import db from "~/drizzle";
import { sessions, users } from "~/drizzle/schema";
if (typeof import.meta.env.PROD === "undefined")
throw new Error("No env PROD found!");
if (typeof import.meta.env.VITE_DISCORD_CLIENT_ID === "undefined")
throw new Error("No env VITE_DISCORD_CLIENT_ID found!");
if (typeof import.meta.env.VITE_DISCORD_CLIENT_SECRET === "undefined")
throw new Error("No env PROD found!");
if (typeof import.meta.env.VITE_AUTH_REDIRECT_URL === "undefined")
throw new Error("No env VITE_AUTH_REDIRECT_URL found!");
const adapter = new DrizzlePostgreSQLAdapter(db, sessions, users);
export const lucia = new Lucia(adapter, {

View file

@ -11,12 +11,11 @@ import { discord, lucia } from "~/lib/auth";
import { paths } from "~/types/discord";
export async function GET(event: APIEvent): Promise<Response> {
const code = new URL(event.request.url).searchParams.get("code");
const state = new URL(event.request.url).searchParams.get("state");
const error = new URL(event.request.url).searchParams.get("error");
const error_description = new URL(event.request.url).searchParams.get(
"error_description",
);
const url = new URL(event.request.url);
const code = url.searchParams.get("code");
const state = url.searchParams.get("state");
const error = url.searchParams.get("error");
const error_description = url.searchParams.get("error_description");
if (error)
switch (error) {
case "access_denied":
@ -61,7 +60,6 @@ export async function GET(event: APIEvent): Promise<Response> {
{ sessionId: createId() },
);
const sessionCookie = lucia.createSessionCookie(session.id);
console.log(sessionCookie);
setCookie(
sessionCookie.name,
sessionCookie.value,
@ -100,7 +98,6 @@ export async function GET(event: APIEvent): Promise<Response> {
})
.returning()
.execute();
console.log(createId(), createId(), { warst: createId() });
const session = await lucia.createSession(
userId,
{},

View file

@ -4,6 +4,9 @@ import httpStatus from "http-status";
import { setCookie } from "vinxi/http";
import { discord } from "~/lib/auth";
if (typeof import.meta.env.PROD === "undefined")
throw new Error("No env PROD found!");
export async function GET(event: APIEvent) {
const state = generateState();
const url = await discord.createAuthorizationURL(state, {

View file

@ -19,6 +19,9 @@ import { discordTokens } from "~/drizzle/schema";
import { paths } from "~/types/discord";
import "../../styles/pages/config.scss";
if (typeof import.meta.env.VITE_DISCORD_BOT_TOKEN === "undefined")
throw new Error("No env VITE_DISCORD_BOT_TOKEN found!");
const guessTZ = () => Intl.DateTimeFormat().resolvedOptions().timeZone;
const initialValue = (params: ReturnType<typeof useParams>) => ({

View file

@ -15,6 +15,12 @@ import { discordTokens } from "~/drizzle/schema";
import { paths } from "~/types/discord";
import "../../styles/pages/config.scss";
if (typeof import.meta.env.VITE_DISCORD_CLIENT_ID === "undefined")
throw new Error("No env VITE_DISCORD_CLIENT_ID found!");
if (typeof import.meta.env.VITE_DISCORD_OAUTH2_PERMISSIONS === "undefined")
throw new Error("No env VITE_DISCORD_OAUTH2_PERMISSIONS found!");
const initialValue = () => ({
success: null as boolean | null,
guilds: [] as {
@ -105,7 +111,7 @@ function index() {
href={
i() % 3 === 0
? `/config/${guild.id}`
: `https://discord.com/api/oauth2/authorize?client_id=${import.meta.env.VITE_DISCORD_CLIENT_ID}&permissions=${import.meta.env.VITE_DISCORD_BOT_PERMISSIONS}&scope=bot&guild_id=${guild.id}`
: `https://discord.com/api/oauth2/authorize?client_id=${import.meta.env.VITE_DISCORD_CLIENT_ID}&permissions=${import.meta.env.VITE_DISCORD_OAUTH2_PERMISSIONS}&scope=bot&guild_id=${guild.id}`
}
class="flex-row centered"
>

2
src/types/env.d.ts vendored
View file

@ -4,7 +4,7 @@ interface ImportMetaEnv {
readonly VITE_DISCORD_CLIENT_ID: string;
readonly VITE_DISCORD_CLIENT_SECRET: string;
readonly VITE_DISCORD_BOT_TOKEN: string;
readonly VITE_DISCORD_BOT_PERMISSIONS: string;
readonly VITE_DISCORD_OAUTH2_PERMISSIONS: string;
readonly VITE_AUTH_SECRET: string;
readonly VITE_AUTH_REDIRECT_PROXY_URL: string | undefined;