From 0144e8df1a9504cf96be733e33cdfce056d9f593 Mon Sep 17 00:00:00 2001 From: rasmusq Date: Tue, 25 Nov 2025 16:08:50 +0100 Subject: [PATCH] initial production version --- wishlist-app/.dockerignore => .dockerignore | 0 .env.example | 20 + wishlist-app/.gitignore => .gitignore | 3 + wishlist-app/.npmrc => .npmrc | 0 COOLIFY_DEPLOYMENT.md | 75 +++ DOCKER.md | 57 ++ wishlist-app/Dockerfile => Dockerfile | 4 +- LICENSE | 33 + README.md | 64 ++ SETUP.md | 71 +++ wishlist-app/bun.lock => bun.lock | 181 +++++- components.json | 16 + docker-compose.coolify.yml | 52 ++ .../docker-compose.yml => docker-compose.yml | 7 +- .../drizzle.config.ts => drizzle.config.ts | 0 .../meta/0000_snapshot.json | 0 drizzle/meta/0001_snapshot.json | 593 ++++++++++++++++++ drizzle/meta/0002_snapshot.json | 593 ++++++++++++++++++ drizzle/meta/_journal.json | 27 + wishlist-app/package.json => package.json | 14 +- patches/@auth+core+0.34.3.patch | 18 + .../scripts => scripts}/docker-migrate.sh | 0 src/app.css | 129 ++++ src/app.d.ts | 14 + src/app.html | 21 + src/auth.ts | 123 ++++ src/hooks.server.ts | 1 + .../src => src}/lib/assets/favicon.svg | 0 .../components/dashboard/WishlistCard.svelte | 45 ++ .../components/dashboard/WishlistGrid.svelte | 79 +++ .../components/layout/DashboardHeader.svelte | 18 + src/lib/components/layout/EmptyState.svelte | 45 ++ src/lib/components/layout/Navigation.svelte | 34 + .../components/layout/PageContainer.svelte | 11 + src/lib/components/ui/ColorPicker.svelte | 63 ++ .../lib/components/ui/button/button.svelte | 0 .../lib/components/ui/button/index.ts | 0 .../components/ui/card/card-content.svelte | 0 .../ui/card/card-description.svelte | 0 .../lib/components/ui/card/card-header.svelte | 0 .../lib/components/ui/card/card-title.svelte | 0 .../lib/components/ui/card/card.svelte | 0 .../lib/components/ui/card/index.ts | 0 .../lib/components/ui/input/index.ts | 0 .../lib/components/ui/input/input.svelte | 0 .../lib/components/ui/label/index.ts | 0 .../lib/components/ui/label/label.svelte | 0 .../ui/language-toggle/LanguageToggle.svelte | 58 ++ .../components/ui/language-toggle/index.ts | 2 + .../lib/components/ui/textarea/index.ts | 0 .../components/ui/textarea/textarea.svelte | 0 .../ui/theme-toggle/ThemeToggle.svelte | 22 + src/lib/components/ui/theme-toggle/index.ts | 1 + .../components/wishlist/AddItemForm.svelte | 140 +++++ .../components/wishlist/EditItemForm.svelte | 176 ++++++ .../wishlist/EditableItemsList.svelte | 72 +++ .../components/wishlist/ImageSelector.svelte | 33 + .../wishlist/ReservationButton.svelte | 70 +++ src/lib/components/wishlist/ShareLinks.svelte | 58 ++ .../wishlist/WishlistActionButtons.svelte | 33 + .../components/wishlist/WishlistHeader.svelte | 191 ++++++ .../components/wishlist/WishlistItem.svelte | 116 ++++ src/lib/i18n/translations/da.ts | 93 +++ src/lib/i18n/translations/en.ts | 168 +++++ src/lib/i18n/translations/index.ts | 15 + src/lib/index.ts | 1 + {wishlist-app/src => src}/lib/server/db.ts | 4 +- src/lib/server/schema.ts | 166 +++++ src/lib/stores/language.svelte.ts | 63 ++ src/lib/stores/theme.svelte.ts | 63 ++ src/lib/utils.ts | 13 + src/lib/utils/colors.ts | 18 + .../src => src}/routes/+layout.svelte | 4 +- src/routes/+page.server.ts | 8 + {wishlist-app/src => src}/routes/+page.svelte | 38 +- src/routes/api/scrape-images/+server.ts | 75 +++ .../routes/api/wishlists/+server.ts | 11 +- src/routes/dashboard/+page.server.ts | 111 ++++ src/routes/dashboard/+page.svelte | 189 ++++++ src/routes/signin/+page.server.ts | 24 + src/routes/signin/+page.svelte | 102 +++ src/routes/signup/+page.server.ts | 68 ++ src/routes/signup/+page.svelte | 81 +++ src/routes/wishlist/[token]/+page.server.ts | 158 +++++ src/routes/wishlist/[token]/+page.svelte | 137 ++++ .../wishlist/[token]/edit/+page.server.ts | 228 +++++++ src/routes/wishlist/[token]/edit/+page.svelte | 300 +++++++++ {wishlist-app/static => static}/robots.txt | 0 .../svelte.config.js => svelte.config.js | 0 wishlist-app/tsconfig.json => tsconfig.json | 0 wishlist-app/vite.config.ts => vite.config.ts | 0 wishlist-app/.env.example | 3 - wishlist-app/COOLIFY_DEPLOYMENT.md | 272 -------- wishlist-app/DOCKER.md | 387 ------------ wishlist-app/README.md | 227 ------- wishlist-app/SETUP.md | 149 ----- .../drizzle/0000_last_steve_rogers.sql | 35 -- wishlist-app/drizzle/meta/_journal.json | 13 - wishlist-app/src/app.css | 34 - wishlist-app/src/app.d.ts | 13 - wishlist-app/src/app.html | 11 - wishlist-app/src/lib/index.ts | 1 - wishlist-app/src/lib/server/schema.ts | 64 -- wishlist-app/src/lib/utils.ts | 8 - .../routes/wishlist/[token]/+page.server.ts | 83 --- .../src/routes/wishlist/[token]/+page.svelte | 158 ----- .../wishlist/[token]/edit/+page.server.ts | 80 --- .../routes/wishlist/[token]/edit/+page.svelte | 223 ------- 108 files changed, 5502 insertions(+), 1780 deletions(-) rename wishlist-app/.dockerignore => .dockerignore (100%) create mode 100644 .env.example rename wishlist-app/.gitignore => .gitignore (92%) rename wishlist-app/.npmrc => .npmrc (100%) create mode 100644 COOLIFY_DEPLOYMENT.md create mode 100644 DOCKER.md rename wishlist-app/Dockerfile => Dockerfile (91%) create mode 100644 LICENSE create mode 100644 README.md create mode 100644 SETUP.md rename wishlist-app/bun.lock => bun.lock (73%) create mode 100644 components.json create mode 100644 docker-compose.coolify.yml rename wishlist-app/docker-compose.yml => docker-compose.yml (77%) rename wishlist-app/drizzle.config.ts => drizzle.config.ts (100%) rename {wishlist-app/drizzle => drizzle}/meta/0000_snapshot.json (100%) create mode 100644 drizzle/meta/0001_snapshot.json create mode 100644 drizzle/meta/0002_snapshot.json create mode 100644 drizzle/meta/_journal.json rename wishlist-app/package.json => package.json (73%) create mode 100644 patches/@auth+core+0.34.3.patch rename {wishlist-app/scripts => scripts}/docker-migrate.sh (100%) create mode 100644 src/app.css create mode 100644 src/app.d.ts create mode 100644 src/app.html create mode 100644 src/auth.ts create mode 100644 src/hooks.server.ts rename {wishlist-app/src => src}/lib/assets/favicon.svg (100%) create mode 100644 src/lib/components/dashboard/WishlistCard.svelte create mode 100644 src/lib/components/dashboard/WishlistGrid.svelte create mode 100644 src/lib/components/layout/DashboardHeader.svelte create mode 100644 src/lib/components/layout/EmptyState.svelte create mode 100644 src/lib/components/layout/Navigation.svelte create mode 100644 src/lib/components/layout/PageContainer.svelte create mode 100644 src/lib/components/ui/ColorPicker.svelte rename {wishlist-app/src => src}/lib/components/ui/button/button.svelte (100%) rename {wishlist-app/src => src}/lib/components/ui/button/index.ts (100%) rename {wishlist-app/src => src}/lib/components/ui/card/card-content.svelte (100%) rename {wishlist-app/src => src}/lib/components/ui/card/card-description.svelte (100%) rename {wishlist-app/src => src}/lib/components/ui/card/card-header.svelte (100%) rename {wishlist-app/src => src}/lib/components/ui/card/card-title.svelte (100%) rename {wishlist-app/src => src}/lib/components/ui/card/card.svelte (100%) rename {wishlist-app/src => src}/lib/components/ui/card/index.ts (100%) rename {wishlist-app/src => src}/lib/components/ui/input/index.ts (100%) rename {wishlist-app/src => src}/lib/components/ui/input/input.svelte (100%) rename {wishlist-app/src => src}/lib/components/ui/label/index.ts (100%) rename {wishlist-app/src => src}/lib/components/ui/label/label.svelte (100%) create mode 100644 src/lib/components/ui/language-toggle/LanguageToggle.svelte create mode 100644 src/lib/components/ui/language-toggle/index.ts rename {wishlist-app/src => src}/lib/components/ui/textarea/index.ts (100%) rename {wishlist-app/src => src}/lib/components/ui/textarea/textarea.svelte (100%) create mode 100644 src/lib/components/ui/theme-toggle/ThemeToggle.svelte create mode 100644 src/lib/components/ui/theme-toggle/index.ts create mode 100644 src/lib/components/wishlist/AddItemForm.svelte create mode 100644 src/lib/components/wishlist/EditItemForm.svelte create mode 100644 src/lib/components/wishlist/EditableItemsList.svelte create mode 100644 src/lib/components/wishlist/ImageSelector.svelte create mode 100644 src/lib/components/wishlist/ReservationButton.svelte create mode 100644 src/lib/components/wishlist/ShareLinks.svelte create mode 100644 src/lib/components/wishlist/WishlistActionButtons.svelte create mode 100644 src/lib/components/wishlist/WishlistHeader.svelte create mode 100644 src/lib/components/wishlist/WishlistItem.svelte create mode 100644 src/lib/i18n/translations/da.ts create mode 100644 src/lib/i18n/translations/en.ts create mode 100644 src/lib/i18n/translations/index.ts create mode 100644 src/lib/index.ts rename {wishlist-app/src => src}/lib/server/db.ts (64%) create mode 100644 src/lib/server/schema.ts create mode 100644 src/lib/stores/language.svelte.ts create mode 100644 src/lib/stores/theme.svelte.ts create mode 100644 src/lib/utils.ts create mode 100644 src/lib/utils/colors.ts rename {wishlist-app/src => src}/routes/+layout.svelte (69%) create mode 100644 src/routes/+page.server.ts rename {wishlist-app/src => src}/routes/+page.svelte (57%) create mode 100644 src/routes/api/scrape-images/+server.ts rename {wishlist-app/src => src}/routes/api/wishlists/+server.ts (69%) create mode 100644 src/routes/dashboard/+page.server.ts create mode 100644 src/routes/dashboard/+page.svelte create mode 100644 src/routes/signin/+page.server.ts create mode 100644 src/routes/signin/+page.svelte create mode 100644 src/routes/signup/+page.server.ts create mode 100644 src/routes/signup/+page.svelte create mode 100644 src/routes/wishlist/[token]/+page.server.ts create mode 100644 src/routes/wishlist/[token]/+page.svelte create mode 100644 src/routes/wishlist/[token]/edit/+page.server.ts create mode 100644 src/routes/wishlist/[token]/edit/+page.svelte rename {wishlist-app/static => static}/robots.txt (100%) rename wishlist-app/svelte.config.js => svelte.config.js (100%) rename wishlist-app/tsconfig.json => tsconfig.json (100%) rename wishlist-app/vite.config.ts => vite.config.ts (100%) delete mode 100644 wishlist-app/.env.example delete mode 100644 wishlist-app/COOLIFY_DEPLOYMENT.md delete mode 100644 wishlist-app/DOCKER.md delete mode 100644 wishlist-app/README.md delete mode 100644 wishlist-app/SETUP.md delete mode 100644 wishlist-app/drizzle/0000_last_steve_rogers.sql delete mode 100644 wishlist-app/drizzle/meta/_journal.json delete mode 100644 wishlist-app/src/app.css delete mode 100644 wishlist-app/src/app.d.ts delete mode 100644 wishlist-app/src/app.html delete mode 100644 wishlist-app/src/lib/index.ts delete mode 100644 wishlist-app/src/lib/server/schema.ts delete mode 100644 wishlist-app/src/lib/utils.ts delete mode 100644 wishlist-app/src/routes/wishlist/[token]/+page.server.ts delete mode 100644 wishlist-app/src/routes/wishlist/[token]/+page.svelte delete mode 100644 wishlist-app/src/routes/wishlist/[token]/edit/+page.server.ts delete mode 100644 wishlist-app/src/routes/wishlist/[token]/edit/+page.svelte diff --git a/wishlist-app/.dockerignore b/.dockerignore similarity index 100% rename from wishlist-app/.dockerignore rename to .dockerignore diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..f91f2b5 --- /dev/null +++ b/.env.example @@ -0,0 +1,20 @@ +# Database connection string +# Example: postgresql://username:password@localhost:5432/wishlist +DATABASE_URL=postgresql://user:password@localhost:5432/wishlist + +# Auth.js configuration +# Generate AUTH_SECRET with: openssl rand -base64 32 +AUTH_SECRET=your-secret-key-here +AUTH_URL=http://localhost:5173 +AUTH_TRUST_HOST=true + +# Google OAuth (optional - for Google sign-in) +GOOGLE_CLIENT_ID=your-google-client-id +GOOGLE_CLIENT_SECRET=your-google-client-secret + +# Authentik OAuth (optional - for Authentik sign-in) +# AUTHENTIK_ISSUER should be your Authentik URL with the application slug +# Example: https://authentik.company.com/application/o/wishlist/ +AUTHENTIK_CLIENT_ID=your-authentik-client-id +AUTHENTIK_CLIENT_SECRET=your-authentik-client-secret +AUTHENTIK_ISSUER=https://authentik.example.com/application/o/your-app/ diff --git a/wishlist-app/.gitignore b/.gitignore similarity index 92% rename from wishlist-app/.gitignore rename to .gitignore index 3b462cb..4d813fe 100644 --- a/wishlist-app/.gitignore +++ b/.gitignore @@ -21,3 +21,6 @@ Thumbs.db # Vite vite.config.js.timestamp-* vite.config.ts.timestamp-* + +# Claude +.claude diff --git a/wishlist-app/.npmrc b/.npmrc similarity index 100% rename from wishlist-app/.npmrc rename to .npmrc diff --git a/COOLIFY_DEPLOYMENT.md b/COOLIFY_DEPLOYMENT.md new file mode 100644 index 0000000..746e425 --- /dev/null +++ b/COOLIFY_DEPLOYMENT.md @@ -0,0 +1,75 @@ +# Coolify Deployment + +## Prerequisites + +- Coolify instance +- Git repository + +## Database Setup + +Choose one: + +**Option A: Docker Compose (Recommended)** +- Database included in `docker-compose.coolify.yml` +- Skip to step 2 + +**Option B: Separate PostgreSQL Resource** +1. Create PostgreSQL database in Coolify +2. Note connection details + +## Deploy + +### Using Docker Compose (Recommended) + +1. Create application in Coolify +2. Select Git repository +3. Configure: + - Build Pack: Docker Compose + - File: `./docker-compose.coolify.yml` +4. Assign domain to `app` service only (format: `http://yourdomain.com:3000`) +5. Set environment variables (if needed) +6. Deploy + +### Using Dockerfile + +1. Create application in Coolify +2. Select Git repository +3. Configure: + - Build Pack: Docker + - Port: `3000` +4. Add domain +5. Set environment variables: + - `DATABASE_URL` + - `AUTH_SECRET` (generate with `openssl rand -base64 32`) + - `AUTH_URL` (your domain with https) + - `GOOGLE_CLIENT_ID` (optional) + - `GOOGLE_CLIENT_SECRET` (optional) +6. Deploy + +## After Deployment + +Run migrations: +```bash +# In Coolify terminal or SSH +docker exec -it bun run db:push +``` + +## Environment Variables + +Required: +- `DATABASE_URL` - Connection string +- `AUTH_SECRET` - Random secret +- `AUTH_URL` - Your app URL +- `AUTH_TRUST_HOST` - `true` + +Optional: +- `GOOGLE_CLIENT_ID` +- `GOOGLE_CLIENT_SECRET` + +## Troubleshooting + +**Container crashes:** Check logs in Coolify dashboard + +**Database connection:** Verify `DATABASE_URL` format + +**Auth issues:** Check `AUTH_URL` matches your domain diff --git a/DOCKER.md b/DOCKER.md new file mode 100644 index 0000000..169a05b --- /dev/null +++ b/DOCKER.md @@ -0,0 +1,57 @@ +# Docker Guide + +## Docker Compose + +```bash +# Start services +docker-compose up -d + +# Setup database +docker-compose exec app bun run db:push + +# View logs +docker-compose logs -f app + +# Stop services +docker-compose down +``` + +Visit `http://localhost:3000` + +## Docker Build + +```bash +# Build image +docker build -t wishlist-app . + +# Run container +docker run -d \ + -p 3000:3000 \ + -e DATABASE_URL="postgresql://user:pass@host:5432/db" \ + --name wishlist-app \ + wishlist-app +``` + +## Environment Variables + +Required: +- `DATABASE_URL` - PostgreSQL connection string +- `NODE_ENV` - Set to `production` +- `PORT` - Default `3000` + +## Database Setup + +```bash +# docker-compose +docker-compose exec app bun run db:push + +# Standalone container +docker exec -it wishlist-app bun run db:push +``` + +## Migrations + +Production migrations: +```bash +docker exec -it wishlist-app bun run db:migrate +``` diff --git a/wishlist-app/Dockerfile b/Dockerfile similarity index 91% rename from wishlist-app/Dockerfile rename to Dockerfile index 22d4341..c4cbaaf 100644 --- a/wishlist-app/Dockerfile +++ b/Dockerfile @@ -4,8 +4,10 @@ WORKDIR /app # Install dependencies FROM base AS deps -COPY package.json bun.lockb ./ +COPY package.json bun.lock* ./ +COPY patches ./patches RUN bun install --frozen-lockfile +RUN bunx patch-package # Build the application FROM base AS builder diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..5879434 --- /dev/null +++ b/LICENSE @@ -0,0 +1,33 @@ +GNU AFFERO GENERAL PUBLIC LICENSE +Version 3, 19 November 2007 + +Copyright (C) 2025 Rasmus Quist + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . + +--- + +ADDITIONAL TERMS: + +This software may only be used in open source projects. Any use of this +software in proprietary, closed-source, or non-open-source projects is +strictly prohibited. + +For the purposes of this license, "open source project" means a project +whose source code is publicly available under an OSI-approved open source +license. + +--- + +Full license text: https://www.gnu.org/licenses/agpl-3.0.txt diff --git a/README.md b/README.md new file mode 100644 index 0000000..bac032e --- /dev/null +++ b/README.md @@ -0,0 +1,64 @@ +# Wishlist App + +A wishlist application built with SvelteKit, Drizzle ORM, and PostgreSQL. + +## Prerequisites + +- [Bun](https://bun.sh/) +- PostgreSQL database + +## Local Development + +```bash +# Install dependencies +bun install + +# Copy environment file +cp .env.example .env + +# Edit .env with your DATABASE_URL +# DATABASE_URL=postgresql://username:password@localhost:5432/wishlist + +# Set up database +bun run db:push + +# Start development server +bun run dev +``` + +Visit `http://localhost:5173` + +## Docker + +```bash +docker-compose up -d +docker-compose exec app bun run db:push +``` + +Visit `http://localhost:3000` + +## Database Commands + +- `bun run db:push` - Push schema to database (development) +- `bun run db:generate` - Generate migrations +- `bun run db:migrate` - Run migrations (production) +- `bun run db:studio` - Open Drizzle Studio + +## Key Files + +- `src/lib/server/schema.ts` - Database schema +- `src/lib/server/db.ts` - Database connection +- `src/routes/` - Pages and API endpoints +- `src/auth.ts` - Authentication configuration +- `.env` - Environment variables (copy from `.env.example`) + +## Production Build + +```bash +bun run build +bun run preview +``` + +## License + +AGPL-3.0 - This project may only be used in open source projects. diff --git a/SETUP.md b/SETUP.md new file mode 100644 index 0000000..04d94be --- /dev/null +++ b/SETUP.md @@ -0,0 +1,71 @@ +# Setup Guide + +## Docker (Recommended) + +```bash +docker-compose up -d +docker-compose exec app bun run db:push +``` + +Visit `http://localhost:3000` + +## Local Development + +### 1. Install PostgreSQL + +Choose one: + +**Local PostgreSQL:** +```bash +sudo apt install postgresql +sudo -u postgres createdb wishlist +sudo -u postgres psql +CREATE USER wishlistuser WITH PASSWORD 'password'; +GRANT ALL PRIVILEGES ON DATABASE wishlist TO wishlistuser; +\q +``` + +**Docker PostgreSQL:** +```bash +docker run --name wishlist-postgres \ + -e POSTGRES_DB=wishlist \ + -e POSTGRES_USER=wishlistuser \ + -e POSTGRES_PASSWORD=password \ + -p 5432:5432 \ + -d postgres:16 +``` + +**Hosted:** Supabase, Neon, or Railway + +### 2. Configure + +```bash +cp .env.example .env +# Edit .env with your DATABASE_URL +``` + +### 3. Run + +```bash +bun install +bun run db:push +bun run dev +``` + +Visit `http://localhost:5173` + +## Troubleshooting + +**Connection errors:** +- Check PostgreSQL is running: `sudo systemctl status postgresql` +- Test connection: `psql "postgresql://user:pass@localhost:5432/wishlist"` + +**Port in use:** +```bash +bun run dev -- --port 3000 +``` + +**Schema changes:** +```bash +bun run db:push +``` diff --git a/wishlist-app/bun.lock b/bun.lock similarity index 73% rename from wishlist-app/bun.lock rename to bun.lock index 3d6e5ba..ae85026 100644 --- a/wishlist-app/bun.lock +++ b/bun.lock @@ -5,31 +5,48 @@ "": { "name": "wishlist-app", "dependencies": { + "@auth/core": "^0.34.3", + "@auth/drizzle-adapter": "^1.11.1", + "@auth/sveltekit": "^1.11.1", "@internationalized/date": "^3.10.0", "@paralleldrive/cuid2": "^3.0.4", + "bcrypt": "^6.0.0", "bits-ui": "^2.14.4", "clsx": "^2.1.1", "drizzle-orm": "^0.44.7", + "lucide-svelte": "^0.554.0", "postgres": "^3.4.7", + "svelte-dnd-action": "^0.9.67", "tailwind-merge": "^3.4.0", - "tailwind-variants": "^3.1.1", + "tailwind-variants": "^3.2.2", }, "devDependencies": { + "@lucide/svelte": "^0.544.0", "@sveltejs/adapter-auto": "^7.0.0", "@sveltejs/adapter-node": "^5.4.0", "@sveltejs/kit": "^2.48.5", "@sveltejs/vite-plugin-svelte": "^6.2.1", "@tailwindcss/vite": "^4.1.17", + "@types/bcrypt": "^6.0.0", "drizzle-kit": "^0.31.7", + "patch-package": "^8.0.1", + "postinstall-postinstall": "^2.1.0", "svelte": "^5.43.8", "svelte-check": "^4.3.4", "tailwindcss": "^4.1.17", + "tw-animate-css": "^1.4.0", "typescript": "^5.9.3", "vite": "^7.2.2", }, }, }, "packages": { + "@auth/core": ["@auth/core@0.34.3", "", { "dependencies": { "@panva/hkdf": "^1.1.1", "@types/cookie": "0.6.0", "cookie": "0.6.0", "jose": "^5.1.3", "oauth4webapi": "^2.10.4", "preact": "10.11.3", "preact-render-to-string": "5.2.3" }, "peerDependencies": { "@simplewebauthn/browser": "^9.0.1", "@simplewebauthn/server": "^9.0.2", "nodemailer": "^7" }, "optionalPeers": ["@simplewebauthn/browser", "@simplewebauthn/server", "nodemailer"] }, "sha512-jMjY/S0doZnWYNV90x0jmU3B+UcrsfGYnukxYrRbj0CVvGI/MX3JbHsxSrx2d4mbnXaUsqJmAcDfoQWA6r0lOw=="], + + "@auth/drizzle-adapter": ["@auth/drizzle-adapter@1.11.1", "", { "dependencies": { "@auth/core": "0.41.1" } }, "sha512-cQTvDZqsyF7RPhDm/B6SvqdVP9EzQhy3oM4Muu7fjjmSYFLbSR203E6dH631ZHSKDn2b4WZkfMnjPDzRsPSAeA=="], + + "@auth/sveltekit": ["@auth/sveltekit@1.11.1", "", { "dependencies": { "@auth/core": "0.41.1", "set-cookie-parser": "^2.7.0" }, "peerDependencies": { "@simplewebauthn/browser": "^9.0.1", "@simplewebauthn/server": "^9.0.3", "@sveltejs/kit": "^1.0.0 || ^2.0.0", "nodemailer": "^7.0.7", "svelte": "^3.54.0 || ^4.0.0 || ^5.0.0-0" }, "optionalPeers": ["@simplewebauthn/browser", "@simplewebauthn/server", "nodemailer"] }, "sha512-cWNfXcKrNIVtJYOY1tq7H7m03j89Wg7xrTvOJALu18fZdYulzYCPIAdTw8XSEzOp6KyhOGo7tmW7VtzRNtr/8Q=="], + "@drizzle-team/brocli": ["@drizzle-team/brocli@0.10.2", "", {}, "sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w=="], "@esbuild-kit/core-utils": ["@esbuild-kit/core-utils@3.3.2", "", { "dependencies": { "esbuild": "~0.18.20", "source-map-support": "^0.5.21" } }, "sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ=="], @@ -106,8 +123,12 @@ "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], + "@lucide/svelte": ["@lucide/svelte@0.544.0", "", { "peerDependencies": { "svelte": "^5" } }, "sha512-9f9O6uxng2pLB01sxNySHduJN3HTl5p0HDu4H26VR51vhZfiMzyOMe9Mhof3XAk4l813eTtl+/DYRvGyoRR+yw=="], + "@noble/hashes": ["@noble/hashes@2.0.1", "", {}, "sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw=="], + "@panva/hkdf": ["@panva/hkdf@1.2.1", "", {}, "sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw=="], + "@paralleldrive/cuid2": ["@paralleldrive/cuid2@3.0.4", "", { "dependencies": { "@noble/hashes": "^2.0.1", "bignumber.js": "^9.3.1", "error-causes": "^3.0.2" }, "bin": { "cuid2": "bin/cuid2.js" } }, "sha512-sM6M2PWrByOEpN2QYAdulhEbSZmChwj0e52u4hpwB7u4PznFiNAavtE6m7O8tWUlzX+jT2eKKtc5/ZgX+IHrtg=="], "@polka/url": ["@polka/url@1.0.0-next.29", "", {}, "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww=="], @@ -210,36 +231,66 @@ "@tailwindcss/vite": ["@tailwindcss/vite@4.1.17", "", { "dependencies": { "@tailwindcss/node": "4.1.17", "@tailwindcss/oxide": "4.1.17", "tailwindcss": "4.1.17" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7" } }, "sha512-4+9w8ZHOiGnpcGI6z1TVVfWaX/koK7fKeSYF3qlYg2xpBtbteP2ddBxiarL+HVgfSJGeK5RIxRQmKm4rTJJAwA=="], + "@types/bcrypt": ["@types/bcrypt@6.0.0", "", { "dependencies": { "@types/node": "*" } }, "sha512-/oJGukuH3D2+D+3H4JWLaAsJ/ji86dhRidzZ/Od7H/i8g+aCmvkeCc6Ni/f9uxGLSQVCRZkX2/lqEFG2BvWtlQ=="], + "@types/cookie": ["@types/cookie@0.6.0", "", {}, "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA=="], "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], + "@types/node": ["@types/node@24.10.1", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ=="], + "@types/resolve": ["@types/resolve@1.20.2", "", {}, "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q=="], + "@yarnpkg/lockfile": ["@yarnpkg/lockfile@1.1.0", "", {}, "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ=="], + "acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="], + "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + "aria-query": ["aria-query@5.3.2", "", {}, "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw=="], "axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="], + "bcrypt": ["bcrypt@6.0.0", "", { "dependencies": { "node-addon-api": "^8.3.0", "node-gyp-build": "^4.8.4" } }, "sha512-cU8v/EGSrnH+HnxV2z0J7/blxH8gq7Xh2JFT6Aroax7UohdmiJJlxApMxtKfuI7z68NvvVcmR78k2LbT6efhRg=="], + "bignumber.js": ["bignumber.js@9.3.1", "", {}, "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ=="], "bits-ui": ["bits-ui@2.14.4", "", { "dependencies": { "@floating-ui/core": "^1.7.1", "@floating-ui/dom": "^1.7.1", "esm-env": "^1.1.2", "runed": "^0.35.1", "svelte-toolbelt": "^0.10.6", "tabbable": "^6.2.0" }, "peerDependencies": { "@internationalized/date": "^3.8.1", "svelte": "^5.33.0" } }, "sha512-W6kenhnbd/YVvur+DKkaVJ6GldE53eLewur5AhUCqslYQ0vjZr8eWlOfwZnMiPB+PF5HMVqf61vXBvmyrAmPWg=="], + "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], + "buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="], + "call-bind": ["call-bind@1.0.8", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.0", "es-define-property": "^1.0.0", "get-intrinsic": "^1.2.4", "set-function-length": "^1.2.2" } }, "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww=="], + + "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], + + "call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="], + + "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + "chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="], + "ci-info": ["ci-info@3.9.0", "", {}, "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ=="], + "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="], + "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], + + "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], + "commondir": ["commondir@1.0.1", "", {}, "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg=="], "cookie": ["cookie@0.6.0", "", {}, "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw=="], + "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], + "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], "deepmerge": ["deepmerge@4.3.1", "", {}, "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A=="], + "define-data-property": ["define-data-property@1.1.4", "", { "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", "gopd": "^1.0.1" } }, "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A=="], + "dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="], "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], @@ -250,10 +301,18 @@ "drizzle-orm": ["drizzle-orm@0.44.7", "", { "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=4", "@electric-sql/pglite": ">=0.2.0", "@libsql/client": ">=0.10.0", "@libsql/client-wasm": ">=0.10.0", "@neondatabase/serverless": ">=0.10.0", "@op-engineering/op-sqlite": ">=2", "@opentelemetry/api": "^1.4.1", "@planetscale/database": ">=1.13", "@prisma/client": "*", "@tidbcloud/serverless": "*", "@types/better-sqlite3": "*", "@types/pg": "*", "@types/sql.js": "*", "@upstash/redis": ">=1.34.7", "@vercel/postgres": ">=0.8.0", "@xata.io/client": "*", "better-sqlite3": ">=7", "bun-types": "*", "expo-sqlite": ">=14.0.0", "gel": ">=2", "knex": "*", "kysely": "*", "mysql2": ">=2", "pg": ">=8", "postgres": ">=3", "sql.js": ">=1", "sqlite3": ">=5" }, "optionalPeers": ["@aws-sdk/client-rds-data", "@cloudflare/workers-types", "@electric-sql/pglite", "@libsql/client", "@libsql/client-wasm", "@neondatabase/serverless", "@op-engineering/op-sqlite", "@opentelemetry/api", "@planetscale/database", "@prisma/client", "@tidbcloud/serverless", "@types/better-sqlite3", "@types/pg", "@types/sql.js", "@upstash/redis", "@vercel/postgres", "@xata.io/client", "better-sqlite3", "bun-types", "expo-sqlite", "gel", "knex", "kysely", "mysql2", "pg", "postgres", "sql.js", "sqlite3"] }, "sha512-quIpnYznjU9lHshEOAYLoZ9s3jweleHlZIAWR/jX9gAWNg/JhQ1wj0KGRf7/Zm+obRrYd9GjPVJg790QY9N5AQ=="], + "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], + "enhanced-resolve": ["enhanced-resolve@5.18.3", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" } }, "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww=="], "error-causes": ["error-causes@3.0.2", "", {}, "sha512-i0B8zq1dHL6mM85FGoxaJnVtx6LD5nL2v0hlpGdntg5FOSyzQ46c9lmz5qx0xRS2+PWHGOHcYxGIBC5Le2dRMw=="], + "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], + + "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], + + "es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="], + "esbuild": ["esbuild@0.25.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.12", "@esbuild/android-arm": "0.25.12", "@esbuild/android-arm64": "0.25.12", "@esbuild/android-x64": "0.25.12", "@esbuild/darwin-arm64": "0.25.12", "@esbuild/darwin-x64": "0.25.12", "@esbuild/freebsd-arm64": "0.25.12", "@esbuild/freebsd-x64": "0.25.12", "@esbuild/linux-arm": "0.25.12", "@esbuild/linux-arm64": "0.25.12", "@esbuild/linux-ia32": "0.25.12", "@esbuild/linux-loong64": "0.25.12", "@esbuild/linux-mips64el": "0.25.12", "@esbuild/linux-ppc64": "0.25.12", "@esbuild/linux-riscv64": "0.25.12", "@esbuild/linux-s390x": "0.25.12", "@esbuild/linux-x64": "0.25.12", "@esbuild/netbsd-arm64": "0.25.12", "@esbuild/netbsd-x64": "0.25.12", "@esbuild/openbsd-arm64": "0.25.12", "@esbuild/openbsd-x64": "0.25.12", "@esbuild/openharmony-arm64": "0.25.12", "@esbuild/sunos-x64": "0.25.12", "@esbuild/win32-arm64": "0.25.12", "@esbuild/win32-ia32": "0.25.12", "@esbuild/win32-x64": "0.25.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="], "esbuild-register": ["esbuild-register@3.6.0", "", { "dependencies": { "debug": "^4.3.4" }, "peerDependencies": { "esbuild": ">=0.12 <1" } }, "sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg=="], @@ -266,26 +325,64 @@ "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], + "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], + + "find-yarn-workspace-root": ["find-yarn-workspace-root@2.0.0", "", { "dependencies": { "micromatch": "^4.0.2" } }, "sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ=="], + + "fs-extra": ["fs-extra@10.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ=="], + "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], + "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], + + "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], + "get-tsconfig": ["get-tsconfig@4.13.0", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ=="], + "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], + "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], + "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], + + "has-property-descriptors": ["has-property-descriptors@1.0.2", "", { "dependencies": { "es-define-property": "^1.0.0" } }, "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg=="], + + "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], + "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], "inline-style-parser": ["inline-style-parser@0.2.7", "", {}, "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA=="], "is-core-module": ["is-core-module@2.16.1", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w=="], + "is-docker": ["is-docker@2.2.1", "", { "bin": { "is-docker": "cli.js" } }, "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ=="], + "is-module": ["is-module@1.0.0", "", {}, "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g=="], + "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], + "is-reference": ["is-reference@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.6" } }, "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw=="], + "is-wsl": ["is-wsl@2.2.0", "", { "dependencies": { "is-docker": "^2.0.0" } }, "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww=="], + + "isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="], + + "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + "jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="], + "jose": ["jose@5.10.0", "", {}, "sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg=="], + + "json-stable-stringify": ["json-stable-stringify@1.3.0", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.4", "isarray": "^2.0.5", "jsonify": "^0.0.1", "object-keys": "^1.1.1" } }, "sha512-qtYiSSFlwot9XHtF9bD9c7rwKjr+RecWT//ZnPvSmEjpV5mmPOCN4j8UjY5hbjNkOwZ/jQv3J6R1/pL7RwgMsg=="], + + "jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="], + + "jsonify": ["jsonify@0.0.1", "", {}, "sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg=="], + + "klaw-sync": ["klaw-sync@6.0.0", "", { "dependencies": { "graceful-fs": "^4.1.11" } }, "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ=="], + "kleur": ["kleur@4.1.5", "", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="], "lightningcss": ["lightningcss@1.30.2", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.30.2", "lightningcss-darwin-arm64": "1.30.2", "lightningcss-darwin-x64": "1.30.2", "lightningcss-freebsd-x64": "1.30.2", "lightningcss-linux-arm-gnueabihf": "1.30.2", "lightningcss-linux-arm64-gnu": "1.30.2", "lightningcss-linux-arm64-musl": "1.30.2", "lightningcss-linux-x64-gnu": "1.30.2", "lightningcss-linux-x64-musl": "1.30.2", "lightningcss-win32-arm64-msvc": "1.30.2", "lightningcss-win32-x64-msvc": "1.30.2" } }, "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ=="], @@ -314,10 +411,18 @@ "locate-character": ["locate-character@3.0.0", "", {}, "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA=="], + "lucide-svelte": ["lucide-svelte@0.554.0", "", { "peerDependencies": { "svelte": "^3 || ^4 || ^5.0.0-next.42" } }, "sha512-LLcpHi3SuKup0nVD1kKqo8FDZnjXJp48uST26GGh8Jcyrxqk5gmgpnvKmHsHox674UL3cPS1DCul/wFL7ybGqg=="], + "lz-string": ["lz-string@1.5.0", "", { "bin": { "lz-string": "bin/bin.js" } }, "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ=="], "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], + "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], + + "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], + + "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], + "mri": ["mri@1.2.0", "", {}, "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA=="], "mrmime": ["mrmime@2.0.1", "", {}, "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ=="], @@ -326,6 +431,20 @@ "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], + "node-addon-api": ["node-addon-api@8.5.0", "", {}, "sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A=="], + + "node-gyp-build": ["node-gyp-build@4.8.4", "", { "bin": { "node-gyp-build": "bin.js", "node-gyp-build-optional": "optional.js", "node-gyp-build-test": "build-test.js" } }, "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ=="], + + "oauth4webapi": ["oauth4webapi@2.17.0", "", {}, "sha512-lbC0Z7uzAFNFyzEYRIC+pkSVvDHJTbEW+dYlSBAlCYDe6RxUkJ26bClhk8ocBZip1wfI9uKTe0fm4Ib4RHn6uQ=="], + + "object-keys": ["object-keys@1.1.1", "", {}, "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="], + + "open": ["open@7.4.2", "", { "dependencies": { "is-docker": "^2.0.0", "is-wsl": "^2.1.1" } }, "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q=="], + + "patch-package": ["patch-package@8.0.1", "", { "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" } }, "sha512-VsKRIA8f5uqHQ7NGhwIna6Bx6D9s/1iXlA1hthBVBEbkq+t4kXD0HHt+rJhf/Z+Ci0F/HCB2hvn0qLdLG+Qxlw=="], + + "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], + "path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="], "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], @@ -336,6 +455,14 @@ "postgres": ["postgres@3.4.7", "", {}, "sha512-Jtc2612XINuBjIl/QTWsV5UvE8UHuNblcO3vVADSrKsrc6RqGX6lOW1cEo3CM2v0XG4Nat8nI+YM7/f26VxXLw=="], + "postinstall-postinstall": ["postinstall-postinstall@2.1.0", "", {}, "sha512-7hQX6ZlZXIoRiWNrbMQaLzUUfH+sSx39u8EJ9HYuDc1kLo9IXKWjM5RSquZN1ad5GnH8CGFM78fsAAQi3OKEEQ=="], + + "preact": ["preact@10.11.3", "", {}, "sha512-eY93IVpod/zG3uMF22Unl8h9KkrcKIRs2EGar8hwLZZDU1lkjph303V9HZBwufh2s736U6VXuhD109LYqPoffg=="], + + "preact-render-to-string": ["preact-render-to-string@5.2.3", "", { "dependencies": { "pretty-format": "^3.8.0" }, "peerDependencies": { "preact": ">=10" } }, "sha512-aPDxUn5o3GhWdtJtW0svRC2SS/l8D9MAgo2+AWml+BhDImb27ALf04Q2d+AHqUUOc6RdSXFIBVa2gxzgMKgtZA=="], + + "pretty-format": ["pretty-format@3.8.0", "", {}, "sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew=="], + "readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="], "resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="], @@ -348,10 +475,20 @@ "sade": ["sade@1.8.1", "", { "dependencies": { "mri": "^1.1.0" } }, "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A=="], + "semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], + "set-cookie-parser": ["set-cookie-parser@2.7.2", "", {}, "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw=="], + "set-function-length": ["set-function-length@1.2.2", "", { "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", "gopd": "^1.0.1", "has-property-descriptors": "^1.0.2" } }, "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg=="], + + "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], + + "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], + "sirv": ["sirv@3.0.2", "", { "dependencies": { "@polka/url": "^1.0.0-next.24", "mrmime": "^2.0.0", "totalist": "^3.0.0" } }, "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g=="], + "slash": ["slash@2.0.0", "", {}, "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A=="], + "source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], @@ -360,19 +497,23 @@ "style-to-object": ["style-to-object@1.0.14", "", { "dependencies": { "inline-style-parser": "0.2.7" } }, "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw=="], + "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], + "supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="], "svelte": ["svelte@5.43.14", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "@jridgewell/sourcemap-codec": "^1.5.0", "@sveltejs/acorn-typescript": "^1.0.5", "@types/estree": "^1.0.5", "acorn": "^8.12.1", "aria-query": "^5.3.1", "axobject-query": "^4.1.0", "clsx": "^2.1.1", "esm-env": "^1.2.1", "esrap": "^2.1.0", "is-reference": "^3.0.3", "locate-character": "^3.0.0", "magic-string": "^0.30.11", "zimmerframe": "^1.1.2" } }, "sha512-pHeUrp1A5S6RGaXhJB7PtYjL1VVjbVrJ2EfuAoPu9/1LeoMaJa/pcdCsCSb0gS4eUHAHnhCbUDxORZyvGK6kOQ=="], "svelte-check": ["svelte-check@4.3.4", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", "chokidar": "^4.0.1", "fdir": "^6.2.0", "picocolors": "^1.0.0", "sade": "^1.7.4" }, "peerDependencies": { "svelte": "^4.0.0 || ^5.0.0-next.0", "typescript": ">=5.0.0" }, "bin": { "svelte-check": "bin/svelte-check" } }, "sha512-DVWvxhBrDsd+0hHWKfjP99lsSXASeOhHJYyuKOFYJcP7ThfSCKgjVarE8XfuMWpS5JV3AlDf+iK1YGGo2TACdw=="], + "svelte-dnd-action": ["svelte-dnd-action@0.9.67", "", { "peerDependencies": { "svelte": ">=3.23.0 || ^5.0.0-next.0" } }, "sha512-yEJQZ9SFy3O4mnOdtjwWyotRsWRktNf4W8k67zgiLiMtMNQnwCyJHBjkGMgZMDh8EGZ4gr88l+GebBWoHDwo+g=="], + "svelte-toolbelt": ["svelte-toolbelt@0.10.6", "", { "dependencies": { "clsx": "^2.1.1", "runed": "^0.35.1", "style-to-object": "^1.0.8" }, "peerDependencies": { "svelte": "^5.30.2" } }, "sha512-YWuX+RE+CnWYx09yseAe4ZVMM7e7GRFZM6OYWpBKOb++s+SQ8RBIMMe+Bs/CznBMc0QPLjr+vDBxTAkozXsFXQ=="], "tabbable": ["tabbable@6.3.0", "", {}, "sha512-EIHvdY5bPLuWForiR/AN2Bxngzpuwn1is4asboytXtpTgsArc+WmSJKVLlhdh71u7jFcryDqB2A8lQvj78MkyQ=="], "tailwind-merge": ["tailwind-merge@3.4.0", "", {}, "sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g=="], - "tailwind-variants": ["tailwind-variants@3.1.1", "", { "peerDependencies": { "tailwind-merge": ">=3.0.0", "tailwindcss": "*" }, "optionalPeers": ["tailwind-merge"] }, "sha512-ftLXe3krnqkMHsuBTEmaVUXYovXtPyTK7ckEfDRXS8PBZx0bAUas+A0jYxuKA5b8qg++wvQ3d2MQ7l/xeZxbZQ=="], + "tailwind-variants": ["tailwind-variants@3.2.2", "", { "peerDependencies": { "tailwind-merge": ">=3.0.0", "tailwindcss": "*" }, "optionalPeers": ["tailwind-merge"] }, "sha512-Mi4kHeMTLvKlM98XPnK+7HoBPmf4gygdFmqQPaDivc3DpYS6aIY6KiG/PgThrGvii5YZJqRsPz0aPyhoFzmZgg=="], "tailwindcss": ["tailwindcss@4.1.17", "", {}, "sha512-j9Ee2YjuQqYT9bbRTfTZht9W/ytp5H+jJpZKiYdP/bpnXARAuELt9ofP0lPnmHjbga7SNQIxdTAXCmtKVYjN+Q=="], @@ -380,18 +521,36 @@ "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="], + "tmp": ["tmp@0.2.5", "", {}, "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow=="], + + "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], + "totalist": ["totalist@3.0.1", "", {}, "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ=="], "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + "tw-animate-css": ["tw-animate-css@1.4.0", "", {}, "sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ=="], + "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], + "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + + "universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="], + "vite": ["vite@7.2.4", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-NL8jTlbo0Tn4dUEXEsUg8KeyG/Lkmc4Fnzb8JXN/Ykm9G4HNImjtABMJgkQoVjOBN/j2WAwDTRytdqJbZsah7w=="], "vitefu": ["vitefu@1.1.1", "", { "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0" }, "optionalPeers": ["vite"] }, "sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ=="], + "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + + "yaml": ["yaml@2.8.1", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw=="], + "zimmerframe": ["zimmerframe@1.1.4", "", {}, "sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ=="], + "@auth/drizzle-adapter/@auth/core": ["@auth/core@0.41.1", "", { "dependencies": { "@panva/hkdf": "^1.2.1", "jose": "^6.0.6", "oauth4webapi": "^3.3.0", "preact": "10.24.3", "preact-render-to-string": "6.5.11" }, "peerDependencies": { "@simplewebauthn/browser": "^9.0.1", "@simplewebauthn/server": "^9.0.2", "nodemailer": "^7.0.7" }, "optionalPeers": ["@simplewebauthn/browser", "@simplewebauthn/server", "nodemailer"] }, "sha512-t9cJ2zNYAdWMacGRMT6+r4xr1uybIdmYa49calBPeTqwgAFPV/88ac9TEvCR85pvATiSPt8VaNf+Gt24JIT/uw=="], + + "@auth/sveltekit/@auth/core": ["@auth/core@0.41.1", "", { "dependencies": { "@panva/hkdf": "^1.2.1", "jose": "^6.0.6", "oauth4webapi": "^3.3.0", "preact": "10.24.3", "preact-render-to-string": "6.5.11" }, "peerDependencies": { "@simplewebauthn/browser": "^9.0.1", "@simplewebauthn/server": "^9.0.2", "nodemailer": "^7.0.7" }, "optionalPeers": ["@simplewebauthn/browser", "@simplewebauthn/server", "nodemailer"] }, "sha512-t9cJ2zNYAdWMacGRMT6+r4xr1uybIdmYa49calBPeTqwgAFPV/88ac9TEvCR85pvATiSPt8VaNf+Gt24JIT/uw=="], + "@esbuild-kit/core-utils/esbuild": ["esbuild@0.18.20", "", { "optionalDependencies": { "@esbuild/android-arm": "0.18.20", "@esbuild/android-arm64": "0.18.20", "@esbuild/android-x64": "0.18.20", "@esbuild/darwin-arm64": "0.18.20", "@esbuild/darwin-x64": "0.18.20", "@esbuild/freebsd-arm64": "0.18.20", "@esbuild/freebsd-x64": "0.18.20", "@esbuild/linux-arm": "0.18.20", "@esbuild/linux-arm64": "0.18.20", "@esbuild/linux-ia32": "0.18.20", "@esbuild/linux-loong64": "0.18.20", "@esbuild/linux-mips64el": "0.18.20", "@esbuild/linux-ppc64": "0.18.20", "@esbuild/linux-riscv64": "0.18.20", "@esbuild/linux-s390x": "0.18.20", "@esbuild/linux-x64": "0.18.20", "@esbuild/netbsd-x64": "0.18.20", "@esbuild/openbsd-x64": "0.18.20", "@esbuild/sunos-x64": "0.18.20", "@esbuild/win32-arm64": "0.18.20", "@esbuild/win32-ia32": "0.18.20", "@esbuild/win32-x64": "0.18.20" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA=="], "@rollup/plugin-commonjs/is-reference": ["is-reference@1.2.1", "", { "dependencies": { "@types/estree": "*" } }, "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ=="], @@ -408,6 +567,24 @@ "@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + + "@auth/drizzle-adapter/@auth/core/jose": ["jose@6.1.2", "", {}, "sha512-MpcPtHLE5EmztuFIqB0vzHAWJPpmN1E6L4oo+kze56LIs3MyXIj9ZHMDxqOvkP38gBR7K1v3jqd4WU2+nrfONQ=="], + + "@auth/drizzle-adapter/@auth/core/oauth4webapi": ["oauth4webapi@3.8.3", "", {}, "sha512-pQ5BsX3QRTgnt5HxgHwgunIRaDXBdkT23tf8dfzmtTIL2LTpdmxgbpbBm0VgFWAIDlezQvQCTgnVIUmHupXHxw=="], + + "@auth/drizzle-adapter/@auth/core/preact": ["preact@10.24.3", "", {}, "sha512-Z2dPnBnMUfyQfSQ+GBdsGa16hz35YmLmtTLhM169uW944hYL6xzTYkJjC07j+Wosz733pMWx0fgON3JNw1jJQA=="], + + "@auth/drizzle-adapter/@auth/core/preact-render-to-string": ["preact-render-to-string@6.5.11", "", { "peerDependencies": { "preact": ">=10" } }, "sha512-ubnauqoGczeGISiOh6RjX0/cdaF8v/oDXIjO85XALCQjwQP+SB4RDXXtvZ6yTYSjG+PC1QRP2AhPgCEsM2EvUw=="], + + "@auth/sveltekit/@auth/core/jose": ["jose@6.1.2", "", {}, "sha512-MpcPtHLE5EmztuFIqB0vzHAWJPpmN1E6L4oo+kze56LIs3MyXIj9ZHMDxqOvkP38gBR7K1v3jqd4WU2+nrfONQ=="], + + "@auth/sveltekit/@auth/core/oauth4webapi": ["oauth4webapi@3.8.3", "", {}, "sha512-pQ5BsX3QRTgnt5HxgHwgunIRaDXBdkT23tf8dfzmtTIL2LTpdmxgbpbBm0VgFWAIDlezQvQCTgnVIUmHupXHxw=="], + + "@auth/sveltekit/@auth/core/preact": ["preact@10.24.3", "", {}, "sha512-Z2dPnBnMUfyQfSQ+GBdsGa16hz35YmLmtTLhM169uW944hYL6xzTYkJjC07j+Wosz733pMWx0fgON3JNw1jJQA=="], + + "@auth/sveltekit/@auth/core/preact-render-to-string": ["preact-render-to-string@6.5.11", "", { "peerDependencies": { "preact": ">=10" } }, "sha512-ubnauqoGczeGISiOh6RjX0/cdaF8v/oDXIjO85XALCQjwQP+SB4RDXXtvZ6yTYSjG+PC1QRP2AhPgCEsM2EvUw=="], + "@esbuild-kit/core-utils/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.18.20", "", { "os": "android", "cpu": "arm" }, "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw=="], "@esbuild-kit/core-utils/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.18.20", "", { "os": "android", "cpu": "arm64" }, "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ=="], diff --git a/components.json b/components.json new file mode 100644 index 0000000..c5d91b4 --- /dev/null +++ b/components.json @@ -0,0 +1,16 @@ +{ + "$schema": "https://shadcn-svelte.com/schema.json", + "tailwind": { + "css": "src/app.css", + "baseColor": "slate" + }, + "aliases": { + "components": "$lib/components", + "utils": "$lib/utils", + "ui": "$lib/components/ui", + "hooks": "$lib/hooks", + "lib": "$lib" + }, + "typescript": true, + "registry": "https://shadcn-svelte.com/registry" +} diff --git a/docker-compose.coolify.yml b/docker-compose.coolify.yml new file mode 100644 index 0000000..4f3c2ef --- /dev/null +++ b/docker-compose.coolify.yml @@ -0,0 +1,52 @@ +# Coolify-optimized Docker Compose +# Includes both app and database - database is only exposed internally + +services: + db: + image: postgres:16-alpine + environment: + POSTGRES_USER: ${POSTGRES_USER:-wishlistuser} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-wishlistpassword} + POSTGRES_DB: ${POSTGRES_DB:-wishlist} + volumes: + - postgres_data:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-wishlistuser} -d ${POSTGRES_DB:-wishlist}"] + interval: 10s + timeout: 5s + retries: 5 + restart: unless-stopped + # NOTE: No ports exposed - only accessible internally by app service + + app: + build: + context: . + dockerfile: Dockerfile + environment: + # Coolify will inject these from Environment Variables + DATABASE_URL: postgresql://${POSTGRES_USER:-wishlistuser}:${POSTGRES_PASSWORD:-wishlistpassword}@db:5432/${POSTGRES_DB:-wishlist} + NODE_ENV: production + PORT: 3000 + AUTH_SECRET: ${AUTH_SECRET} + AUTH_URL: ${AUTH_URL:-https://wish.rasmusq.com} + AUTH_TRUST_HOST: ${AUTH_TRUST_HOST:-true} + GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-} + GOOGLE_CLIENT_SECRET: ${GOOGLE_CLIENT_SECRET:-} + depends_on: + db: + condition: service_healthy + restart: unless-stopped + labels: + - traefik.enable=true + - traefik.http.routers.wishlist.rule=Host(`wish.rasmusq.com`) + - traefik.http.routers.wishlist.entryPoints=https + - traefik.http.routers.wishlist.tls=true + - traefik.http.routers.wishlist.tls.certresolver=letsencrypt + - traefik.http.services.wishlist.loadbalancer.server.port=3000 + # Forward headers for Auth.js behind reverse proxy + - traefik.http.middlewares.wishlist-headers.headers.customrequestheaders.X-Forwarded-Proto=https + - traefik.http.middlewares.wishlist-headers.headers.customrequestheaders.X-Forwarded-Host=wish.rasmusq.com + - traefik.http.routers.wishlist.middlewares=wishlist-headers + +volumes: + postgres_data: diff --git a/wishlist-app/docker-compose.yml b/docker-compose.yml similarity index 77% rename from wishlist-app/docker-compose.yml rename to docker-compose.yml index 5bbded6..e9358a8 100644 --- a/wishlist-app/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,3 @@ -version: '3.8' - services: db: image: postgres:16-alpine @@ -27,6 +25,11 @@ services: DATABASE_URL: postgresql://wishlistuser:wishlistpassword@db:5432/wishlist NODE_ENV: production PORT: 3000 + AUTH_SECRET: ${AUTH_SECRET:-change-me-in-production} + AUTH_URL: ${AUTH_URL:-http://localhost:3000} + AUTH_TRUST_HOST: true + GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-} + GOOGLE_CLIENT_SECRET: ${GOOGLE_CLIENT_SECRET:-} ports: - "3000:3000" depends_on: diff --git a/wishlist-app/drizzle.config.ts b/drizzle.config.ts similarity index 100% rename from wishlist-app/drizzle.config.ts rename to drizzle.config.ts diff --git a/wishlist-app/drizzle/meta/0000_snapshot.json b/drizzle/meta/0000_snapshot.json similarity index 100% rename from wishlist-app/drizzle/meta/0000_snapshot.json rename to drizzle/meta/0000_snapshot.json diff --git a/drizzle/meta/0001_snapshot.json b/drizzle/meta/0001_snapshot.json new file mode 100644 index 0000000..39dcd62 --- /dev/null +++ b/drizzle/meta/0001_snapshot.json @@ -0,0 +1,593 @@ +{ + "id": "d5cb75d0-dd76-4feb-87ce-6b2e8b3aaae1", + "prevId": "94fab923-b1d4-447e-b367-5ee7b7894b14", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.account": { + "name": "account", + "schema": "", + "columns": { + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "providerAccountId": { + "name": "providerAccountId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "numeric", + "primaryKey": false, + "notNull": false + }, + "token_type": { + "name": "token_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "session_state": { + "name": "session_state", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "account_userId_user_id_fk": { + "name": "account_userId_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "account_provider_providerAccountId_pk": { + "name": "account_provider_providerAccountId_pk", + "columns": [ + "provider", + "providerAccountId" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.items": { + "name": "items", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "wishlist_id": { + "name": "wishlist_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "link": { + "name": "link", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "image_url": { + "name": "image_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "price": { + "name": "price", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": false + }, + "currency": { + "name": "currency", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'DKK'" + }, + "priority": { + "name": "priority", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'medium'" + }, + "is_reserved": { + "name": "is_reserved", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "items_wishlist_id_wishlists_id_fk": { + "name": "items_wishlist_id_wishlists_id_fk", + "tableFrom": "items", + "tableTo": "wishlists", + "columnsFrom": [ + "wishlist_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.reservations": { + "name": "reservations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "item_id": { + "name": "item_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "reserver_name": { + "name": "reserver_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "reservations_item_id_items_id_fk": { + "name": "reservations_item_id_items_id_fk", + "tableFrom": "reservations", + "tableTo": "items", + "columnsFrom": [ + "item_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.saved_wishlists": { + "name": "saved_wishlists", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "wishlist_id": { + "name": "wishlist_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "nickname": { + "name": "nickname", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "saved_wishlists_user_id_user_id_fk": { + "name": "saved_wishlists_user_id_user_id_fk", + "tableFrom": "saved_wishlists", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "saved_wishlists_wishlist_id_wishlists_id_fk": { + "name": "saved_wishlists_wishlist_id_wishlists_id_fk", + "tableFrom": "saved_wishlists", + "tableTo": "wishlists", + "columnsFrom": [ + "wishlist_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.session": { + "name": "session", + "schema": "", + "columns": { + "sessionToken": { + "name": "sessionToken", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "session_userId_user_id_fk": { + "name": "session_userId_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user": { + "name": "user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "emailVerified": { + "name": "emailVerified", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_email_unique": { + "name": "user_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + }, + "user_username_unique": { + "name": "user_username_unique", + "nullsNotDistinct": false, + "columns": [ + "username" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.verificationToken": { + "name": "verificationToken", + "schema": "", + "columns": { + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "verificationToken_identifier_token_pk": { + "name": "verificationToken_identifier_token_pk", + "columns": [ + "identifier", + "token" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.wishlists": { + "name": "wishlists", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "owner_token": { + "name": "owner_token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "public_token": { + "name": "public_token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "wishlists_user_id_user_id_fk": { + "name": "wishlists_user_id_user_id_fk", + "tableFrom": "wishlists", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "wishlists_owner_token_unique": { + "name": "wishlists_owner_token_unique", + "nullsNotDistinct": false, + "columns": [ + "owner_token" + ] + }, + "wishlists_public_token_unique": { + "name": "wishlists_public_token_unique", + "nullsNotDistinct": false, + "columns": [ + "public_token" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": {}, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/drizzle/meta/0002_snapshot.json b/drizzle/meta/0002_snapshot.json new file mode 100644 index 0000000..123ee9b --- /dev/null +++ b/drizzle/meta/0002_snapshot.json @@ -0,0 +1,593 @@ +{ + "id": "381bf3dc-4cb0-4cd9-a269-fc90409921ee", + "prevId": "d5cb75d0-dd76-4feb-87ce-6b2e8b3aaae1", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.account": { + "name": "account", + "schema": "", + "columns": { + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "providerAccountId": { + "name": "providerAccountId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "numeric", + "primaryKey": false, + "notNull": false + }, + "token_type": { + "name": "token_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "session_state": { + "name": "session_state", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "account_userId_user_id_fk": { + "name": "account_userId_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "account_provider_providerAccountId_pk": { + "name": "account_provider_providerAccountId_pk", + "columns": [ + "provider", + "providerAccountId" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.items": { + "name": "items", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "wishlist_id": { + "name": "wishlist_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "link": { + "name": "link", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "image_url": { + "name": "image_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "price": { + "name": "price", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": false + }, + "currency": { + "name": "currency", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'DKK'" + }, + "priority": { + "name": "priority", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'medium'" + }, + "is_reserved": { + "name": "is_reserved", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "items_wishlist_id_wishlists_id_fk": { + "name": "items_wishlist_id_wishlists_id_fk", + "tableFrom": "items", + "tableTo": "wishlists", + "columnsFrom": [ + "wishlist_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.reservations": { + "name": "reservations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "item_id": { + "name": "item_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "reserver_name": { + "name": "reserver_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "reservations_item_id_items_id_fk": { + "name": "reservations_item_id_items_id_fk", + "tableFrom": "reservations", + "tableTo": "items", + "columnsFrom": [ + "item_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.saved_wishlists": { + "name": "saved_wishlists", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "wishlist_id": { + "name": "wishlist_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "nickname": { + "name": "nickname", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "saved_wishlists_user_id_user_id_fk": { + "name": "saved_wishlists_user_id_user_id_fk", + "tableFrom": "saved_wishlists", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "saved_wishlists_wishlist_id_wishlists_id_fk": { + "name": "saved_wishlists_wishlist_id_wishlists_id_fk", + "tableFrom": "saved_wishlists", + "tableTo": "wishlists", + "columnsFrom": [ + "wishlist_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.session": { + "name": "session", + "schema": "", + "columns": { + "sessionToken": { + "name": "sessionToken", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "session_userId_user_id_fk": { + "name": "session_userId_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user": { + "name": "user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "emailVerified": { + "name": "emailVerified", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_email_unique": { + "name": "user_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + }, + "user_username_unique": { + "name": "user_username_unique", + "nullsNotDistinct": false, + "columns": [ + "username" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.verificationToken": { + "name": "verificationToken", + "schema": "", + "columns": { + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "verificationToken_identifier_token_pk": { + "name": "verificationToken_identifier_token_pk", + "columns": [ + "identifier", + "token" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.wishlists": { + "name": "wishlists", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "owner_token": { + "name": "owner_token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "public_token": { + "name": "public_token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "wishlists_user_id_user_id_fk": { + "name": "wishlists_user_id_user_id_fk", + "tableFrom": "wishlists", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "wishlists_owner_token_unique": { + "name": "wishlists_owner_token_unique", + "nullsNotDistinct": false, + "columns": [ + "owner_token" + ] + }, + "wishlists_public_token_unique": { + "name": "wishlists_public_token_unique", + "nullsNotDistinct": false, + "columns": [ + "public_token" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": {}, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json new file mode 100644 index 0000000..f60cbf6 --- /dev/null +++ b/drizzle/meta/_journal.json @@ -0,0 +1,27 @@ +{ + "version": "7", + "dialect": "postgresql", + "entries": [ + { + "idx": 0, + "version": "7", + "when": 1763822218153, + "tag": "0000_last_steve_rogers", + "breakpoints": true + }, + { + "idx": 1, + "version": "7", + "when": 1763987735422, + "tag": "0001_petite_silver_centurion", + "breakpoints": true + }, + { + "idx": 2, + "version": "7", + "when": 1764006320677, + "tag": "0002_lowly_electro", + "breakpoints": true + } + ] +} \ No newline at end of file diff --git a/wishlist-app/package.json b/package.json similarity index 73% rename from wishlist-app/package.json rename to package.json index 3f6fedb..ddd9c90 100644 --- a/wishlist-app/package.json +++ b/package.json @@ -8,6 +8,7 @@ "build": "vite build", "preview": "vite preview", "prepare": "svelte-kit sync || echo ''", + "postinstall": "patch-package", "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", "db:generate": "drizzle-kit generate", @@ -16,26 +17,37 @@ "db:studio": "drizzle-kit studio" }, "devDependencies": { + "@lucide/svelte": "^0.544.0", "@sveltejs/adapter-auto": "^7.0.0", "@sveltejs/adapter-node": "^5.4.0", "@sveltejs/kit": "^2.48.5", "@sveltejs/vite-plugin-svelte": "^6.2.1", "@tailwindcss/vite": "^4.1.17", + "@types/bcrypt": "^6.0.0", "drizzle-kit": "^0.31.7", + "patch-package": "^8.0.1", + "postinstall-postinstall": "^2.1.0", "svelte": "^5.43.8", "svelte-check": "^4.3.4", "tailwindcss": "^4.1.17", + "tw-animate-css": "^1.4.0", "typescript": "^5.9.3", "vite": "^7.2.2" }, "dependencies": { + "@auth/core": "^0.34.3", + "@auth/drizzle-adapter": "^1.11.1", + "@auth/sveltekit": "^1.11.1", "@internationalized/date": "^3.10.0", "@paralleldrive/cuid2": "^3.0.4", + "bcrypt": "^6.0.0", "bits-ui": "^2.14.4", "clsx": "^2.1.1", "drizzle-orm": "^0.44.7", + "lucide-svelte": "^0.554.0", "postgres": "^3.4.7", + "svelte-dnd-action": "^0.9.67", "tailwind-merge": "^3.4.0", - "tailwind-variants": "^3.1.1" + "tailwind-variants": "^3.2.2" } } diff --git a/patches/@auth+core+0.34.3.patch b/patches/@auth+core+0.34.3.patch new file mode 100644 index 0000000..d3cb08e --- /dev/null +++ b/patches/@auth+core+0.34.3.patch @@ -0,0 +1,18 @@ +diff --git a/node_modules/@auth/core/lib/utils/env.js b/node_modules/@auth/core/lib/utils/env.js +index 1234567..abcdefg 100644 +--- a/node_modules/@auth/core/lib/utils/env.js ++++ b/node_modules/@auth/core/lib/utils/env.js +@@ -44,7 +44,12 @@ export function setEnvDefaults(envObject, config) { + return finalProvider; + }); + } +-export function createActionURL(action, protocol, headers, envObject, basePath) { ++export function createActionURL(action, protocol, headers, envObject, configOrBasePath) { ++ // Fix: Extract basePath from config object if needed ++ const basePath = typeof configOrBasePath === 'object' && configOrBasePath !== null ++ ? configOrBasePath.basePath ++ : configOrBasePath; ++ + let envUrl = envObject.AUTH_URL ?? envObject.NEXTAUTH_URL; + let url; + if (envUrl) { diff --git a/wishlist-app/scripts/docker-migrate.sh b/scripts/docker-migrate.sh similarity index 100% rename from wishlist-app/scripts/docker-migrate.sh rename to scripts/docker-migrate.sh diff --git a/src/app.css b/src/app.css new file mode 100644 index 0000000..2eeb9e0 --- /dev/null +++ b/src/app.css @@ -0,0 +1,129 @@ +@import "tailwindcss"; + +@import "tw-animate-css"; + +@custom-variant dark (&:is(.dark *)); + +* { + transition: + background-color 1s ease, + background-image 1s ease, + color 1s ease, + border-color 1s ease; +} + +:root { + --radius: 0.625rem; + --background: oklch(1 0 0); + --foreground: oklch(0.129 0.042 264.695); + --card: oklch(1 0 0); + --card-foreground: oklch(0.129 0.042 264.695); + --popover: oklch(1 0 0); + --popover-foreground: oklch(0.129 0.042 264.695); + --primary: oklch(0.208 0.042 265.755); + --primary-foreground: oklch(0.984 0.003 247.858); + --secondary: oklch(0.968 0.007 247.896); + --secondary-foreground: oklch(0.208 0.042 265.755); + --muted: oklch(0.968 0.007 247.896); + --muted-foreground: oklch(0.554 0.046 257.417); + --accent: oklch(0.968 0.007 247.896); + --accent-foreground: oklch(0.208 0.042 265.755); + --destructive: oklch(0.577 0.245 27.325); + --border: oklch(0.929 0.013 255.508); + --input: oklch(0.929 0.013 255.508); + --ring: oklch(0.704 0.04 256.788); + --chart-1: oklch(0.646 0.222 41.116); + --chart-2: oklch(0.6 0.118 184.704); + --chart-3: oklch(0.398 0.07 227.392); + --chart-4: oklch(0.828 0.189 84.429); + --chart-5: oklch(0.769 0.188 70.08); + --sidebar: oklch(0.984 0.003 247.858); + --sidebar-foreground: oklch(0.129 0.042 264.695); + --sidebar-primary: oklch(0.208 0.042 265.755); + --sidebar-primary-foreground: oklch(0.984 0.003 247.858); + --sidebar-accent: oklch(0.968 0.007 247.896); + --sidebar-accent-foreground: oklch(0.208 0.042 265.755); + --sidebar-border: oklch(0.929 0.013 255.508); + --sidebar-ring: oklch(0.704 0.04 256.788); +} + +.dark { + --background: oklch(0.129 0.042 264.695); + --foreground: oklch(0.984 0.003 247.858); + --card: oklch(0.208 0.042 265.755); + --card-foreground: oklch(0.984 0.003 247.858); + --popover: oklch(0.208 0.042 265.755); + --popover-foreground: oklch(0.984 0.003 247.858); + --primary: oklch(0.929 0.013 255.508); + --primary-foreground: oklch(0.208 0.042 265.755); + --secondary: oklch(0.279 0.041 260.031); + --secondary-foreground: oklch(0.984 0.003 247.858); + --muted: oklch(0.279 0.041 260.031); + --muted-foreground: oklch(0.704 0.04 256.788); + --accent: oklch(0.279 0.041 260.031); + --accent-foreground: oklch(0.984 0.003 247.858); + --destructive: oklch(0.704 0.191 22.216); + --border: oklch(1 0 0 / 10%); + --input: oklch(1 0 0 / 15%); + --ring: oklch(0.551 0.027 264.364); + --chart-1: oklch(0.488 0.243 264.376); + --chart-2: oklch(0.696 0.17 162.48); + --chart-3: oklch(0.769 0.188 70.08); + --chart-4: oklch(0.627 0.265 303.9); + --chart-5: oklch(0.645 0.246 16.439); + --sidebar: oklch(0.208 0.042 265.755); + --sidebar-foreground: oklch(0.984 0.003 247.858); + --sidebar-primary: oklch(0.488 0.243 264.376); + --sidebar-primary-foreground: oklch(0.984 0.003 247.858); + --sidebar-accent: oklch(0.279 0.041 260.031); + --sidebar-accent-foreground: oklch(0.984 0.003 247.858); + --sidebar-border: oklch(1 0 0 / 10%); + --sidebar-ring: oklch(0.551 0.027 264.364); +} + +@theme inline { + --radius-sm: calc(var(--radius) - 4px); + --radius-md: calc(var(--radius) - 2px); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) + 4px); + --color-background: var(--background); + --color-foreground: var(--foreground); + --color-card: var(--card); + --color-card-foreground: var(--card-foreground); + --color-popover: var(--popover); + --color-popover-foreground: var(--popover-foreground); + --color-primary: var(--primary); + --color-primary-foreground: var(--primary-foreground); + --color-secondary: var(--secondary); + --color-secondary-foreground: var(--secondary-foreground); + --color-muted: var(--muted); + --color-muted-foreground: var(--muted-foreground); + --color-accent: var(--accent); + --color-accent-foreground: var(--accent-foreground); + --color-destructive: var(--destructive); + --color-border: var(--border); + --color-input: var(--input); + --color-ring: var(--ring); + --color-chart-1: var(--chart-1); + --color-chart-2: var(--chart-2); + --color-chart-3: var(--chart-3); + --color-chart-4: var(--chart-4); + --color-chart-5: var(--chart-5); + --color-sidebar: var(--sidebar); + --color-sidebar-foreground: var(--sidebar-foreground); + --color-sidebar-primary: var(--sidebar-primary); + --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); + --color-sidebar-accent: var(--sidebar-accent); + --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); + --color-sidebar-border: var(--sidebar-border); + --color-sidebar-ring: var(--sidebar-ring); +} + +@layer base { + * { + @apply border-border outline-ring/50; + } + body { + @apply bg-background text-foreground; + } +} diff --git a/src/app.d.ts b/src/app.d.ts new file mode 100644 index 0000000..4a0091a --- /dev/null +++ b/src/app.d.ts @@ -0,0 +1,14 @@ +import type { Session } from '@auth/core/types'; + +declare global { + namespace App { + interface Locals { + session: Session | null; + } + interface PageData { + session: Session | null; + } + } +} + +export {}; diff --git a/src/app.html b/src/app.html new file mode 100644 index 0000000..1d315ae --- /dev/null +++ b/src/app.html @@ -0,0 +1,21 @@ + + + + + + + %sveltekit.head% + + +
%sveltekit.body%
+ + diff --git a/src/auth.ts b/src/auth.ts new file mode 100644 index 0000000..4fa6d8f --- /dev/null +++ b/src/auth.ts @@ -0,0 +1,123 @@ +import { SvelteKitAuth } from '@auth/sveltekit'; +import { DrizzleAdapter } from '@auth/drizzle-adapter'; +import Credentials from '@auth/core/providers/credentials'; +import Google from '@auth/core/providers/google'; +import type { OAuthConfig } from '@auth/core/providers'; +import { db } from '$lib/server/db'; +import { users } from '$lib/server/schema'; +import { eq } from 'drizzle-orm'; +import bcrypt from 'bcrypt'; +import { env } from '$env/dynamic/private'; +import type { SvelteKitAuthConfig } from '@auth/sveltekit'; + +function Authentik(config: { + clientId: string; + clientSecret: string; + issuer: string; +}): OAuthConfig { + return { + id: 'authentik', + name: 'Authentik', + type: 'oidc', + clientId: config.clientId, + clientSecret: config.clientSecret, + issuer: config.issuer, + authorization: { + params: { + scope: 'openid email profile' + } + }, + profile(profile) { + return { + id: profile.sub, + email: profile.email, + name: profile.name || profile.preferred_username, + image: profile.picture + }; + } + }; +} + +const authConfig: SvelteKitAuthConfig = { + adapter: DrizzleAdapter(db), + session: { + strategy: 'jwt' + }, + providers: [ + ...(env.GOOGLE_CLIENT_ID && env.GOOGLE_CLIENT_SECRET + ? [ + Google({ + clientId: env.GOOGLE_CLIENT_ID, + clientSecret: env.GOOGLE_CLIENT_SECRET + }) + ] + : []), + ...(env.AUTHENTIK_CLIENT_ID && env.AUTHENTIK_CLIENT_SECRET && env.AUTHENTIK_ISSUER + ? [ + Authentik({ + clientId: env.AUTHENTIK_CLIENT_ID, + clientSecret: env.AUTHENTIK_CLIENT_SECRET, + issuer: env.AUTHENTIK_ISSUER + }) + ] + : []), + Credentials({ + id: 'credentials', + name: 'credentials', + credentials: { + username: { label: 'Username', type: 'text' }, + password: { label: 'Password', type: 'password' } + }, + async authorize(credentials) { + if (!credentials?.username || !credentials?.password) { + return null; + } + + const user = await db.query.users.findFirst({ + where: eq(users.username, credentials.username as string) + }); + + if (!user || !user.password) { + return null; + } + + const isValidPassword = await bcrypt.compare( + credentials.password as string, + user.password + ); + + if (!isValidPassword) { + return null; + } + + return { + id: user.id, + email: user.email || undefined, + name: user.name, + image: user.image + }; + } + }) + ], + pages: { + signIn: '/signin' + }, + callbacks: { + async jwt({ token, user }) { + if (user) { + token.id = user.id; + } + return token; + }, + async session({ session, token }) { + if (token && session.user) { + session.user.id = token.id as string; + } + return session; + } + }, + secret: env.AUTH_SECRET, + trustHost: true +}; + +export const { handle, signIn, signOut } = SvelteKitAuth(authConfig); diff --git a/src/hooks.server.ts b/src/hooks.server.ts new file mode 100644 index 0000000..e6726b0 --- /dev/null +++ b/src/hooks.server.ts @@ -0,0 +1 @@ +export { handle } from './auth'; diff --git a/wishlist-app/src/lib/assets/favicon.svg b/src/lib/assets/favicon.svg similarity index 100% rename from wishlist-app/src/lib/assets/favicon.svg rename to src/lib/assets/favicon.svg diff --git a/src/lib/components/dashboard/WishlistCard.svelte b/src/lib/components/dashboard/WishlistCard.svelte new file mode 100644 index 0000000..a8a6d0a --- /dev/null +++ b/src/lib/components/dashboard/WishlistCard.svelte @@ -0,0 +1,45 @@ + + + + +
+ + {title} + + + {itemCount} item{itemCount === 1 ? '' : 's'} + +
+ {#if description} + {description} + {/if} +
+ + {#if children} +
+ {@render children()} +
+ {/if} +
+
diff --git a/src/lib/components/dashboard/WishlistGrid.svelte b/src/lib/components/dashboard/WishlistGrid.svelte new file mode 100644 index 0000000..41f1494 --- /dev/null +++ b/src/lib/components/dashboard/WishlistGrid.svelte @@ -0,0 +1,79 @@ + + + + +
+
+ {title} + {description} +
+ {#if headerAction} + {@render headerAction()} + {/if} +
+
+ + {#if items && items.length > 0} +
+ {#each items as item (item.id)} +
+ {@render children(item)} +
+ {/each} +
+ {:else} + + {/if} +
+
diff --git a/src/lib/components/layout/DashboardHeader.svelte b/src/lib/components/layout/DashboardHeader.svelte new file mode 100644 index 0000000..2118364 --- /dev/null +++ b/src/lib/components/layout/DashboardHeader.svelte @@ -0,0 +1,18 @@ + + +
+
+

Dashboard

+

Welcome back, {userName || userEmail}

+
+
+ + +
+
diff --git a/src/lib/components/layout/EmptyState.svelte b/src/lib/components/layout/EmptyState.svelte new file mode 100644 index 0000000..81ba088 --- /dev/null +++ b/src/lib/components/layout/EmptyState.svelte @@ -0,0 +1,45 @@ + + +
+

{message}

+ {#if description} +

{description}

+ {/if} + {#if children} +
+ {@render children()} +
+ {:else if actionLabel} + + {/if} +
diff --git a/src/lib/components/layout/Navigation.svelte b/src/lib/components/layout/Navigation.svelte new file mode 100644 index 0000000..3bc7a2c --- /dev/null +++ b/src/lib/components/layout/Navigation.svelte @@ -0,0 +1,34 @@ + + + diff --git a/src/lib/components/layout/PageContainer.svelte b/src/lib/components/layout/PageContainer.svelte new file mode 100644 index 0000000..844e8d0 --- /dev/null +++ b/src/lib/components/layout/PageContainer.svelte @@ -0,0 +1,11 @@ + + +
+
+ {@render children()} +
+
diff --git a/src/lib/components/ui/ColorPicker.svelte b/src/lib/components/ui/ColorPicker.svelte new file mode 100644 index 0000000..b8bddcc --- /dev/null +++ b/src/lib/components/ui/ColorPicker.svelte @@ -0,0 +1,63 @@ + + +
+ {#if color} + + {/if} + +
diff --git a/wishlist-app/src/lib/components/ui/button/button.svelte b/src/lib/components/ui/button/button.svelte similarity index 100% rename from wishlist-app/src/lib/components/ui/button/button.svelte rename to src/lib/components/ui/button/button.svelte diff --git a/wishlist-app/src/lib/components/ui/button/index.ts b/src/lib/components/ui/button/index.ts similarity index 100% rename from wishlist-app/src/lib/components/ui/button/index.ts rename to src/lib/components/ui/button/index.ts diff --git a/wishlist-app/src/lib/components/ui/card/card-content.svelte b/src/lib/components/ui/card/card-content.svelte similarity index 100% rename from wishlist-app/src/lib/components/ui/card/card-content.svelte rename to src/lib/components/ui/card/card-content.svelte diff --git a/wishlist-app/src/lib/components/ui/card/card-description.svelte b/src/lib/components/ui/card/card-description.svelte similarity index 100% rename from wishlist-app/src/lib/components/ui/card/card-description.svelte rename to src/lib/components/ui/card/card-description.svelte diff --git a/wishlist-app/src/lib/components/ui/card/card-header.svelte b/src/lib/components/ui/card/card-header.svelte similarity index 100% rename from wishlist-app/src/lib/components/ui/card/card-header.svelte rename to src/lib/components/ui/card/card-header.svelte diff --git a/wishlist-app/src/lib/components/ui/card/card-title.svelte b/src/lib/components/ui/card/card-title.svelte similarity index 100% rename from wishlist-app/src/lib/components/ui/card/card-title.svelte rename to src/lib/components/ui/card/card-title.svelte diff --git a/wishlist-app/src/lib/components/ui/card/card.svelte b/src/lib/components/ui/card/card.svelte similarity index 100% rename from wishlist-app/src/lib/components/ui/card/card.svelte rename to src/lib/components/ui/card/card.svelte diff --git a/wishlist-app/src/lib/components/ui/card/index.ts b/src/lib/components/ui/card/index.ts similarity index 100% rename from wishlist-app/src/lib/components/ui/card/index.ts rename to src/lib/components/ui/card/index.ts diff --git a/wishlist-app/src/lib/components/ui/input/index.ts b/src/lib/components/ui/input/index.ts similarity index 100% rename from wishlist-app/src/lib/components/ui/input/index.ts rename to src/lib/components/ui/input/index.ts diff --git a/wishlist-app/src/lib/components/ui/input/input.svelte b/src/lib/components/ui/input/input.svelte similarity index 100% rename from wishlist-app/src/lib/components/ui/input/input.svelte rename to src/lib/components/ui/input/input.svelte diff --git a/wishlist-app/src/lib/components/ui/label/index.ts b/src/lib/components/ui/label/index.ts similarity index 100% rename from wishlist-app/src/lib/components/ui/label/index.ts rename to src/lib/components/ui/label/index.ts diff --git a/wishlist-app/src/lib/components/ui/label/label.svelte b/src/lib/components/ui/label/label.svelte similarity index 100% rename from wishlist-app/src/lib/components/ui/label/label.svelte rename to src/lib/components/ui/label/label.svelte diff --git a/src/lib/components/ui/language-toggle/LanguageToggle.svelte b/src/lib/components/ui/language-toggle/LanguageToggle.svelte new file mode 100644 index 0000000..5a1422c --- /dev/null +++ b/src/lib/components/ui/language-toggle/LanguageToggle.svelte @@ -0,0 +1,58 @@ + + +
+ + + {#if showMenu} +
+
+ {#each languages as lang} + + {/each} +
+
+ {/if} +
diff --git a/src/lib/components/ui/language-toggle/index.ts b/src/lib/components/ui/language-toggle/index.ts new file mode 100644 index 0000000..11504d8 --- /dev/null +++ b/src/lib/components/ui/language-toggle/index.ts @@ -0,0 +1,2 @@ +import LanguageToggle from './LanguageToggle.svelte'; +export { LanguageToggle }; diff --git a/wishlist-app/src/lib/components/ui/textarea/index.ts b/src/lib/components/ui/textarea/index.ts similarity index 100% rename from wishlist-app/src/lib/components/ui/textarea/index.ts rename to src/lib/components/ui/textarea/index.ts diff --git a/wishlist-app/src/lib/components/ui/textarea/textarea.svelte b/src/lib/components/ui/textarea/textarea.svelte similarity index 100% rename from wishlist-app/src/lib/components/ui/textarea/textarea.svelte rename to src/lib/components/ui/textarea/textarea.svelte diff --git a/src/lib/components/ui/theme-toggle/ThemeToggle.svelte b/src/lib/components/ui/theme-toggle/ThemeToggle.svelte new file mode 100644 index 0000000..d20e523 --- /dev/null +++ b/src/lib/components/ui/theme-toggle/ThemeToggle.svelte @@ -0,0 +1,22 @@ + + + diff --git a/src/lib/components/ui/theme-toggle/index.ts b/src/lib/components/ui/theme-toggle/index.ts new file mode 100644 index 0000000..be5625b --- /dev/null +++ b/src/lib/components/ui/theme-toggle/index.ts @@ -0,0 +1 @@ +export { default as ThemeToggle } from './ThemeToggle.svelte'; diff --git a/src/lib/components/wishlist/AddItemForm.svelte b/src/lib/components/wishlist/AddItemForm.svelte new file mode 100644 index 0000000..9ed4aa9 --- /dev/null +++ b/src/lib/components/wishlist/AddItemForm.svelte @@ -0,0 +1,140 @@ + + + + + Add New Item + + +
{ + return async ({ update }) => { + await update({ reset: false }); + onSuccess?.(); + }; + }} + class="space-y-4" + > +
+
+ + +
+ +
+ +