diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..c9b357c
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,28 @@
+# Rust
+target/
+Cargo.lock
+
+# Node
+node_modules/
+.turbo/
+dist/
+build/
+.svelte-kit/
+
+# Environment
+.env
+.env.local
+.env.*.local
+
+# IDE
+.vscode/
+.idea/
+*.swp
+*.swo
+
+# OS
+.DS_Store
+Thumbs.db
+
+# Docker
+docker/data/
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..b3a8dbe
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,52 @@
+[workspace]
+resolver = "2"
+members = [
+ "crates/pvm-api",
+ "crates/pvm-core",
+ "crates/pvm-auth",
+ "crates/pvm-types",
+]
+
+[workspace.package]
+version = "0.1.0"
+edition = "2024"
+license = "UNLICENSED"
+
+[workspace.dependencies]
+# Async runtime
+tokio = { version = "1", features = ["full"] }
+
+# Web framework
+axum = { version = "0.8", features = ["ws", "macros"] }
+axum-extra = { version = "0.10", features = ["typed-header", "cookie"] }
+tower = "0.5"
+tower-http = { version = "0.6", features = ["cors", "trace", "compression-gzip"] }
+
+# Serialization
+serde = { version = "1", features = ["derive"] }
+serde_json = "1"
+
+# Auth / JWT
+jsonwebtoken = "9"
+
+# Database
+sqlx = { version = "0.8", features = ["runtime-tokio", "postgres", "sqlite", "chrono", "uuid"] }
+
+# Logging / Tracing
+tracing = "0.1"
+tracing-subscriber = { version = "0.3", features = ["env-filter", "json"] }
+
+# Error handling
+thiserror = "2"
+anyhow = "1"
+
+# OpenAPI
+utoipa = { version = "5", features = ["axum_extras", "uuid", "chrono"] }
+utoipa-axum = "0.2"
+utoipa-swagger-ui = { version = "9", features = ["axum"] }
+
+# Misc
+chrono = { version = "0.4", features = ["serde"] }
+uuid = { version = "1", features = ["v4", "serde"] }
+dotenvy = "0.15"
+reqwest = { version = "0.12", features = ["json"] }
diff --git a/apps/dashboard/.env.example b/apps/dashboard/.env.example
new file mode 100644
index 0000000..1287633
--- /dev/null
+++ b/apps/dashboard/.env.example
@@ -0,0 +1,16 @@
+# Zitadel OIDC Configuration
+AUTH_ZITADEL_ISSUER=https://auth.pvm.example.com
+AUTH_ZITADEL_CLIENT_ID=your-client-id
+AUTH_ZITADEL_CLIENT_SECRET=your-client-secret
+
+# Auth.js secret (generate with: openssl rand -base64 32)
+AUTH_SECRET=your-auth-secret
+
+# Backend API URL
+PUBLIC_API_URL=http://localhost:3001
+
+# Zitadel account management URL (for password/MFA changes)
+PUBLIC_ZITADEL_ACCOUNT_URL=https://auth.pvm.example.com/ui/console
+
+# App URL (for OIDC redirects)
+ORIGIN=http://localhost:5173
diff --git a/apps/dashboard/.gitignore b/apps/dashboard/.gitignore
new file mode 100644
index 0000000..3b462cb
--- /dev/null
+++ b/apps/dashboard/.gitignore
@@ -0,0 +1,23 @@
+node_modules
+
+# Output
+.output
+.vercel
+.netlify
+.wrangler
+/.svelte-kit
+/build
+
+# OS
+.DS_Store
+Thumbs.db
+
+# Env
+.env
+.env.*
+!.env.example
+!.env.test
+
+# Vite
+vite.config.js.timestamp-*
+vite.config.ts.timestamp-*
diff --git a/apps/dashboard/.npmrc b/apps/dashboard/.npmrc
new file mode 100644
index 0000000..b6f27f1
--- /dev/null
+++ b/apps/dashboard/.npmrc
@@ -0,0 +1 @@
+engine-strict=true
diff --git a/apps/dashboard/README.md b/apps/dashboard/README.md
new file mode 100644
index 0000000..dd3edc7
--- /dev/null
+++ b/apps/dashboard/README.md
@@ -0,0 +1,42 @@
+# sv
+
+Everything you need to build a Svelte project, powered by [`sv`](https://github.com/sveltejs/cli).
+
+## Creating a project
+
+If you're seeing this, you've probably already done this step. Congrats!
+
+```sh
+# create a new project
+npx sv create my-app
+```
+
+To recreate this project with the same configuration:
+
+```sh
+# recreate this project
+npx sv create --template minimal --types ts --no-install dashboard
+```
+
+## Developing
+
+Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
+
+```sh
+npm run dev
+
+# or start the server and open the app in a new browser tab
+npm run dev -- --open
+```
+
+## Building
+
+To create a production version of your app:
+
+```sh
+npm run build
+```
+
+You can preview the production build with `npm run preview`.
+
+> To deploy your app, you may need to install an [adapter](https://svelte.dev/docs/kit/adapters) for your target environment.
diff --git a/apps/dashboard/package.json b/apps/dashboard/package.json
new file mode 100644
index 0000000..85bdebb
--- /dev/null
+++ b/apps/dashboard/package.json
@@ -0,0 +1,30 @@
+{
+ "name": "dashboard",
+ "private": true,
+ "version": "0.0.1",
+ "type": "module",
+ "scripts": {
+ "dev": "vite dev",
+ "build": "vite build",
+ "preview": "vite preview",
+ "prepare": "svelte-kit sync || echo ''",
+ "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
+ "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"
+ },
+ "devDependencies": {
+ "@sveltejs/adapter-auto": "^7.0.0",
+ "@sveltejs/adapter-node": "^5.0.0",
+ "@sveltejs/kit": "^2.50.2",
+ "@sveltejs/vite-plugin-svelte": "^6.2.4",
+ "@tailwindcss/vite": "^4.0.0",
+ "svelte": "^5.49.2",
+ "svelte-check": "^4.3.6",
+ "typescript": "^5.9.3",
+ "vite": "^7.3.1"
+ },
+ "dependencies": {
+ "@auth/core": "^0.38.0",
+ "@auth/sveltekit": "^1.7.0",
+ "tailwindcss": "^4.0.0"
+ }
+}
diff --git a/apps/dashboard/src/app.css b/apps/dashboard/src/app.css
new file mode 100644
index 0000000..b8029e2
--- /dev/null
+++ b/apps/dashboard/src/app.css
@@ -0,0 +1,38 @@
+@import "tailwindcss";
+
+@theme {
+ --color-primary: #1e40af;
+ --color-primary-light: #3b82f6;
+ --color-primary-dark: #1e3a8a;
+ --color-surface: #ffffff;
+ --color-surface-dark: #0f172a;
+ --color-surface-card: #f8fafc;
+ --color-surface-card-dark: #1e293b;
+ --color-surface-sidebar: #f1f5f9;
+ --color-surface-sidebar-dark: #0f172a;
+ --color-border: #e2e8f0;
+ --color-border-dark: #334155;
+ --color-text: #0f172a;
+ --color-text-dark: #f1f5f9;
+ --color-text-muted: #64748b;
+ --color-text-muted-dark: #94a3b8;
+ --color-accent: #10b981;
+ --color-danger: #ef4444;
+}
+
+:root {
+ color-scheme: light dark;
+}
+
+body {
+ font-family: 'Inter', system-ui, -apple-system, sans-serif;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+@media (prefers-color-scheme: dark) {
+ body {
+ background-color: var(--color-surface-dark);
+ color: var(--color-text-dark);
+ }
+}
diff --git a/apps/dashboard/src/app.d.ts b/apps/dashboard/src/app.d.ts
new file mode 100644
index 0000000..8334603
--- /dev/null
+++ b/apps/dashboard/src/app.d.ts
@@ -0,0 +1,27 @@
+// See https://svelte.dev/docs/kit/types#app.d.ts
+
+declare module '@auth/sveltekit' {
+ interface Session {
+ accessToken?: string;
+ }
+}
+
+declare module '@auth/core/jwt' {
+ interface JWT {
+ accessToken?: string;
+ refreshToken?: string;
+ expiresAt?: number;
+ }
+}
+
+declare global {
+ namespace App {
+ // interface Error {}
+ // interface Locals {}
+ // interface PageData {}
+ // interface PageState {}
+ // interface Platform {}
+ }
+}
+
+export {};
diff --git a/apps/dashboard/src/app.html b/apps/dashboard/src/app.html
new file mode 100644
index 0000000..f273cc5
--- /dev/null
+++ b/apps/dashboard/src/app.html
@@ -0,0 +1,11 @@
+
+
+
+
+
+ %sveltekit.head%
+
+
+ %sveltekit.body%
+
+
diff --git a/apps/dashboard/src/auth.ts b/apps/dashboard/src/auth.ts
new file mode 100644
index 0000000..9cd616d
--- /dev/null
+++ b/apps/dashboard/src/auth.ts
@@ -0,0 +1,45 @@
+import { SvelteKitAuth } from '@auth/sveltekit';
+import type { Provider } from '@auth/core/providers';
+import { env } from '$env/dynamic/private';
+
+function zitadelProvider(): Provider {
+ return {
+ id: 'zitadel',
+ name: 'Zitadel',
+ type: 'oidc',
+ issuer: env.AUTH_ZITADEL_ISSUER,
+ clientId: env.AUTH_ZITADEL_CLIENT_ID,
+ clientSecret: env.AUTH_ZITADEL_CLIENT_SECRET,
+ authorization: {
+ params: {
+ scope: 'openid profile email offline_access'
+ }
+ },
+ checks: ['pkce', 'state'],
+ client: {
+ token_endpoint_auth_method: 'client_secret_basic'
+ }
+ };
+}
+
+export const { handle, signIn, signOut } = SvelteKitAuth({
+ providers: [zitadelProvider()],
+ callbacks: {
+ async jwt({ token, account }) {
+ if (account) {
+ token.accessToken = account.access_token;
+ token.refreshToken = account.refresh_token;
+ token.expiresAt = account.expires_at;
+ }
+ return token;
+ },
+ async session({ session, token }) {
+ session.accessToken = token.accessToken as string;
+ return session;
+ }
+ },
+ pages: {
+ signIn: '/auth/signin'
+ },
+ trustHost: true
+});
diff --git a/apps/dashboard/src/hooks.server.ts b/apps/dashboard/src/hooks.server.ts
new file mode 100644
index 0000000..e6726b0
--- /dev/null
+++ b/apps/dashboard/src/hooks.server.ts
@@ -0,0 +1 @@
+export { handle } from './auth';
diff --git a/apps/dashboard/src/lib/api.ts b/apps/dashboard/src/lib/api.ts
new file mode 100644
index 0000000..6878c57
--- /dev/null
+++ b/apps/dashboard/src/lib/api.ts
@@ -0,0 +1,62 @@
+const API_BASE = import.meta.env.PUBLIC_API_URL || 'http://localhost:3001';
+
+export class ApiClient {
+ private token: string;
+
+ constructor(token: string) {
+ this.token = token;
+ }
+
+ private async request(path: string, options?: RequestInit): Promise {
+ const res = await fetch(`${API_BASE}${path}`, {
+ ...options,
+ headers: {
+ 'Content-Type': 'application/json',
+ Authorization: `Bearer ${this.token}`,
+ ...options?.headers
+ }
+ });
+
+ if (!res.ok) {
+ throw new ApiError(res.status, await res.text());
+ }
+
+ return res.json();
+ }
+
+ async get(path: string): Promise {
+ return this.request(path);
+ }
+
+ async post(path: string, body?: unknown): Promise {
+ return this.request(path, {
+ method: 'POST',
+ body: body ? JSON.stringify(body) : undefined
+ });
+ }
+
+ async put(path: string, body?: unknown): Promise {
+ return this.request(path, {
+ method: 'PUT',
+ body: body ? JSON.stringify(body) : undefined
+ });
+ }
+
+ async delete(path: string): Promise {
+ return this.request(path, { method: 'DELETE' });
+ }
+}
+
+export class ApiError extends Error {
+ status: number;
+
+ constructor(status: number, message: string) {
+ super(message);
+ this.status = status;
+ this.name = 'ApiError';
+ }
+}
+
+export function createApiClient(token: string): ApiClient {
+ return new ApiClient(token);
+}
diff --git a/apps/dashboard/src/lib/assets/favicon.svg b/apps/dashboard/src/lib/assets/favicon.svg
new file mode 100644
index 0000000..cc5dc66
--- /dev/null
+++ b/apps/dashboard/src/lib/assets/favicon.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/apps/dashboard/src/lib/index.ts b/apps/dashboard/src/lib/index.ts
new file mode 100644
index 0000000..856f2b6
--- /dev/null
+++ b/apps/dashboard/src/lib/index.ts
@@ -0,0 +1 @@
+// place files you want to import through the `$lib` alias in this folder.
diff --git a/apps/dashboard/src/routes/+layout.server.ts b/apps/dashboard/src/routes/+layout.server.ts
new file mode 100644
index 0000000..790f996
--- /dev/null
+++ b/apps/dashboard/src/routes/+layout.server.ts
@@ -0,0 +1,6 @@
+import type { LayoutServerLoad } from './$types';
+
+export const load: LayoutServerLoad = async (event) => {
+ const session = await event.locals.auth();
+ return { session };
+};
diff --git a/apps/dashboard/src/routes/+layout.svelte b/apps/dashboard/src/routes/+layout.svelte
new file mode 100644
index 0000000..f322522
--- /dev/null
+++ b/apps/dashboard/src/routes/+layout.svelte
@@ -0,0 +1,13 @@
+
+
+
+
+ PVM - Poker Venue Manager
+
+
+{@render children()}
diff --git a/apps/dashboard/src/routes/+page.svelte b/apps/dashboard/src/routes/+page.svelte
new file mode 100644
index 0000000..5a4262b
--- /dev/null
+++ b/apps/dashboard/src/routes/+page.svelte
@@ -0,0 +1,90 @@
+
+
+
+
+
+
+
+ Manage your poker venue
+ with ease
+
+
+ PVM helps poker rooms run smoother — manage tournaments, track players,
+ handle waitlists, and display live information. All from one dashboard.
+
+ {#if session}
+
+ Go to Dashboard
+
+ {:else}
+
+ {/if}
+
+
+
+
+
Player Management
+
Track players, manage waitlists, and keep everyone in the game.
+
+
+
+
Tournaments
+
Create and manage tournaments with automatic blind structures and payouts.
+
+
+
+
Live Displays
+
Show live tournament info, waitlists, and announcements on venue screens.
+
+
+
+
diff --git a/apps/dashboard/src/routes/auth/signin/+page.svelte b/apps/dashboard/src/routes/auth/signin/+page.svelte
new file mode 100644
index 0000000..18860b6
--- /dev/null
+++ b/apps/dashboard/src/routes/auth/signin/+page.svelte
@@ -0,0 +1,83 @@
+
+
+
+
+
+
+
+ PVM
+
+
+
Sign in to PVM
+
Poker Venue Manager
+
+
+
+
+
+
+
+
+
+ Social providers via Zitadel
+
+
+
+
+
+
+
+
+
+
+
+
+ Social providers are configured through Zitadel.
+ All sign-in methods redirect to your identity provider.
+
+
+
+
+ ← Back to home
+
+
+
diff --git a/apps/dashboard/src/routes/dashboard/+layout.server.ts b/apps/dashboard/src/routes/dashboard/+layout.server.ts
new file mode 100644
index 0000000..b1b21b7
--- /dev/null
+++ b/apps/dashboard/src/routes/dashboard/+layout.server.ts
@@ -0,0 +1,10 @@
+import { redirect } from '@sveltejs/kit';
+import type { LayoutServerLoad } from './$types';
+
+export const load: LayoutServerLoad = async (event) => {
+ const session = await event.locals.auth();
+ if (!session) {
+ throw redirect(303, '/auth/signin');
+ }
+ return { session };
+};
diff --git a/apps/dashboard/src/routes/dashboard/+layout.svelte b/apps/dashboard/src/routes/dashboard/+layout.svelte
new file mode 100644
index 0000000..8d4d780
--- /dev/null
+++ b/apps/dashboard/src/routes/dashboard/+layout.svelte
@@ -0,0 +1,151 @@
+
+
+
+
+ {#if sidebarOpen}
+
(sidebarOpen = false)}
+ onkeydown={(e) => e.key === 'Escape' && (sidebarOpen = false)}
+ role="button"
+ tabindex="-1"
+ aria-label="Close sidebar"
+ >
+ {/if}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {session?.user?.name || 'User'}
+
+ {#if session?.user?.image}
+

+ {:else}
+
+ {session?.user?.name?.charAt(0)?.toUpperCase() || '?'}
+
+ {/if}
+
+
+
+
+
+
+
+ {@render children()}
+
+
+
diff --git a/apps/dashboard/src/routes/dashboard/+page.svelte b/apps/dashboard/src/routes/dashboard/+page.svelte
new file mode 100644
index 0000000..286cad9
--- /dev/null
+++ b/apps/dashboard/src/routes/dashboard/+page.svelte
@@ -0,0 +1,116 @@
+
+
+
+
+
+ Welcome back, {session?.user?.name || 'there'}
+
+
+ Here's an overview of your poker venue.
+
+
+
+
+
+
+ {#if session?.user?.image}
+

+ {:else}
+
+ {session?.user?.name?.charAt(0)?.toUpperCase() || '?'}
+
+ {/if}
+
+
+ {session?.user?.name || 'Unknown User'}
+
+
+ {session?.user?.email || 'No email'}
+
+
+
+
+
+
+
+
+
+
--
+
Connect backend to see data
+
+
+
+
+
--
+
Connect backend to see data
+
+
+
+
+
--
+
Connect backend to see data
+
+
+
+
+
+
Getting Started
+
+
+
+
Sign in to your account
+
+
+
+ 2
+
+
Set up your venue profile
+
+
+
+ 3
+
+
Configure your first tournament
+
+
+
+ 4
+
+
Connect a display device
+
+
+
+
diff --git a/apps/dashboard/src/routes/dashboard/account/+page.svelte b/apps/dashboard/src/routes/dashboard/account/+page.svelte
new file mode 100644
index 0000000..2e5c586
--- /dev/null
+++ b/apps/dashboard/src/routes/dashboard/account/+page.svelte
@@ -0,0 +1,103 @@
+
+
+
+
+
Account Settings
+
+ Manage your account and security settings.
+
+
+
+
+
+
Profile
+
+ {#if session?.user?.image}
+

+ {:else}
+
+ {session?.user?.name?.charAt(0)?.toUpperCase() || '?'}
+
+ {/if}
+
+
+ {session?.user?.name || 'Unknown User'}
+
+
+ {session?.user?.email || 'No email'}
+
+
+
+
+ Profile information is managed through your identity provider (Zitadel).
+
+
+
+
+
+
+
+
+
+ Two-Factor Authentication (2FA)
+
+
+ Add an extra layer of security to your account with TOTP-based two-factor authentication.
+ Managed through Zitadel.
+
+
+
+ Manage 2FA in Zitadel
+
+
+
+
+
+
Sign Out
+
+ Sign out of your PVM account on this device.
+
+
+
+
diff --git a/apps/dashboard/static/robots.txt b/apps/dashboard/static/robots.txt
new file mode 100644
index 0000000..b6dd667
--- /dev/null
+++ b/apps/dashboard/static/robots.txt
@@ -0,0 +1,3 @@
+# allow crawling everything by default
+User-agent: *
+Disallow:
diff --git a/apps/dashboard/svelte.config.js b/apps/dashboard/svelte.config.js
new file mode 100644
index 0000000..10c4eeb
--- /dev/null
+++ b/apps/dashboard/svelte.config.js
@@ -0,0 +1,13 @@
+import adapter from '@sveltejs/adapter-auto';
+
+/** @type {import('@sveltejs/kit').Config} */
+const config = {
+ kit: {
+ // adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list.
+ // If your environment is not supported, or you settled on a specific environment, switch out the adapter.
+ // See https://svelte.dev/docs/kit/adapters for more information about adapters.
+ adapter: adapter()
+ }
+};
+
+export default config;
diff --git a/apps/dashboard/tsconfig.json b/apps/dashboard/tsconfig.json
new file mode 100644
index 0000000..2c2ed3c
--- /dev/null
+++ b/apps/dashboard/tsconfig.json
@@ -0,0 +1,20 @@
+{
+ "extends": "./.svelte-kit/tsconfig.json",
+ "compilerOptions": {
+ "rewriteRelativeImportExtensions": true,
+ "allowJs": true,
+ "checkJs": true,
+ "esModuleInterop": true,
+ "forceConsistentCasingInFileNames": true,
+ "resolveJsonModule": true,
+ "skipLibCheck": true,
+ "sourceMap": true,
+ "strict": true,
+ "moduleResolution": "bundler"
+ }
+ // Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias
+ // except $lib which is handled by https://svelte.dev/docs/kit/configuration#files
+ //
+ // To make changes to top-level options such as include and exclude, we recommend extending
+ // the generated config; see https://svelte.dev/docs/kit/configuration#typescript
+}
diff --git a/apps/dashboard/vite.config.ts b/apps/dashboard/vite.config.ts
new file mode 100644
index 0000000..bf699a8
--- /dev/null
+++ b/apps/dashboard/vite.config.ts
@@ -0,0 +1,7 @@
+import { sveltekit } from '@sveltejs/kit/vite';
+import tailwindcss from '@tailwindcss/vite';
+import { defineConfig } from 'vite';
+
+export default defineConfig({
+ plugins: [tailwindcss(), sveltekit()]
+});
diff --git a/crates/pvm-api/Cargo.toml b/crates/pvm-api/Cargo.toml
new file mode 100644
index 0000000..982cb8c
--- /dev/null
+++ b/crates/pvm-api/Cargo.toml
@@ -0,0 +1,26 @@
+[package]
+name = "pvm-api"
+version.workspace = true
+edition.workspace = true
+
+[dependencies]
+pvm-core = { path = "../pvm-core" }
+pvm-types = { path = "../pvm-types" }
+pvm-auth = { path = "../pvm-auth" }
+
+axum.workspace = true
+axum-extra.workspace = true
+tower.workspace = true
+tower-http.workspace = true
+tokio.workspace = true
+serde.workspace = true
+serde_json.workspace = true
+tracing.workspace = true
+tracing-subscriber.workspace = true
+utoipa.workspace = true
+utoipa-axum.workspace = true
+utoipa-swagger-ui.workspace = true
+chrono.workspace = true
+uuid.workspace = true
+dotenvy.workspace = true
+thiserror.workspace = true
diff --git a/crates/pvm-api/src/main.rs b/crates/pvm-api/src/main.rs
new file mode 100644
index 0000000..b561e91
--- /dev/null
+++ b/crates/pvm-api/src/main.rs
@@ -0,0 +1,113 @@
+use axum::extract::FromRef;
+use axum::http::Method;
+use pvm_auth::jwks::JwksCache;
+use pvm_auth::middleware::AuthState;
+use pvm_types::user::UserProfile;
+use tokio::net::TcpListener;
+use tokio::signal;
+use tower_http::cors::{Any, CorsLayer};
+use tower_http::trace::TraceLayer;
+use tracing::info;
+use utoipa::OpenApi;
+
+mod routes;
+
+#[derive(Clone, FromRef)]
+struct AppState {
+ auth: AuthState,
+}
+
+#[derive(OpenApi)]
+#[openapi(
+ info(title = "PVM API", version = "0.1.0", description = "Poker Venue Manager API"),
+ paths(routes::health, routes::user_profile),
+ components(schemas(routes::HealthResponse, UserProfile)),
+)]
+struct ApiDoc;
+
+#[tokio::main]
+async fn main() {
+ // Load .env if present
+ let _ = dotenvy::dotenv();
+
+ // Init tracing
+ tracing_subscriber::fmt()
+ .with_env_filter(
+ tracing_subscriber::EnvFilter::try_from_default_env()
+ .unwrap_or_else(|_| "pvm_api=debug,pvm_auth=debug,tower_http=debug".parse().unwrap()),
+ )
+ .init();
+
+ // Config from env
+ let port: u16 = std::env::var("PVM_API_PORT")
+ .ok()
+ .and_then(|v| v.parse().ok())
+ .unwrap_or(3001);
+
+ let issuer_url = std::env::var("PVM_ZITADEL_ISSUER_URL")
+ .unwrap_or_else(|_| "http://localhost:8080".into());
+
+ let audience = std::env::var("PVM_ZITADEL_AUDIENCE")
+ .unwrap_or_else(|_| "pvm-api".into());
+
+ // Build auth state
+ let jwks_cache = JwksCache::new(&issuer_url);
+ jwks_cache.spawn_refresh_task();
+
+ let auth_state = AuthState {
+ jwks_cache,
+ audience,
+ issuer: issuer_url,
+ };
+
+ let state = AppState { auth: auth_state };
+
+ // CORS
+ let cors = CorsLayer::new()
+ .allow_origin(Any)
+ .allow_methods([Method::GET, Method::POST, Method::PUT, Method::DELETE])
+ .allow_headers(Any);
+
+ // Build router
+ let app = routes::router()
+ .merge(
+ utoipa_swagger_ui::SwaggerUi::new("/swagger-ui")
+ .url("/api-docs/openapi.json", ApiDoc::openapi()),
+ )
+ .layer(TraceLayer::new_for_http())
+ .layer(cors)
+ .with_state(state);
+
+ // Start server
+ let addr = format!("0.0.0.0:{port}");
+ info!(%addr, "Starting PVM API server");
+ let listener = TcpListener::bind(&addr).await.expect("failed to bind");
+ axum::serve(listener, app)
+ .with_graceful_shutdown(shutdown_signal())
+ .await
+ .expect("server error");
+}
+
+async fn shutdown_signal() {
+ let ctrl_c = async {
+ signal::ctrl_c().await.expect("failed to install Ctrl+C handler");
+ };
+
+ #[cfg(unix)]
+ let terminate = async {
+ signal::unix::signal(signal::unix::SignalKind::terminate())
+ .expect("failed to install signal handler")
+ .recv()
+ .await;
+ };
+
+ #[cfg(not(unix))]
+ let terminate = std::future::pending::<()>();
+
+ tokio::select! {
+ _ = ctrl_c => {},
+ _ = terminate => {},
+ }
+
+ info!("Shutdown signal received, starting graceful shutdown");
+}
diff --git a/crates/pvm-api/src/routes.rs b/crates/pvm-api/src/routes.rs
new file mode 100644
index 0000000..a90bccf
--- /dev/null
+++ b/crates/pvm-api/src/routes.rs
@@ -0,0 +1,59 @@
+use axum::routing::get;
+use axum::{Json, Router};
+use chrono::Utc;
+use pvm_auth::middleware::AuthUser;
+use pvm_types::user::UserProfile;
+use serde::Serialize;
+use utoipa::ToSchema;
+use uuid::Uuid;
+
+use crate::AppState;
+
+pub fn router() -> Router {
+ Router::new()
+ .route("/api/health", get(health))
+ .route("/api/user/profile", get(user_profile))
+}
+
+#[derive(Serialize, ToSchema)]
+pub struct HealthResponse {
+ pub status: String,
+}
+
+#[utoipa::path(
+ get,
+ path = "/api/health",
+ responses(
+ (status = 200, description = "Service is healthy", body = HealthResponse),
+ ),
+ tag = "health",
+)]
+pub async fn health() -> Json {
+ Json(HealthResponse {
+ status: "ok".into(),
+ })
+}
+
+#[utoipa::path(
+ get,
+ path = "/api/user/profile",
+ responses(
+ (status = 200, description = "User profile from JWT claims", body = UserProfile),
+ (status = 401, description = "Missing or invalid authentication"),
+ ),
+ security(("bearer_auth" = [])),
+ tag = "user",
+)]
+pub async fn user_profile(AuthUser(claims): AuthUser) -> Json {
+ let profile = UserProfile {
+ id: Uuid::parse_str(&claims.sub).unwrap_or_else(|_| Uuid::new_v4()),
+ email: claims.email.unwrap_or_default(),
+ name: claims.name,
+ picture: claims.picture,
+ email_verified: claims.email_verified.unwrap_or(false),
+ mfa_enabled: false,
+ created_at: Utc::now(),
+ };
+
+ Json(profile)
+}
diff --git a/crates/pvm-auth/Cargo.toml b/crates/pvm-auth/Cargo.toml
new file mode 100644
index 0000000..4c40484
--- /dev/null
+++ b/crates/pvm-auth/Cargo.toml
@@ -0,0 +1,17 @@
+[package]
+name = "pvm-auth"
+version.workspace = true
+edition.workspace = true
+
+[dependencies]
+pvm-types = { path = "../pvm-types" }
+axum.workspace = true
+jsonwebtoken.workspace = true
+reqwest.workspace = true
+serde.workspace = true
+serde_json.workspace = true
+thiserror.workspace = true
+tokio.workspace = true
+tracing.workspace = true
+chrono.workspace = true
+uuid.workspace = true
diff --git a/crates/pvm-auth/src/claims.rs b/crates/pvm-auth/src/claims.rs
new file mode 100644
index 0000000..be2a413
--- /dev/null
+++ b/crates/pvm-auth/src/claims.rs
@@ -0,0 +1,24 @@
+use serde::{Deserialize, Serialize};
+
+/// JWT claims from Zitadel OIDC tokens
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct PvmClaims {
+ /// Subject (user ID from Zitadel)
+ pub sub: String,
+ /// Issuer (Zitadel instance URL)
+ pub iss: String,
+ /// Audience
+ pub aud: Vec,
+ /// Expiration time (UTC timestamp)
+ pub exp: i64,
+ /// Issued at (UTC timestamp)
+ pub iat: i64,
+ /// Email address
+ pub email: Option,
+ /// Whether the email is verified
+ pub email_verified: Option,
+ /// Display name
+ pub name: Option,
+ /// Profile picture URL
+ pub picture: Option,
+}
diff --git a/crates/pvm-auth/src/jwks.rs b/crates/pvm-auth/src/jwks.rs
new file mode 100644
index 0000000..5e2855a
--- /dev/null
+++ b/crates/pvm-auth/src/jwks.rs
@@ -0,0 +1,105 @@
+use jsonwebtoken::jwk::JwkSet;
+use std::sync::Arc;
+use std::time::{Duration, Instant};
+use tokio::sync::RwLock;
+use tracing::{info, warn};
+
+const REFRESH_INTERVAL: Duration = Duration::from_secs(3600); // 1 hour
+
+#[derive(Clone)]
+pub struct JwksCache {
+ inner: Arc>,
+ jwks_url: String,
+ client: reqwest::Client,
+}
+
+struct CacheInner {
+ jwks: Option,
+ last_refresh: Option,
+}
+
+impl JwksCache {
+ pub fn new(issuer_url: &str) -> Self {
+ let jwks_url = format!(
+ "{}/.well-known/jwks.json",
+ issuer_url.trim_end_matches('/')
+ );
+
+ Self {
+ inner: Arc::new(RwLock::new(CacheInner {
+ jwks: None,
+ last_refresh: None,
+ })),
+ jwks_url,
+ client: reqwest::Client::new(),
+ }
+ }
+
+ pub async fn get_jwks(&self) -> Result {
+ // Check if we have a cached, non-stale JWKS
+ {
+ let cache = self.inner.read().await;
+ if let (Some(jwks), Some(last_refresh)) = (&cache.jwks, &cache.last_refresh) {
+ if last_refresh.elapsed() < REFRESH_INTERVAL {
+ return Ok(jwks.clone());
+ }
+ }
+ }
+
+ // Need to refresh
+ self.refresh().await
+ }
+
+ async fn refresh(&self) -> Result {
+ info!(url = %self.jwks_url, "Fetching JWKS");
+
+ let response = self
+ .client
+ .get(&self.jwks_url)
+ .send()
+ .await
+ .map_err(|e| JwksError::Fetch(e.to_string()))?;
+
+ if !response.status().is_success() {
+ return Err(JwksError::Fetch(format!(
+ "JWKS endpoint returned status {}",
+ response.status()
+ )));
+ }
+
+ let jwks: JwkSet = response
+ .json()
+ .await
+ .map_err(|e| JwksError::Parse(e.to_string()))?;
+
+ info!(keys = jwks.keys.len(), "JWKS refreshed");
+
+ let mut cache = self.inner.write().await;
+ cache.jwks = Some(jwks.clone());
+ cache.last_refresh = Some(Instant::now());
+
+ Ok(jwks)
+ }
+
+ /// Spawn a background task that periodically refreshes the JWKS cache.
+ pub fn spawn_refresh_task(&self) {
+ let cache = self.clone();
+ tokio::spawn(async move {
+ loop {
+ tokio::time::sleep(REFRESH_INTERVAL).await;
+ if let Err(e) = cache.refresh().await {
+ warn!(error = %e, "Background JWKS refresh failed");
+ }
+ }
+ });
+ }
+}
+
+#[derive(Debug, thiserror::Error)]
+pub enum JwksError {
+ #[error("Failed to fetch JWKS: {0}")]
+ Fetch(String),
+
+ #[error("Failed to parse JWKS: {0}")]
+ Parse(String),
+}
diff --git a/crates/pvm-auth/src/lib.rs b/crates/pvm-auth/src/lib.rs
new file mode 100644
index 0000000..02dfc5f
--- /dev/null
+++ b/crates/pvm-auth/src/lib.rs
@@ -0,0 +1,3 @@
+pub mod claims;
+pub mod jwks;
+pub mod middleware;
diff --git a/crates/pvm-auth/src/middleware.rs b/crates/pvm-auth/src/middleware.rs
new file mode 100644
index 0000000..8f524d7
--- /dev/null
+++ b/crates/pvm-auth/src/middleware.rs
@@ -0,0 +1,121 @@
+use axum::extract::{FromRef, FromRequestParts};
+use axum::http::request::Parts;
+use axum::http::StatusCode;
+use axum::response::{IntoResponse, Response};
+use jsonwebtoken::{decode, decode_header, DecodingKey, Validation};
+use serde::Serialize;
+use tracing::warn;
+
+use crate::claims::PvmClaims;
+use crate::jwks::JwksCache;
+
+/// Axum extractor that validates a JWT Bearer token and yields PvmClaims.
+///
+/// Usage in a handler:
+/// ```ignore
+/// async fn profile(AuthUser(claims): AuthUser) -> impl IntoResponse { ... }
+/// ```
+pub struct AuthUser(pub PvmClaims);
+
+/// Shared auth state that must be added to the Axum router state.
+#[derive(Clone)]
+pub struct AuthState {
+ pub jwks_cache: JwksCache,
+ pub audience: String,
+ pub issuer: String,
+}
+
+#[derive(Debug)]
+pub enum AuthError {
+ MissingHeader,
+ InvalidHeader,
+ InvalidToken(String),
+ JwksError(String),
+}
+
+#[derive(Serialize)]
+struct AuthErrorBody {
+ error: String,
+}
+
+impl IntoResponse for AuthError {
+ fn into_response(self) -> Response {
+ let msg = match &self {
+ AuthError::MissingHeader => "Missing Authorization header",
+ AuthError::InvalidHeader => "Invalid Authorization header format",
+ AuthError::InvalidToken(e) => e.as_str(),
+ AuthError::JwksError(e) => e.as_str(),
+ };
+
+ warn!(error = msg, "Auth rejection");
+
+ let body = AuthErrorBody {
+ error: msg.to_string(),
+ };
+
+ (StatusCode::UNAUTHORIZED, axum::Json(body)).into_response()
+ }
+}
+
+impl FromRequestParts for AuthUser
+where
+ S: Send + Sync,
+ AuthState: axum::extract::FromRef,
+{
+ type Rejection = AuthError;
+
+ async fn from_request_parts(parts: &mut Parts, state: &S) -> Result {
+ let auth_state = AuthState::from_ref(state);
+
+ // Extract the Bearer token
+ let auth_header = parts
+ .headers
+ .get(axum::http::header::AUTHORIZATION)
+ .ok_or(AuthError::MissingHeader)?
+ .to_str()
+ .map_err(|_| AuthError::InvalidHeader)?;
+
+ let token = auth_header
+ .strip_prefix("Bearer ")
+ .ok_or(AuthError::InvalidHeader)?;
+
+ // Decode the JWT header to get the key ID (kid)
+ let header =
+ decode_header(token).map_err(|e| AuthError::InvalidToken(e.to_string()))?;
+
+ let kid = header.kid.ok_or_else(|| {
+ AuthError::InvalidToken("Token header missing 'kid'".into())
+ })?;
+
+ // Fetch JWKS and find the matching key
+ let jwks: jsonwebtoken::jwk::JwkSet = auth_state
+ .jwks_cache
+ .get_jwks()
+ .await
+ .map_err(|e: crate::jwks::JwksError| AuthError::JwksError(e.to_string()))?;
+
+ let jwk = jwks
+ .keys
+ .iter()
+ .find(|k| k.common.key_id.as_deref() == Some(&kid))
+ .ok_or_else(|| {
+ AuthError::InvalidToken(format!("No JWK found for kid '{kid}'"))
+ })?;
+
+ // Build the decoding key from the JWK
+ let decoding_key = DecodingKey::from_jwk(jwk)
+ .map_err(|e| AuthError::InvalidToken(e.to_string()))?;
+
+ // Validate the token
+ let mut validation = Validation::new(
+ header.alg,
+ );
+ validation.set_audience(&[&auth_state.audience]);
+ validation.set_issuer(&[&auth_state.issuer]);
+
+ let token_data = decode::(token, &decoding_key, &validation)
+ .map_err(|e| AuthError::InvalidToken(e.to_string()))?;
+
+ Ok(AuthUser(token_data.claims))
+ }
+}
diff --git a/crates/pvm-core/Cargo.toml b/crates/pvm-core/Cargo.toml
new file mode 100644
index 0000000..2430d64
--- /dev/null
+++ b/crates/pvm-core/Cargo.toml
@@ -0,0 +1,13 @@
+[package]
+name = "pvm-core"
+version.workspace = true
+edition.workspace = true
+
+[dependencies]
+pvm-types = { path = "../pvm-types" }
+axum.workspace = true
+serde.workspace = true
+serde_json.workspace = true
+thiserror.workspace = true
+uuid.workspace = true
+chrono.workspace = true
diff --git a/crates/pvm-core/src/error.rs b/crates/pvm-core/src/error.rs
new file mode 100644
index 0000000..40726b8
--- /dev/null
+++ b/crates/pvm-core/src/error.rs
@@ -0,0 +1,41 @@
+use axum::http::StatusCode;
+use axum::response::{IntoResponse, Response};
+use serde::Serialize;
+use thiserror::Error;
+
+#[derive(Debug, Error)]
+pub enum PvmError {
+ #[error("Authentication required")]
+ Unauthorized,
+
+ #[error("Insufficient permissions")]
+ Forbidden,
+
+ #[error("Resource not found: {0}")]
+ NotFound(String),
+
+ #[error("Internal error: {0}")]
+ Internal(String),
+}
+
+#[derive(Serialize)]
+struct ErrorBody {
+ error: String,
+}
+
+impl IntoResponse for PvmError {
+ fn into_response(self) -> Response {
+ let status = match &self {
+ PvmError::Unauthorized => StatusCode::UNAUTHORIZED,
+ PvmError::Forbidden => StatusCode::FORBIDDEN,
+ PvmError::NotFound(_) => StatusCode::NOT_FOUND,
+ PvmError::Internal(_) => StatusCode::INTERNAL_SERVER_ERROR,
+ };
+
+ let body = ErrorBody {
+ error: self.to_string(),
+ };
+
+ (status, axum::Json(body)).into_response()
+ }
+}
diff --git a/crates/pvm-core/src/lib.rs b/crates/pvm-core/src/lib.rs
new file mode 100644
index 0000000..a91e735
--- /dev/null
+++ b/crates/pvm-core/src/lib.rs
@@ -0,0 +1 @@
+pub mod error;
diff --git a/crates/pvm-types/Cargo.toml b/crates/pvm-types/Cargo.toml
new file mode 100644
index 0000000..4684da4
--- /dev/null
+++ b/crates/pvm-types/Cargo.toml
@@ -0,0 +1,10 @@
+[package]
+name = "pvm-types"
+version.workspace = true
+edition.workspace = true
+
+[dependencies]
+serde.workspace = true
+chrono.workspace = true
+uuid.workspace = true
+utoipa.workspace = true
diff --git a/crates/pvm-types/src/lib.rs b/crates/pvm-types/src/lib.rs
new file mode 100644
index 0000000..22d12a3
--- /dev/null
+++ b/crates/pvm-types/src/lib.rs
@@ -0,0 +1 @@
+pub mod user;
diff --git a/crates/pvm-types/src/user.rs b/crates/pvm-types/src/user.rs
new file mode 100644
index 0000000..df0d16a
--- /dev/null
+++ b/crates/pvm-types/src/user.rs
@@ -0,0 +1,15 @@
+use chrono::{DateTime, Utc};
+use serde::{Deserialize, Serialize};
+use utoipa::ToSchema;
+use uuid::Uuid;
+
+#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
+pub struct UserProfile {
+ pub id: Uuid,
+ pub email: String,
+ pub name: Option,
+ pub picture: Option,
+ pub email_verified: bool,
+ pub mfa_enabled: bool,
+ pub created_at: DateTime,
+}
diff --git a/docker/.env.example b/docker/.env.example
new file mode 100644
index 0000000..05ec75d
--- /dev/null
+++ b/docker/.env.example
@@ -0,0 +1,7 @@
+# Zitadel
+ZITADEL_MASTERKEY=a-32-character-masterkey-for-dev!
+ZITADEL_DB_PASSWORD=zitadel-dev-password
+ZITADEL_ADMIN_PASSWORD=Admin1234!
+
+# PVM Application Database
+PVM_DB_PASSWORD=pvm-dev-password
diff --git a/docker/README.md b/docker/README.md
new file mode 100644
index 0000000..db65ed9
--- /dev/null
+++ b/docker/README.md
@@ -0,0 +1,75 @@
+# PVM Docker Dev Environment
+
+Local development stack with Zitadel auth, PostgreSQL, and DragonflyDB.
+
+## Services
+
+| Service | Description | Port |
+|---------|-------------|------|
+| **zitadel** | Zitadel v3 identity provider (OIDC/OAuth2) | 8080 |
+| **zitadel-db** | PostgreSQL 16 for Zitadel (internal, not exposed) | — |
+| **pvm-db** | PostgreSQL 16 for PVM application data | 5432 |
+| **dragonfly** | DragonflyDB (Redis-compatible cache) | 6379 |
+
+## Quick Start
+
+```bash
+# Copy env file and adjust if needed
+cp .env.example .env
+
+# Start all services
+docker compose -f docker-compose.dev.yml up -d
+
+# Check status
+docker compose -f docker-compose.dev.yml ps
+
+# View Zitadel logs (first startup takes ~30-60s)
+docker compose -f docker-compose.dev.yml logs -f zitadel
+```
+
+## Zitadel Admin Console
+
+Once Zitadel finishes initializing (watch the logs for "server is listening"), open:
+
+- **Console URL:** http://localhost:8080/ui/console
+- **Username:** `admin`
+- **Password:** value of `ZITADEL_ADMIN_PASSWORD` in your `.env` (default: `Admin1234!`)
+
+## First-Time Zitadel Setup
+
+After the first `docker compose up`, configure Zitadel for PVM:
+
+1. **Log in** to the admin console at http://localhost:8080/ui/console
+2. **Create a project** called "PVM"
+3. **Create an application** within the project:
+ - Name: "PVM Web"
+ - Type: Web
+ - Auth method: PKCE (recommended for SvelteKit)
+ - Redirect URIs: `http://localhost:5173/auth/callback/zitadel`
+ - Post-logout URIs: `http://localhost:5173`
+4. **Note the Client ID** — you'll need it for SvelteKit's `AUTH_ZITADEL_ID`
+5. (Optional) **Configure social login** providers under Settings > Identity Providers:
+ - Google, Apple, Facebook — each requires an OAuth app from the respective developer console
+
+## Connecting from the PVM Backend
+
+```
+# PostgreSQL (PVM app database)
+DATABASE_URL=postgres://pvm:pvm-dev-password@localhost:5432/pvm
+
+# DragonflyDB (Redis-compatible)
+REDIS_URL=redis://localhost:6379
+
+# Zitadel issuer (for OIDC/JWT validation)
+ZITADEL_URL=http://localhost:8080
+```
+
+## Stopping & Cleanup
+
+```bash
+# Stop services (data is preserved in volumes)
+docker compose -f docker-compose.dev.yml down
+
+# Stop and delete all data (fresh start)
+docker compose -f docker-compose.dev.yml down -v
+```
diff --git a/docker/docker-compose.dev.yml b/docker/docker-compose.dev.yml
new file mode 100644
index 0000000..e8f44f6
--- /dev/null
+++ b/docker/docker-compose.dev.yml
@@ -0,0 +1,73 @@
+services:
+ zitadel:
+ image: ghcr.io/zitadel/zitadel:v3-latest
+ command: start-from-init --masterkey "${ZITADEL_MASTERKEY}" --tlsMode disabled
+ environment:
+ ZITADEL_DATABASE_POSTGRES_HOST: zitadel-db
+ ZITADEL_DATABASE_POSTGRES_PORT: 5432
+ ZITADEL_DATABASE_POSTGRES_DATABASE: zitadel
+ ZITADEL_DATABASE_POSTGRES_USER_USERNAME: zitadel
+ ZITADEL_DATABASE_POSTGRES_USER_PASSWORD: "${ZITADEL_DB_PASSWORD}"
+ ZITADEL_DATABASE_POSTGRES_USER_SSL_MODE: disable
+ ZITADEL_DATABASE_POSTGRES_ADMIN_USERNAME: zitadel
+ ZITADEL_DATABASE_POSTGRES_ADMIN_PASSWORD: "${ZITADEL_DB_PASSWORD}"
+ ZITADEL_DATABASE_POSTGRES_ADMIN_SSL_MODE: disable
+ ZITADEL_EXTERNALDOMAIN: localhost
+ ZITADEL_EXTERNALPORT: 8080
+ ZITADEL_EXTERNALSECURE: "false"
+ ZITADEL_TLS_MODE: disabled
+ ZITADEL_FIRSTINSTANCE_ORG_HUMAN_USERNAME: admin
+ ZITADEL_FIRSTINSTANCE_ORG_HUMAN_PASSWORD: "${ZITADEL_ADMIN_PASSWORD}"
+ ports:
+ - "8080:8080"
+ depends_on:
+ zitadel-db:
+ condition: service_healthy
+ restart: unless-stopped
+
+ zitadel-db:
+ image: postgres:16-alpine
+ environment:
+ POSTGRES_DB: zitadel
+ POSTGRES_USER: zitadel
+ POSTGRES_PASSWORD: "${ZITADEL_DB_PASSWORD}"
+ volumes:
+ - zitadel-pg-data:/var/lib/postgresql/data
+ healthcheck:
+ test: ["CMD-SHELL", "pg_isready -U zitadel -d zitadel"]
+ interval: 5s
+ timeout: 5s
+ retries: 10
+ restart: unless-stopped
+
+ pvm-db:
+ image: postgres:16-alpine
+ environment:
+ POSTGRES_DB: pvm
+ POSTGRES_USER: pvm
+ POSTGRES_PASSWORD: "${PVM_DB_PASSWORD}"
+ ports:
+ - "5432:5432"
+ volumes:
+ - pvm-pg-data:/var/lib/postgresql/data
+ healthcheck:
+ test: ["CMD-SHELL", "pg_isready -U pvm -d pvm"]
+ interval: 5s
+ timeout: 5s
+ retries: 10
+ restart: unless-stopped
+
+ dragonfly:
+ image: docker.dragonflydb.io/dragonflydb/dragonfly:latest
+ ports:
+ - "6379:6379"
+ volumes:
+ - dragonfly-data:/data
+ ulimits:
+ memlock: -1
+ restart: unless-stopped
+
+volumes:
+ zitadel-pg-data:
+ pvm-pg-data:
+ dragonfly-data:
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..50941b5
--- /dev/null
+++ b/package.json
@@ -0,0 +1,10 @@
+{
+ "name": "pvm",
+ "private": true,
+ "scripts": {
+ "dev": "turbo dev",
+ "build": "turbo build",
+ "test": "turbo test",
+ "lint": "turbo lint"
+ }
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
new file mode 100644
index 0000000..c0d3c90
--- /dev/null
+++ b/pnpm-lock.yaml
@@ -0,0 +1,1612 @@
+lockfileVersion: '9.0'
+
+settings:
+ autoInstallPeers: true
+ excludeLinksFromLockfile: false
+
+importers:
+
+ .: {}
+
+ apps/dashboard:
+ dependencies:
+ '@auth/core':
+ specifier: ^0.38.0
+ version: 0.38.0
+ '@auth/sveltekit':
+ specifier: ^1.7.0
+ version: 1.11.1(@sveltejs/kit@2.50.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.50.0)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.50.0)(typescript@5.9.3)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.50.0)
+ tailwindcss:
+ specifier: ^4.0.0
+ version: 4.1.18
+ devDependencies:
+ '@sveltejs/adapter-auto':
+ specifier: ^7.0.0
+ version: 7.0.0(@sveltejs/kit@2.50.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.50.0)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.50.0)(typescript@5.9.3)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.30.2)))
+ '@sveltejs/adapter-node':
+ specifier: ^5.0.0
+ version: 5.5.2(@sveltejs/kit@2.50.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.50.0)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.50.0)(typescript@5.9.3)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.30.2)))
+ '@sveltejs/kit':
+ specifier: ^2.50.2
+ version: 2.50.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.50.0)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.50.0)(typescript@5.9.3)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.30.2))
+ '@sveltejs/vite-plugin-svelte':
+ specifier: ^6.2.4
+ version: 6.2.4(svelte@5.50.0)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.30.2))
+ '@tailwindcss/vite':
+ specifier: ^4.0.0
+ version: 4.1.18(vite@7.3.1(jiti@2.6.1)(lightningcss@1.30.2))
+ svelte:
+ specifier: ^5.49.2
+ version: 5.50.0
+ svelte-check:
+ specifier: ^4.3.6
+ version: 4.3.6(picomatch@4.0.3)(svelte@5.50.0)(typescript@5.9.3)
+ typescript:
+ specifier: ^5.9.3
+ version: 5.9.3
+ vite:
+ specifier: ^7.3.1
+ version: 7.3.1(jiti@2.6.1)(lightningcss@1.30.2)
+
+packages:
+
+ '@auth/core@0.38.0':
+ resolution: {integrity: sha512-ClHl44x4cY3wfJmHLpW+XrYqED0fZIzbHmwbExltzroCjR5ts3DLTWzADRba8mJFYZ8JIEJDa+lXnGl0E9Bl7Q==}
+ peerDependencies:
+ '@simplewebauthn/browser': ^9.0.1
+ '@simplewebauthn/server': ^9.0.2
+ nodemailer: ^6.8.0
+ peerDependenciesMeta:
+ '@simplewebauthn/browser':
+ optional: true
+ '@simplewebauthn/server':
+ optional: true
+ nodemailer:
+ optional: true
+
+ '@auth/core@0.41.1':
+ resolution: {integrity: sha512-t9cJ2zNYAdWMacGRMT6+r4xr1uybIdmYa49calBPeTqwgAFPV/88ac9TEvCR85pvATiSPt8VaNf+Gt24JIT/uw==}
+ peerDependencies:
+ '@simplewebauthn/browser': ^9.0.1
+ '@simplewebauthn/server': ^9.0.2
+ nodemailer: ^7.0.7
+ peerDependenciesMeta:
+ '@simplewebauthn/browser':
+ optional: true
+ '@simplewebauthn/server':
+ optional: true
+ nodemailer:
+ optional: true
+
+ '@auth/sveltekit@1.11.1':
+ resolution: {integrity: sha512-cWNfXcKrNIVtJYOY1tq7H7m03j89Wg7xrTvOJALu18fZdYulzYCPIAdTw8XSEzOp6KyhOGo7tmW7VtzRNtr/8Q==}
+ 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
+ peerDependenciesMeta:
+ '@simplewebauthn/browser':
+ optional: true
+ '@simplewebauthn/server':
+ optional: true
+ nodemailer:
+ optional: true
+
+ '@esbuild/aix-ppc64@0.27.3':
+ resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==}
+ engines: {node: '>=18'}
+ cpu: [ppc64]
+ os: [aix]
+
+ '@esbuild/android-arm64@0.27.3':
+ resolution: {integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [android]
+
+ '@esbuild/android-arm@0.27.3':
+ resolution: {integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==}
+ engines: {node: '>=18'}
+ cpu: [arm]
+ os: [android]
+
+ '@esbuild/android-x64@0.27.3':
+ resolution: {integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [android]
+
+ '@esbuild/darwin-arm64@0.27.3':
+ resolution: {integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@esbuild/darwin-x64@0.27.3':
+ resolution: {integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [darwin]
+
+ '@esbuild/freebsd-arm64@0.27.3':
+ resolution: {integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [freebsd]
+
+ '@esbuild/freebsd-x64@0.27.3':
+ resolution: {integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@esbuild/linux-arm64@0.27.3':
+ resolution: {integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [linux]
+
+ '@esbuild/linux-arm@0.27.3':
+ resolution: {integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==}
+ engines: {node: '>=18'}
+ cpu: [arm]
+ os: [linux]
+
+ '@esbuild/linux-ia32@0.27.3':
+ resolution: {integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==}
+ engines: {node: '>=18'}
+ cpu: [ia32]
+ os: [linux]
+
+ '@esbuild/linux-loong64@0.27.3':
+ resolution: {integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==}
+ engines: {node: '>=18'}
+ cpu: [loong64]
+ os: [linux]
+
+ '@esbuild/linux-mips64el@0.27.3':
+ resolution: {integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==}
+ engines: {node: '>=18'}
+ cpu: [mips64el]
+ os: [linux]
+
+ '@esbuild/linux-ppc64@0.27.3':
+ resolution: {integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==}
+ engines: {node: '>=18'}
+ cpu: [ppc64]
+ os: [linux]
+
+ '@esbuild/linux-riscv64@0.27.3':
+ resolution: {integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==}
+ engines: {node: '>=18'}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@esbuild/linux-s390x@0.27.3':
+ resolution: {integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==}
+ engines: {node: '>=18'}
+ cpu: [s390x]
+ os: [linux]
+
+ '@esbuild/linux-x64@0.27.3':
+ resolution: {integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [linux]
+
+ '@esbuild/netbsd-arm64@0.27.3':
+ resolution: {integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [netbsd]
+
+ '@esbuild/netbsd-x64@0.27.3':
+ resolution: {integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [netbsd]
+
+ '@esbuild/openbsd-arm64@0.27.3':
+ resolution: {integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [openbsd]
+
+ '@esbuild/openbsd-x64@0.27.3':
+ resolution: {integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [openbsd]
+
+ '@esbuild/openharmony-arm64@0.27.3':
+ resolution: {integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [openharmony]
+
+ '@esbuild/sunos-x64@0.27.3':
+ resolution: {integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [sunos]
+
+ '@esbuild/win32-arm64@0.27.3':
+ resolution: {integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [win32]
+
+ '@esbuild/win32-ia32@0.27.3':
+ resolution: {integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==}
+ engines: {node: '>=18'}
+ cpu: [ia32]
+ os: [win32]
+
+ '@esbuild/win32-x64@0.27.3':
+ resolution: {integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [win32]
+
+ '@jridgewell/gen-mapping@0.3.13':
+ resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
+
+ '@jridgewell/remapping@2.3.5':
+ resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==}
+
+ '@jridgewell/resolve-uri@3.1.2':
+ resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
+ engines: {node: '>=6.0.0'}
+
+ '@jridgewell/sourcemap-codec@1.5.5':
+ resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
+
+ '@jridgewell/trace-mapping@0.3.31':
+ resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
+
+ '@panva/hkdf@1.2.1':
+ resolution: {integrity: sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw==}
+
+ '@polka/url@1.0.0-next.29':
+ resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==}
+
+ '@rollup/plugin-commonjs@28.0.9':
+ resolution: {integrity: sha512-PIR4/OHZ79romx0BVVll/PkwWpJ7e5lsqFa3gFfcrFPWwLXLV39JVUzQV9RKjWerE7B845Hqjj9VYlQeieZ2dA==}
+ engines: {node: '>=16.0.0 || 14 >= 14.17'}
+ peerDependencies:
+ rollup: ^2.68.0||^3.0.0||^4.0.0
+ peerDependenciesMeta:
+ rollup:
+ optional: true
+
+ '@rollup/plugin-json@6.1.0':
+ resolution: {integrity: sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==}
+ engines: {node: '>=14.0.0'}
+ peerDependencies:
+ rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0
+ peerDependenciesMeta:
+ rollup:
+ optional: true
+
+ '@rollup/plugin-node-resolve@16.0.3':
+ resolution: {integrity: sha512-lUYM3UBGuM93CnMPG1YocWu7X802BrNF3jW2zny5gQyLQgRFJhV1Sq0Zi74+dh/6NBx1DxFC4b4GXg9wUCG5Qg==}
+ engines: {node: '>=14.0.0'}
+ peerDependencies:
+ rollup: ^2.78.0||^3.0.0||^4.0.0
+ peerDependenciesMeta:
+ rollup:
+ optional: true
+
+ '@rollup/pluginutils@5.3.0':
+ resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==}
+ engines: {node: '>=14.0.0'}
+ peerDependencies:
+ rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0
+ peerDependenciesMeta:
+ rollup:
+ optional: true
+
+ '@rollup/rollup-android-arm-eabi@4.57.1':
+ resolution: {integrity: sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==}
+ cpu: [arm]
+ os: [android]
+
+ '@rollup/rollup-android-arm64@4.57.1':
+ resolution: {integrity: sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==}
+ cpu: [arm64]
+ os: [android]
+
+ '@rollup/rollup-darwin-arm64@4.57.1':
+ resolution: {integrity: sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@rollup/rollup-darwin-x64@4.57.1':
+ resolution: {integrity: sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==}
+ cpu: [x64]
+ os: [darwin]
+
+ '@rollup/rollup-freebsd-arm64@4.57.1':
+ resolution: {integrity: sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==}
+ cpu: [arm64]
+ os: [freebsd]
+
+ '@rollup/rollup-freebsd-x64@4.57.1':
+ resolution: {integrity: sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@rollup/rollup-linux-arm-gnueabihf@4.57.1':
+ resolution: {integrity: sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==}
+ cpu: [arm]
+ os: [linux]
+ libc: [glibc]
+
+ '@rollup/rollup-linux-arm-musleabihf@4.57.1':
+ resolution: {integrity: sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==}
+ cpu: [arm]
+ os: [linux]
+ libc: [musl]
+
+ '@rollup/rollup-linux-arm64-gnu@4.57.1':
+ resolution: {integrity: sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==}
+ cpu: [arm64]
+ os: [linux]
+ libc: [glibc]
+
+ '@rollup/rollup-linux-arm64-musl@4.57.1':
+ resolution: {integrity: sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==}
+ cpu: [arm64]
+ os: [linux]
+ libc: [musl]
+
+ '@rollup/rollup-linux-loong64-gnu@4.57.1':
+ resolution: {integrity: sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==}
+ cpu: [loong64]
+ os: [linux]
+ libc: [glibc]
+
+ '@rollup/rollup-linux-loong64-musl@4.57.1':
+ resolution: {integrity: sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==}
+ cpu: [loong64]
+ os: [linux]
+ libc: [musl]
+
+ '@rollup/rollup-linux-ppc64-gnu@4.57.1':
+ resolution: {integrity: sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==}
+ cpu: [ppc64]
+ os: [linux]
+ libc: [glibc]
+
+ '@rollup/rollup-linux-ppc64-musl@4.57.1':
+ resolution: {integrity: sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==}
+ cpu: [ppc64]
+ os: [linux]
+ libc: [musl]
+
+ '@rollup/rollup-linux-riscv64-gnu@4.57.1':
+ resolution: {integrity: sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==}
+ cpu: [riscv64]
+ os: [linux]
+ libc: [glibc]
+
+ '@rollup/rollup-linux-riscv64-musl@4.57.1':
+ resolution: {integrity: sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==}
+ cpu: [riscv64]
+ os: [linux]
+ libc: [musl]
+
+ '@rollup/rollup-linux-s390x-gnu@4.57.1':
+ resolution: {integrity: sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==}
+ cpu: [s390x]
+ os: [linux]
+ libc: [glibc]
+
+ '@rollup/rollup-linux-x64-gnu@4.57.1':
+ resolution: {integrity: sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==}
+ cpu: [x64]
+ os: [linux]
+ libc: [glibc]
+
+ '@rollup/rollup-linux-x64-musl@4.57.1':
+ resolution: {integrity: sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==}
+ cpu: [x64]
+ os: [linux]
+ libc: [musl]
+
+ '@rollup/rollup-openbsd-x64@4.57.1':
+ resolution: {integrity: sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==}
+ cpu: [x64]
+ os: [openbsd]
+
+ '@rollup/rollup-openharmony-arm64@4.57.1':
+ resolution: {integrity: sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==}
+ cpu: [arm64]
+ os: [openharmony]
+
+ '@rollup/rollup-win32-arm64-msvc@4.57.1':
+ resolution: {integrity: sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==}
+ cpu: [arm64]
+ os: [win32]
+
+ '@rollup/rollup-win32-ia32-msvc@4.57.1':
+ resolution: {integrity: sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==}
+ cpu: [ia32]
+ os: [win32]
+
+ '@rollup/rollup-win32-x64-gnu@4.57.1':
+ resolution: {integrity: sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==}
+ cpu: [x64]
+ os: [win32]
+
+ '@rollup/rollup-win32-x64-msvc@4.57.1':
+ resolution: {integrity: sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==}
+ cpu: [x64]
+ os: [win32]
+
+ '@standard-schema/spec@1.1.0':
+ resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==}
+
+ '@sveltejs/acorn-typescript@1.0.8':
+ resolution: {integrity: sha512-esgN+54+q0NjB0Y/4BomT9samII7jGwNy/2a3wNZbT2A2RpmXsXwUt24LvLhx6jUq2gVk4cWEvcRO6MFQbOfNA==}
+ peerDependencies:
+ acorn: ^8.9.0
+
+ '@sveltejs/adapter-auto@7.0.0':
+ resolution: {integrity: sha512-ImDWaErTOCkRS4Gt+5gZuymKFBobnhChXUZ9lhUZLahUgvA4OOvRzi3sahzYgbxGj5nkA6OV0GAW378+dl/gyw==}
+ peerDependencies:
+ '@sveltejs/kit': ^2.0.0
+
+ '@sveltejs/adapter-node@5.5.2':
+ resolution: {integrity: sha512-L15Djwpr7HrSAPj/Z8PYfc0pa9A1tllrr18phKI0WJHJeoWw45yinPf0IGgVTmakqx1B3JQ+C/OFl9ZwmxHU1Q==}
+ peerDependencies:
+ '@sveltejs/kit': ^2.4.0
+
+ '@sveltejs/kit@2.50.2':
+ resolution: {integrity: sha512-875hTUkEbz+MyJIxWbQjfMaekqdmEKUUfR7JyKcpfMRZqcGyrO9Gd+iS1D/Dx8LpE5FEtutWGOtlAh4ReSAiOA==}
+ engines: {node: '>=18.13'}
+ hasBin: true
+ peerDependencies:
+ '@opentelemetry/api': ^1.0.0
+ '@sveltejs/vite-plugin-svelte': ^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0
+ svelte: ^4.0.0 || ^5.0.0-next.0
+ typescript: ^5.3.3
+ vite: ^5.0.3 || ^6.0.0 || ^7.0.0-beta.0
+ peerDependenciesMeta:
+ '@opentelemetry/api':
+ optional: true
+ typescript:
+ optional: true
+
+ '@sveltejs/vite-plugin-svelte-inspector@5.0.2':
+ resolution: {integrity: sha512-TZzRTcEtZffICSAoZGkPSl6Etsj2torOVrx6Uw0KpXxrec9Gg6jFWQ60Q3+LmNGfZSxHRCZL7vXVZIWmuV50Ig==}
+ engines: {node: ^20.19 || ^22.12 || >=24}
+ peerDependencies:
+ '@sveltejs/vite-plugin-svelte': ^6.0.0-next.0
+ svelte: ^5.0.0
+ vite: ^6.3.0 || ^7.0.0
+
+ '@sveltejs/vite-plugin-svelte@6.2.4':
+ resolution: {integrity: sha512-ou/d51QSdTyN26D7h6dSpusAKaZkAiGM55/AKYi+9AGZw7q85hElbjK3kEyzXHhLSnRISHOYzVge6x0jRZ7DXA==}
+ engines: {node: ^20.19 || ^22.12 || >=24}
+ peerDependencies:
+ svelte: ^5.0.0
+ vite: ^6.3.0 || ^7.0.0
+
+ '@tailwindcss/node@4.1.18':
+ resolution: {integrity: sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ==}
+
+ '@tailwindcss/oxide-android-arm64@4.1.18':
+ resolution: {integrity: sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q==}
+ engines: {node: '>= 10'}
+ cpu: [arm64]
+ os: [android]
+
+ '@tailwindcss/oxide-darwin-arm64@4.1.18':
+ resolution: {integrity: sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A==}
+ engines: {node: '>= 10'}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@tailwindcss/oxide-darwin-x64@4.1.18':
+ resolution: {integrity: sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw==}
+ engines: {node: '>= 10'}
+ cpu: [x64]
+ os: [darwin]
+
+ '@tailwindcss/oxide-freebsd-x64@4.1.18':
+ resolution: {integrity: sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA==}
+ engines: {node: '>= 10'}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18':
+ resolution: {integrity: sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA==}
+ engines: {node: '>= 10'}
+ cpu: [arm]
+ os: [linux]
+
+ '@tailwindcss/oxide-linux-arm64-gnu@4.1.18':
+ resolution: {integrity: sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw==}
+ engines: {node: '>= 10'}
+ cpu: [arm64]
+ os: [linux]
+ libc: [glibc]
+
+ '@tailwindcss/oxide-linux-arm64-musl@4.1.18':
+ resolution: {integrity: sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==}
+ engines: {node: '>= 10'}
+ cpu: [arm64]
+ os: [linux]
+ libc: [musl]
+
+ '@tailwindcss/oxide-linux-x64-gnu@4.1.18':
+ resolution: {integrity: sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==}
+ engines: {node: '>= 10'}
+ cpu: [x64]
+ os: [linux]
+ libc: [glibc]
+
+ '@tailwindcss/oxide-linux-x64-musl@4.1.18':
+ resolution: {integrity: sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==}
+ engines: {node: '>= 10'}
+ cpu: [x64]
+ os: [linux]
+ libc: [musl]
+
+ '@tailwindcss/oxide-wasm32-wasi@4.1.18':
+ resolution: {integrity: sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==}
+ engines: {node: '>=14.0.0'}
+ cpu: [wasm32]
+ bundledDependencies:
+ - '@napi-rs/wasm-runtime'
+ - '@emnapi/core'
+ - '@emnapi/runtime'
+ - '@tybys/wasm-util'
+ - '@emnapi/wasi-threads'
+ - tslib
+
+ '@tailwindcss/oxide-win32-arm64-msvc@4.1.18':
+ resolution: {integrity: sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA==}
+ engines: {node: '>= 10'}
+ cpu: [arm64]
+ os: [win32]
+
+ '@tailwindcss/oxide-win32-x64-msvc@4.1.18':
+ resolution: {integrity: sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q==}
+ engines: {node: '>= 10'}
+ cpu: [x64]
+ os: [win32]
+
+ '@tailwindcss/oxide@4.1.18':
+ resolution: {integrity: sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A==}
+ engines: {node: '>= 10'}
+
+ '@tailwindcss/vite@4.1.18':
+ resolution: {integrity: sha512-jVA+/UpKL1vRLg6Hkao5jldawNmRo7mQYrZtNHMIVpLfLhDml5nMRUo/8MwoX2vNXvnaXNNMedrMfMugAVX1nA==}
+ peerDependencies:
+ vite: ^5.2.0 || ^6 || ^7
+
+ '@types/cookie@0.6.0':
+ resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==}
+
+ '@types/estree@1.0.8':
+ resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
+
+ '@types/resolve@1.20.2':
+ resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==}
+
+ acorn@8.15.0:
+ resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==}
+ engines: {node: '>=0.4.0'}
+ hasBin: true
+
+ aria-query@5.3.2:
+ resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==}
+ engines: {node: '>= 0.4'}
+
+ axobject-query@4.1.0:
+ resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==}
+ engines: {node: '>= 0.4'}
+
+ chokidar@4.0.3:
+ resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==}
+ engines: {node: '>= 14.16.0'}
+
+ clsx@2.1.1:
+ resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==}
+ engines: {node: '>=6'}
+
+ commondir@1.0.1:
+ resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==}
+
+ cookie@0.6.0:
+ resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==}
+ engines: {node: '>= 0.6'}
+
+ deepmerge@4.3.1:
+ resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
+ engines: {node: '>=0.10.0'}
+
+ detect-libc@2.1.2:
+ resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
+ engines: {node: '>=8'}
+
+ devalue@5.6.2:
+ resolution: {integrity: sha512-nPRkjWzzDQlsejL1WVifk5rvcFi/y1onBRxjaFMjZeR9mFpqu2gmAZ9xUB9/IEanEP/vBtGeGganC/GO1fmufg==}
+
+ enhanced-resolve@5.19.0:
+ resolution: {integrity: sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==}
+ engines: {node: '>=10.13.0'}
+
+ esbuild@0.27.3:
+ resolution: {integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==}
+ engines: {node: '>=18'}
+ hasBin: true
+
+ esm-env@1.2.2:
+ resolution: {integrity: sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==}
+
+ esrap@2.2.2:
+ resolution: {integrity: sha512-zA6497ha+qKvoWIK+WM9NAh5ni17sKZKhbS5B3PoYbBvaYHZWoS33zmFybmyqpn07RLUxSmn+RCls2/XF+d0oQ==}
+
+ estree-walker@2.0.2:
+ resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
+
+ fdir@6.5.0:
+ resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
+ engines: {node: '>=12.0.0'}
+ peerDependencies:
+ picomatch: ^3 || ^4
+ peerDependenciesMeta:
+ picomatch:
+ optional: true
+
+ fsevents@2.3.3:
+ resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
+ engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+ os: [darwin]
+
+ function-bind@1.1.2:
+ resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
+
+ graceful-fs@4.2.11:
+ resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
+
+ hasown@2.0.2:
+ resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
+ engines: {node: '>= 0.4'}
+
+ is-core-module@2.16.1:
+ resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==}
+ engines: {node: '>= 0.4'}
+
+ is-module@1.0.0:
+ resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==}
+
+ is-reference@1.2.1:
+ resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==}
+
+ is-reference@3.0.3:
+ resolution: {integrity: sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==}
+
+ jiti@2.6.1:
+ resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==}
+ hasBin: true
+
+ jose@6.1.3:
+ resolution: {integrity: sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==}
+
+ kleur@4.1.5:
+ resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==}
+ engines: {node: '>=6'}
+
+ lightningcss-android-arm64@1.30.2:
+ resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [android]
+
+ lightningcss-darwin-arm64@1.30.2:
+ resolution: {integrity: sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [darwin]
+
+ lightningcss-darwin-x64@1.30.2:
+ resolution: {integrity: sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [darwin]
+
+ lightningcss-freebsd-x64@1.30.2:
+ resolution: {integrity: sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [freebsd]
+
+ lightningcss-linux-arm-gnueabihf@1.30.2:
+ resolution: {integrity: sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm]
+ os: [linux]
+
+ lightningcss-linux-arm64-gnu@1.30.2:
+ resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [linux]
+ libc: [glibc]
+
+ lightningcss-linux-arm64-musl@1.30.2:
+ resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [linux]
+ libc: [musl]
+
+ lightningcss-linux-x64-gnu@1.30.2:
+ resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [linux]
+ libc: [glibc]
+
+ lightningcss-linux-x64-musl@1.30.2:
+ resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [linux]
+ libc: [musl]
+
+ lightningcss-win32-arm64-msvc@1.30.2:
+ resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [win32]
+
+ lightningcss-win32-x64-msvc@1.30.2:
+ resolution: {integrity: sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [win32]
+
+ lightningcss@1.30.2:
+ resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==}
+ engines: {node: '>= 12.0.0'}
+
+ locate-character@3.0.0:
+ resolution: {integrity: sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==}
+
+ magic-string@0.30.21:
+ resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
+
+ mri@1.2.0:
+ resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
+ engines: {node: '>=4'}
+
+ mrmime@2.0.1:
+ resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==}
+ engines: {node: '>=10'}
+
+ nanoid@3.3.11:
+ resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
+ engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
+ hasBin: true
+
+ oauth4webapi@3.8.4:
+ resolution: {integrity: sha512-EKlVEgav8zH31IXxvhCqjEgQws6S9QmnmJyLXmeV5REf59g7VmqRVa5l/rhGWtUqGm2rLVTNwukn9hla5kJ2WQ==}
+
+ obug@2.1.1:
+ resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==}
+
+ path-parse@1.0.7:
+ resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
+
+ picocolors@1.1.1:
+ resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
+
+ picomatch@4.0.3:
+ resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==}
+ engines: {node: '>=12'}
+
+ postcss@8.5.6:
+ resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
+ engines: {node: ^10 || ^12 || >=14}
+
+ preact-render-to-string@6.5.11:
+ resolution: {integrity: sha512-ubnauqoGczeGISiOh6RjX0/cdaF8v/oDXIjO85XALCQjwQP+SB4RDXXtvZ6yTYSjG+PC1QRP2AhPgCEsM2EvUw==}
+ peerDependencies:
+ preact: '>=10'
+
+ preact@10.24.3:
+ resolution: {integrity: sha512-Z2dPnBnMUfyQfSQ+GBdsGa16hz35YmLmtTLhM169uW944hYL6xzTYkJjC07j+Wosz733pMWx0fgON3JNw1jJQA==}
+
+ readdirp@4.1.2:
+ resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==}
+ engines: {node: '>= 14.18.0'}
+
+ resolve@1.22.11:
+ resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==}
+ engines: {node: '>= 0.4'}
+ hasBin: true
+
+ rollup@4.57.1:
+ resolution: {integrity: sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==}
+ engines: {node: '>=18.0.0', npm: '>=8.0.0'}
+ hasBin: true
+
+ sade@1.8.1:
+ resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==}
+ engines: {node: '>=6'}
+
+ set-cookie-parser@2.7.2:
+ resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==}
+
+ set-cookie-parser@3.0.1:
+ resolution: {integrity: sha512-n7Z7dXZhJbwuAHhNzkTti6Aw9QDDjZtm3JTpTGATIdNzdQz5GuFs22w90BcvF4INfnrL5xrX3oGsuqO5Dx3A1Q==}
+
+ sirv@3.0.2:
+ resolution: {integrity: sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==}
+ engines: {node: '>=18'}
+
+ source-map-js@1.2.1:
+ resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
+ engines: {node: '>=0.10.0'}
+
+ supports-preserve-symlinks-flag@1.0.0:
+ resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
+ engines: {node: '>= 0.4'}
+
+ svelte-check@4.3.6:
+ resolution: {integrity: sha512-uBkz96ElE3G4pt9E1Tw0xvBfIUQkeH794kDQZdAUk795UVMr+NJZpuFSS62vcmO/DuSalK83LyOwhgWq8YGU1Q==}
+ engines: {node: '>= 18.0.0'}
+ hasBin: true
+ peerDependencies:
+ svelte: ^4.0.0 || ^5.0.0-next.0
+ typescript: '>=5.0.0'
+
+ svelte@5.50.0:
+ resolution: {integrity: sha512-FR9kTLmX5i0oyeQ5j/+w8DuagIkQ7MWMuPpPVioW2zx9Dw77q+1ufLzF1IqNtcTXPRnIIio4PlasliVn43OnbQ==}
+ engines: {node: '>=18'}
+
+ tailwindcss@4.1.18:
+ resolution: {integrity: sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==}
+
+ tapable@2.3.0:
+ resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==}
+ engines: {node: '>=6'}
+
+ tinyglobby@0.2.15:
+ resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==}
+ engines: {node: '>=12.0.0'}
+
+ totalist@3.0.1:
+ resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==}
+ engines: {node: '>=6'}
+
+ typescript@5.9.3:
+ resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
+ engines: {node: '>=14.17'}
+ hasBin: true
+
+ vite@7.3.1:
+ resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ hasBin: true
+ 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
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
+ jiti:
+ optional: true
+ less:
+ optional: true
+ lightningcss:
+ optional: true
+ sass:
+ optional: true
+ sass-embedded:
+ optional: true
+ stylus:
+ optional: true
+ sugarss:
+ optional: true
+ terser:
+ optional: true
+ tsx:
+ optional: true
+ yaml:
+ optional: true
+
+ vitefu@1.1.1:
+ resolution: {integrity: sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ==}
+ peerDependencies:
+ vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0
+ peerDependenciesMeta:
+ vite:
+ optional: true
+
+ zimmerframe@1.1.4:
+ resolution: {integrity: sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==}
+
+snapshots:
+
+ '@auth/core@0.38.0':
+ dependencies:
+ '@panva/hkdf': 1.2.1
+ jose: 6.1.3
+ oauth4webapi: 3.8.4
+ preact: 10.24.3
+ preact-render-to-string: 6.5.11(preact@10.24.3)
+
+ '@auth/core@0.41.1':
+ dependencies:
+ '@panva/hkdf': 1.2.1
+ jose: 6.1.3
+ oauth4webapi: 3.8.4
+ preact: 10.24.3
+ preact-render-to-string: 6.5.11(preact@10.24.3)
+
+ '@auth/sveltekit@1.11.1(@sveltejs/kit@2.50.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.50.0)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.50.0)(typescript@5.9.3)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.50.0)':
+ dependencies:
+ '@auth/core': 0.41.1
+ '@sveltejs/kit': 2.50.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.50.0)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.50.0)(typescript@5.9.3)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.30.2))
+ set-cookie-parser: 2.7.2
+ svelte: 5.50.0
+
+ '@esbuild/aix-ppc64@0.27.3':
+ optional: true
+
+ '@esbuild/android-arm64@0.27.3':
+ optional: true
+
+ '@esbuild/android-arm@0.27.3':
+ optional: true
+
+ '@esbuild/android-x64@0.27.3':
+ optional: true
+
+ '@esbuild/darwin-arm64@0.27.3':
+ optional: true
+
+ '@esbuild/darwin-x64@0.27.3':
+ optional: true
+
+ '@esbuild/freebsd-arm64@0.27.3':
+ optional: true
+
+ '@esbuild/freebsd-x64@0.27.3':
+ optional: true
+
+ '@esbuild/linux-arm64@0.27.3':
+ optional: true
+
+ '@esbuild/linux-arm@0.27.3':
+ optional: true
+
+ '@esbuild/linux-ia32@0.27.3':
+ optional: true
+
+ '@esbuild/linux-loong64@0.27.3':
+ optional: true
+
+ '@esbuild/linux-mips64el@0.27.3':
+ optional: true
+
+ '@esbuild/linux-ppc64@0.27.3':
+ optional: true
+
+ '@esbuild/linux-riscv64@0.27.3':
+ optional: true
+
+ '@esbuild/linux-s390x@0.27.3':
+ optional: true
+
+ '@esbuild/linux-x64@0.27.3':
+ optional: true
+
+ '@esbuild/netbsd-arm64@0.27.3':
+ optional: true
+
+ '@esbuild/netbsd-x64@0.27.3':
+ optional: true
+
+ '@esbuild/openbsd-arm64@0.27.3':
+ optional: true
+
+ '@esbuild/openbsd-x64@0.27.3':
+ optional: true
+
+ '@esbuild/openharmony-arm64@0.27.3':
+ optional: true
+
+ '@esbuild/sunos-x64@0.27.3':
+ optional: true
+
+ '@esbuild/win32-arm64@0.27.3':
+ optional: true
+
+ '@esbuild/win32-ia32@0.27.3':
+ optional: true
+
+ '@esbuild/win32-x64@0.27.3':
+ optional: true
+
+ '@jridgewell/gen-mapping@0.3.13':
+ dependencies:
+ '@jridgewell/sourcemap-codec': 1.5.5
+ '@jridgewell/trace-mapping': 0.3.31
+
+ '@jridgewell/remapping@2.3.5':
+ dependencies:
+ '@jridgewell/gen-mapping': 0.3.13
+ '@jridgewell/trace-mapping': 0.3.31
+
+ '@jridgewell/resolve-uri@3.1.2': {}
+
+ '@jridgewell/sourcemap-codec@1.5.5': {}
+
+ '@jridgewell/trace-mapping@0.3.31':
+ dependencies:
+ '@jridgewell/resolve-uri': 3.1.2
+ '@jridgewell/sourcemap-codec': 1.5.5
+
+ '@panva/hkdf@1.2.1': {}
+
+ '@polka/url@1.0.0-next.29': {}
+
+ '@rollup/plugin-commonjs@28.0.9(rollup@4.57.1)':
+ dependencies:
+ '@rollup/pluginutils': 5.3.0(rollup@4.57.1)
+ commondir: 1.0.1
+ estree-walker: 2.0.2
+ fdir: 6.5.0(picomatch@4.0.3)
+ is-reference: 1.2.1
+ magic-string: 0.30.21
+ picomatch: 4.0.3
+ optionalDependencies:
+ rollup: 4.57.1
+
+ '@rollup/plugin-json@6.1.0(rollup@4.57.1)':
+ dependencies:
+ '@rollup/pluginutils': 5.3.0(rollup@4.57.1)
+ optionalDependencies:
+ rollup: 4.57.1
+
+ '@rollup/plugin-node-resolve@16.0.3(rollup@4.57.1)':
+ dependencies:
+ '@rollup/pluginutils': 5.3.0(rollup@4.57.1)
+ '@types/resolve': 1.20.2
+ deepmerge: 4.3.1
+ is-module: 1.0.0
+ resolve: 1.22.11
+ optionalDependencies:
+ rollup: 4.57.1
+
+ '@rollup/pluginutils@5.3.0(rollup@4.57.1)':
+ dependencies:
+ '@types/estree': 1.0.8
+ estree-walker: 2.0.2
+ picomatch: 4.0.3
+ optionalDependencies:
+ rollup: 4.57.1
+
+ '@rollup/rollup-android-arm-eabi@4.57.1':
+ optional: true
+
+ '@rollup/rollup-android-arm64@4.57.1':
+ optional: true
+
+ '@rollup/rollup-darwin-arm64@4.57.1':
+ optional: true
+
+ '@rollup/rollup-darwin-x64@4.57.1':
+ optional: true
+
+ '@rollup/rollup-freebsd-arm64@4.57.1':
+ optional: true
+
+ '@rollup/rollup-freebsd-x64@4.57.1':
+ optional: true
+
+ '@rollup/rollup-linux-arm-gnueabihf@4.57.1':
+ optional: true
+
+ '@rollup/rollup-linux-arm-musleabihf@4.57.1':
+ optional: true
+
+ '@rollup/rollup-linux-arm64-gnu@4.57.1':
+ optional: true
+
+ '@rollup/rollup-linux-arm64-musl@4.57.1':
+ optional: true
+
+ '@rollup/rollup-linux-loong64-gnu@4.57.1':
+ optional: true
+
+ '@rollup/rollup-linux-loong64-musl@4.57.1':
+ optional: true
+
+ '@rollup/rollup-linux-ppc64-gnu@4.57.1':
+ optional: true
+
+ '@rollup/rollup-linux-ppc64-musl@4.57.1':
+ optional: true
+
+ '@rollup/rollup-linux-riscv64-gnu@4.57.1':
+ optional: true
+
+ '@rollup/rollup-linux-riscv64-musl@4.57.1':
+ optional: true
+
+ '@rollup/rollup-linux-s390x-gnu@4.57.1':
+ optional: true
+
+ '@rollup/rollup-linux-x64-gnu@4.57.1':
+ optional: true
+
+ '@rollup/rollup-linux-x64-musl@4.57.1':
+ optional: true
+
+ '@rollup/rollup-openbsd-x64@4.57.1':
+ optional: true
+
+ '@rollup/rollup-openharmony-arm64@4.57.1':
+ optional: true
+
+ '@rollup/rollup-win32-arm64-msvc@4.57.1':
+ optional: true
+
+ '@rollup/rollup-win32-ia32-msvc@4.57.1':
+ optional: true
+
+ '@rollup/rollup-win32-x64-gnu@4.57.1':
+ optional: true
+
+ '@rollup/rollup-win32-x64-msvc@4.57.1':
+ optional: true
+
+ '@standard-schema/spec@1.1.0': {}
+
+ '@sveltejs/acorn-typescript@1.0.8(acorn@8.15.0)':
+ dependencies:
+ acorn: 8.15.0
+
+ '@sveltejs/adapter-auto@7.0.0(@sveltejs/kit@2.50.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.50.0)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.50.0)(typescript@5.9.3)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.30.2)))':
+ dependencies:
+ '@sveltejs/kit': 2.50.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.50.0)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.50.0)(typescript@5.9.3)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.30.2))
+
+ '@sveltejs/adapter-node@5.5.2(@sveltejs/kit@2.50.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.50.0)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.50.0)(typescript@5.9.3)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.30.2)))':
+ dependencies:
+ '@rollup/plugin-commonjs': 28.0.9(rollup@4.57.1)
+ '@rollup/plugin-json': 6.1.0(rollup@4.57.1)
+ '@rollup/plugin-node-resolve': 16.0.3(rollup@4.57.1)
+ '@sveltejs/kit': 2.50.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.50.0)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.50.0)(typescript@5.9.3)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.30.2))
+ rollup: 4.57.1
+
+ '@sveltejs/kit@2.50.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.50.0)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.50.0)(typescript@5.9.3)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.30.2))':
+ dependencies:
+ '@standard-schema/spec': 1.1.0
+ '@sveltejs/acorn-typescript': 1.0.8(acorn@8.15.0)
+ '@sveltejs/vite-plugin-svelte': 6.2.4(svelte@5.50.0)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.30.2))
+ '@types/cookie': 0.6.0
+ acorn: 8.15.0
+ cookie: 0.6.0
+ devalue: 5.6.2
+ esm-env: 1.2.2
+ kleur: 4.1.5
+ magic-string: 0.30.21
+ mrmime: 2.0.1
+ sade: 1.8.1
+ set-cookie-parser: 3.0.1
+ sirv: 3.0.2
+ svelte: 5.50.0
+ vite: 7.3.1(jiti@2.6.1)(lightningcss@1.30.2)
+ optionalDependencies:
+ typescript: 5.9.3
+
+ '@sveltejs/vite-plugin-svelte-inspector@5.0.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.50.0)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.50.0)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.30.2))':
+ dependencies:
+ '@sveltejs/vite-plugin-svelte': 6.2.4(svelte@5.50.0)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.30.2))
+ obug: 2.1.1
+ svelte: 5.50.0
+ vite: 7.3.1(jiti@2.6.1)(lightningcss@1.30.2)
+
+ '@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.50.0)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.30.2))':
+ dependencies:
+ '@sveltejs/vite-plugin-svelte-inspector': 5.0.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.50.0)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.50.0)(vite@7.3.1(jiti@2.6.1)(lightningcss@1.30.2))
+ deepmerge: 4.3.1
+ magic-string: 0.30.21
+ obug: 2.1.1
+ svelte: 5.50.0
+ vite: 7.3.1(jiti@2.6.1)(lightningcss@1.30.2)
+ vitefu: 1.1.1(vite@7.3.1(jiti@2.6.1)(lightningcss@1.30.2))
+
+ '@tailwindcss/node@4.1.18':
+ dependencies:
+ '@jridgewell/remapping': 2.3.5
+ enhanced-resolve: 5.19.0
+ jiti: 2.6.1
+ lightningcss: 1.30.2
+ magic-string: 0.30.21
+ source-map-js: 1.2.1
+ tailwindcss: 4.1.18
+
+ '@tailwindcss/oxide-android-arm64@4.1.18':
+ optional: true
+
+ '@tailwindcss/oxide-darwin-arm64@4.1.18':
+ optional: true
+
+ '@tailwindcss/oxide-darwin-x64@4.1.18':
+ optional: true
+
+ '@tailwindcss/oxide-freebsd-x64@4.1.18':
+ optional: true
+
+ '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18':
+ optional: true
+
+ '@tailwindcss/oxide-linux-arm64-gnu@4.1.18':
+ optional: true
+
+ '@tailwindcss/oxide-linux-arm64-musl@4.1.18':
+ optional: true
+
+ '@tailwindcss/oxide-linux-x64-gnu@4.1.18':
+ optional: true
+
+ '@tailwindcss/oxide-linux-x64-musl@4.1.18':
+ optional: true
+
+ '@tailwindcss/oxide-wasm32-wasi@4.1.18':
+ optional: true
+
+ '@tailwindcss/oxide-win32-arm64-msvc@4.1.18':
+ optional: true
+
+ '@tailwindcss/oxide-win32-x64-msvc@4.1.18':
+ optional: true
+
+ '@tailwindcss/oxide@4.1.18':
+ optionalDependencies:
+ '@tailwindcss/oxide-android-arm64': 4.1.18
+ '@tailwindcss/oxide-darwin-arm64': 4.1.18
+ '@tailwindcss/oxide-darwin-x64': 4.1.18
+ '@tailwindcss/oxide-freebsd-x64': 4.1.18
+ '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.18
+ '@tailwindcss/oxide-linux-arm64-gnu': 4.1.18
+ '@tailwindcss/oxide-linux-arm64-musl': 4.1.18
+ '@tailwindcss/oxide-linux-x64-gnu': 4.1.18
+ '@tailwindcss/oxide-linux-x64-musl': 4.1.18
+ '@tailwindcss/oxide-wasm32-wasi': 4.1.18
+ '@tailwindcss/oxide-win32-arm64-msvc': 4.1.18
+ '@tailwindcss/oxide-win32-x64-msvc': 4.1.18
+
+ '@tailwindcss/vite@4.1.18(vite@7.3.1(jiti@2.6.1)(lightningcss@1.30.2))':
+ dependencies:
+ '@tailwindcss/node': 4.1.18
+ '@tailwindcss/oxide': 4.1.18
+ tailwindcss: 4.1.18
+ vite: 7.3.1(jiti@2.6.1)(lightningcss@1.30.2)
+
+ '@types/cookie@0.6.0': {}
+
+ '@types/estree@1.0.8': {}
+
+ '@types/resolve@1.20.2': {}
+
+ acorn@8.15.0: {}
+
+ aria-query@5.3.2: {}
+
+ axobject-query@4.1.0: {}
+
+ chokidar@4.0.3:
+ dependencies:
+ readdirp: 4.1.2
+
+ clsx@2.1.1: {}
+
+ commondir@1.0.1: {}
+
+ cookie@0.6.0: {}
+
+ deepmerge@4.3.1: {}
+
+ detect-libc@2.1.2: {}
+
+ devalue@5.6.2: {}
+
+ enhanced-resolve@5.19.0:
+ dependencies:
+ graceful-fs: 4.2.11
+ tapable: 2.3.0
+
+ esbuild@0.27.3:
+ optionalDependencies:
+ '@esbuild/aix-ppc64': 0.27.3
+ '@esbuild/android-arm': 0.27.3
+ '@esbuild/android-arm64': 0.27.3
+ '@esbuild/android-x64': 0.27.3
+ '@esbuild/darwin-arm64': 0.27.3
+ '@esbuild/darwin-x64': 0.27.3
+ '@esbuild/freebsd-arm64': 0.27.3
+ '@esbuild/freebsd-x64': 0.27.3
+ '@esbuild/linux-arm': 0.27.3
+ '@esbuild/linux-arm64': 0.27.3
+ '@esbuild/linux-ia32': 0.27.3
+ '@esbuild/linux-loong64': 0.27.3
+ '@esbuild/linux-mips64el': 0.27.3
+ '@esbuild/linux-ppc64': 0.27.3
+ '@esbuild/linux-riscv64': 0.27.3
+ '@esbuild/linux-s390x': 0.27.3
+ '@esbuild/linux-x64': 0.27.3
+ '@esbuild/netbsd-arm64': 0.27.3
+ '@esbuild/netbsd-x64': 0.27.3
+ '@esbuild/openbsd-arm64': 0.27.3
+ '@esbuild/openbsd-x64': 0.27.3
+ '@esbuild/openharmony-arm64': 0.27.3
+ '@esbuild/sunos-x64': 0.27.3
+ '@esbuild/win32-arm64': 0.27.3
+ '@esbuild/win32-ia32': 0.27.3
+ '@esbuild/win32-x64': 0.27.3
+
+ esm-env@1.2.2: {}
+
+ esrap@2.2.2:
+ dependencies:
+ '@jridgewell/sourcemap-codec': 1.5.5
+
+ estree-walker@2.0.2: {}
+
+ fdir@6.5.0(picomatch@4.0.3):
+ optionalDependencies:
+ picomatch: 4.0.3
+
+ fsevents@2.3.3:
+ optional: true
+
+ function-bind@1.1.2: {}
+
+ graceful-fs@4.2.11: {}
+
+ hasown@2.0.2:
+ dependencies:
+ function-bind: 1.1.2
+
+ is-core-module@2.16.1:
+ dependencies:
+ hasown: 2.0.2
+
+ is-module@1.0.0: {}
+
+ is-reference@1.2.1:
+ dependencies:
+ '@types/estree': 1.0.8
+
+ is-reference@3.0.3:
+ dependencies:
+ '@types/estree': 1.0.8
+
+ jiti@2.6.1: {}
+
+ jose@6.1.3: {}
+
+ kleur@4.1.5: {}
+
+ lightningcss-android-arm64@1.30.2:
+ optional: true
+
+ lightningcss-darwin-arm64@1.30.2:
+ optional: true
+
+ lightningcss-darwin-x64@1.30.2:
+ optional: true
+
+ lightningcss-freebsd-x64@1.30.2:
+ optional: true
+
+ lightningcss-linux-arm-gnueabihf@1.30.2:
+ optional: true
+
+ lightningcss-linux-arm64-gnu@1.30.2:
+ optional: true
+
+ lightningcss-linux-arm64-musl@1.30.2:
+ optional: true
+
+ lightningcss-linux-x64-gnu@1.30.2:
+ optional: true
+
+ lightningcss-linux-x64-musl@1.30.2:
+ optional: true
+
+ lightningcss-win32-arm64-msvc@1.30.2:
+ optional: true
+
+ lightningcss-win32-x64-msvc@1.30.2:
+ optional: true
+
+ lightningcss@1.30.2:
+ dependencies:
+ detect-libc: 2.1.2
+ 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
+
+ locate-character@3.0.0: {}
+
+ magic-string@0.30.21:
+ dependencies:
+ '@jridgewell/sourcemap-codec': 1.5.5
+
+ mri@1.2.0: {}
+
+ mrmime@2.0.1: {}
+
+ nanoid@3.3.11: {}
+
+ oauth4webapi@3.8.4: {}
+
+ obug@2.1.1: {}
+
+ path-parse@1.0.7: {}
+
+ picocolors@1.1.1: {}
+
+ picomatch@4.0.3: {}
+
+ postcss@8.5.6:
+ dependencies:
+ nanoid: 3.3.11
+ picocolors: 1.1.1
+ source-map-js: 1.2.1
+
+ preact-render-to-string@6.5.11(preact@10.24.3):
+ dependencies:
+ preact: 10.24.3
+
+ preact@10.24.3: {}
+
+ readdirp@4.1.2: {}
+
+ resolve@1.22.11:
+ dependencies:
+ is-core-module: 2.16.1
+ path-parse: 1.0.7
+ supports-preserve-symlinks-flag: 1.0.0
+
+ rollup@4.57.1:
+ dependencies:
+ '@types/estree': 1.0.8
+ optionalDependencies:
+ '@rollup/rollup-android-arm-eabi': 4.57.1
+ '@rollup/rollup-android-arm64': 4.57.1
+ '@rollup/rollup-darwin-arm64': 4.57.1
+ '@rollup/rollup-darwin-x64': 4.57.1
+ '@rollup/rollup-freebsd-arm64': 4.57.1
+ '@rollup/rollup-freebsd-x64': 4.57.1
+ '@rollup/rollup-linux-arm-gnueabihf': 4.57.1
+ '@rollup/rollup-linux-arm-musleabihf': 4.57.1
+ '@rollup/rollup-linux-arm64-gnu': 4.57.1
+ '@rollup/rollup-linux-arm64-musl': 4.57.1
+ '@rollup/rollup-linux-loong64-gnu': 4.57.1
+ '@rollup/rollup-linux-loong64-musl': 4.57.1
+ '@rollup/rollup-linux-ppc64-gnu': 4.57.1
+ '@rollup/rollup-linux-ppc64-musl': 4.57.1
+ '@rollup/rollup-linux-riscv64-gnu': 4.57.1
+ '@rollup/rollup-linux-riscv64-musl': 4.57.1
+ '@rollup/rollup-linux-s390x-gnu': 4.57.1
+ '@rollup/rollup-linux-x64-gnu': 4.57.1
+ '@rollup/rollup-linux-x64-musl': 4.57.1
+ '@rollup/rollup-openbsd-x64': 4.57.1
+ '@rollup/rollup-openharmony-arm64': 4.57.1
+ '@rollup/rollup-win32-arm64-msvc': 4.57.1
+ '@rollup/rollup-win32-ia32-msvc': 4.57.1
+ '@rollup/rollup-win32-x64-gnu': 4.57.1
+ '@rollup/rollup-win32-x64-msvc': 4.57.1
+ fsevents: 2.3.3
+
+ sade@1.8.1:
+ dependencies:
+ mri: 1.2.0
+
+ set-cookie-parser@2.7.2: {}
+
+ set-cookie-parser@3.0.1: {}
+
+ sirv@3.0.2:
+ dependencies:
+ '@polka/url': 1.0.0-next.29
+ mrmime: 2.0.1
+ totalist: 3.0.1
+
+ source-map-js@1.2.1: {}
+
+ supports-preserve-symlinks-flag@1.0.0: {}
+
+ svelte-check@4.3.6(picomatch@4.0.3)(svelte@5.50.0)(typescript@5.9.3):
+ dependencies:
+ '@jridgewell/trace-mapping': 0.3.31
+ chokidar: 4.0.3
+ fdir: 6.5.0(picomatch@4.0.3)
+ picocolors: 1.1.1
+ sade: 1.8.1
+ svelte: 5.50.0
+ typescript: 5.9.3
+ transitivePeerDependencies:
+ - picomatch
+
+ svelte@5.50.0:
+ dependencies:
+ '@jridgewell/remapping': 2.3.5
+ '@jridgewell/sourcemap-codec': 1.5.5
+ '@sveltejs/acorn-typescript': 1.0.8(acorn@8.15.0)
+ '@types/estree': 1.0.8
+ acorn: 8.15.0
+ aria-query: 5.3.2
+ axobject-query: 4.1.0
+ clsx: 2.1.1
+ devalue: 5.6.2
+ esm-env: 1.2.2
+ esrap: 2.2.2
+ is-reference: 3.0.3
+ locate-character: 3.0.0
+ magic-string: 0.30.21
+ zimmerframe: 1.1.4
+
+ tailwindcss@4.1.18: {}
+
+ tapable@2.3.0: {}
+
+ tinyglobby@0.2.15:
+ dependencies:
+ fdir: 6.5.0(picomatch@4.0.3)
+ picomatch: 4.0.3
+
+ totalist@3.0.1: {}
+
+ typescript@5.9.3: {}
+
+ vite@7.3.1(jiti@2.6.1)(lightningcss@1.30.2):
+ dependencies:
+ esbuild: 0.27.3
+ fdir: 6.5.0(picomatch@4.0.3)
+ picomatch: 4.0.3
+ postcss: 8.5.6
+ rollup: 4.57.1
+ tinyglobby: 0.2.15
+ optionalDependencies:
+ fsevents: 2.3.3
+ jiti: 2.6.1
+ lightningcss: 1.30.2
+
+ vitefu@1.1.1(vite@7.3.1(jiti@2.6.1)(lightningcss@1.30.2)):
+ optionalDependencies:
+ vite: 7.3.1(jiti@2.6.1)(lightningcss@1.30.2)
+
+ zimmerframe@1.1.4: {}
diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml
new file mode 100644
index 0000000..e31e0c9
--- /dev/null
+++ b/pnpm-workspace.yaml
@@ -0,0 +1,5 @@
+packages:
+ - "apps/*"
+ - "packages/*"
+onlyBuiltDependencies:
+ - esbuild