1 Commits

Author SHA1 Message Date
bacba95adc WIP: add interface for wg provider 2025-03-16 00:11:31 -07:00
56 changed files with 650 additions and 884 deletions

View File

@@ -1,10 +0,0 @@
[*]
charset = utf-8
insert_final_newline = true
end_of_line = lf
indent_style = tab
indent_size = 2
max_line_length = 100
quote_type = single
trim_trailing_whitespace = true

View File

@@ -1,17 +1,12 @@
DATABASE_URL=file:local.db DATABASE_URL=file:local.db
PUBLIC_AUTH_AUTHENTIK_ENABLE=1 AUTH_DOMAIN=auth.lab.cazzzer.com
AUTH_AUTHENTIK_REQUIRE_INVITE=0 AUTH_CLIENT_ID=
AUTH_AUTHENTIK_DOMAIN=auth.lab.cazzzer.com AUTH_CLIENT_SECRET=
AUTH_AUTHENTIK_CLIENT_ID= GOOGLE_CLIENT_ID=
AUTH_AUTHENTIK_CLIENT_SECRET= GOOGLE_CLIENT_SECRET=
PUBLIC_AUTH_GOOGLE_ENABLE=1 INVITE_TOKEN=GUjdsz9aREFTEBYDrA3AajUE8oVys2xW
AUTH_GOOGLE_REQUIRE_INVITE=1
AUTH_GOOGLE_CLIENT_ID=
AUTH_GOOGLE_CLIENT_SECRET=
AUTH_INVITE_TOKEN=GUjdsz9aREFTEBYDrA3AajUE8oVys2xW
OPNSENSE_API_URL=https://opnsense.cazzzer.com OPNSENSE_API_URL=https://opnsense.cazzzer.com
OPNSENSE_API_KEY= OPNSENSE_API_KEY=

View File

@@ -1,15 +0,0 @@
when:
- event: [push]
steps:
- name: build
image: woodpeckerci/plugin-kaniko
settings:
registry: gitea.cazzzer.com
repo: ${CI_REPO,,}
# replace '/' in branch name
tags: ${CI_COMMIT_BRANCH/\//-}
cache: true
username:
from_secret: registry-username
password:
from_secret: registry-password

View File

@@ -1,7 +0,0 @@
// Folder-specific settings
//
// For a full list of overridable settings, and general information on folder-specific settings,
// see the documentation: https://zed.dev/docs/configuring-zed#settings-files
{
"formatter": "prettier"
}

View File

@@ -2,7 +2,7 @@
# see all versions at https://hub.docker.com/r/oven/bun/tags # see all versions at https://hub.docker.com/r/oven/bun/tags
FROM oven/bun:1-alpine AS base FROM oven/bun:1-alpine AS base
WORKDIR /app WORKDIR /app
COPY package.json bun.lock /app/ COPY package.json bun.lockb /app/
# install dependencies into temp directory # install dependencies into temp directory
# this will cache them and speed up future builds # this will cache them and speed up future builds
@@ -14,7 +14,7 @@ RUN cd /temp/dev && bun install --frozen-lockfile
# install with --production (exclude devDependencies) # install with --production (exclude devDependencies)
RUN mkdir -p /temp/prod RUN mkdir -p /temp/prod
COPY package.json bun.lock /temp/prod/ COPY package.json bun.lock /temp/prod/
RUN cd /temp/prod && bun install --frozen-lockfile --production --ignore-scripts RUN cd /temp/prod && bun install --frozen-lockfile --production
# copy node_modules from temp directory # copy node_modules from temp directory
# then copy all (non-ignored) project files into the image # then copy all (non-ignored) project files into the image

View File

@@ -18,7 +18,7 @@ and [wg-quick](https://www.wireguard.com/quickstart/) for standalone setups.
## Development ## Development
Development uses bun. Development uses bun.
An additional prepare step is needed to set up typia for type validation. An additional prepare step is needed to set up typia for type validation.
For example .env settings, see [.env.example](.env.example) For example .env settings, see [.env.example](.env.example)

196
bun.lock
View File

@@ -5,48 +5,48 @@
"name": "vpgen", "name": "vpgen",
"dependencies": { "dependencies": {
"@libsql/client": "^0.14.0", "@libsql/client": "^0.14.0",
"drizzle-kit": "^0.30.6", "drizzle-kit": "^0.30.5",
"drizzle-orm": "^0.38.4", "drizzle-orm": "^0.38.4",
}, },
"devDependencies": { "devDependencies": {
"@lucide/svelte": "^0.487.0",
"@oslojs/crypto": "^1.0.1", "@oslojs/crypto": "^1.0.1",
"@oslojs/encoding": "^1.1.0", "@oslojs/encoding": "^1.1.0",
"@ryoppippi/unplugin-typia": "npm:@jsr/ryoppippi__unplugin-typia", "@ryoppippi/unplugin-typia": "npm:@jsr/ryoppippi__unplugin-typia",
"@sveltejs/adapter-auto": "^3.3.1", "@sveltejs/adapter-auto": "^3.3.1",
"@sveltejs/adapter-node": "^5.2.12", "@sveltejs/adapter-node": "^5.2.12",
"@sveltejs/kit": "^2.20.7", "@sveltejs/kit": "^2.19.1",
"@sveltejs/vite-plugin-svelte": "^5.0.3", "@sveltejs/vite-plugin-svelte": "^5.0.3",
"@tailwindcss/container-queries": "^0.1.1", "@tailwindcss/container-queries": "^0.1.1",
"@tailwindcss/forms": "^0.5.10", "@tailwindcss/forms": "^0.5.10",
"@tailwindcss/typography": "^0.5.16", "@tailwindcss/typography": "^0.5.16",
"@types/better-sqlite3": "^7.6.13", "@types/better-sqlite3": "^7.6.12",
"@types/eslint": "^9.6.1", "@types/eslint": "^9.6.1",
"@types/qrcode-svg": "^1.1.5", "@types/qrcode-svg": "^1.1.5",
"arctic": "^2.3.4", "arctic": "^2.3.4",
"autoprefixer": "^10.4.21", "autoprefixer": "^10.4.21",
"bits-ui": "^1.3.19", "bits-ui": "^0.22.0",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"eslint": "^9.25.1", "eslint": "^9.22.0",
"eslint-config-prettier": "^9.1.0", "eslint-config-prettier": "^9.1.0",
"eslint-plugin-svelte": "^2.46.1", "eslint-plugin-svelte": "^2.46.1",
"globals": "^15.15.0", "globals": "^15.15.0",
"ip-address": "^10.0.1", "ip-address": "^10.0.1",
"lucide-svelte": "^0.469.0",
"prettier": "^3.5.3", "prettier": "^3.5.3",
"prettier-plugin-svelte": "^3.3.3", "prettier-plugin-svelte": "^3.3.3",
"prettier-plugin-tailwindcss": "^0.6.11", "prettier-plugin-tailwindcss": "^0.6.11",
"qrcode-svg": "^1.1.0", "qrcode-svg": "^1.1.0",
"svelte": "^5.28.1", "svelte": "^5.23.0",
"svelte-check": "^4.1.6", "svelte-check": "^4.1.5",
"tailwind-merge": "^2.6.0", "tailwind-merge": "^2.6.0",
"tailwind-variants": "^0.3.1", "tailwind-variants": "^0.3.1",
"tailwindcss": "^3.4.17", "tailwindcss": "^3.4.17",
"tailwindcss-animate": "^1.0.7", "tailwindcss-animate": "^1.0.7",
"ts-patch": "^3.3.0", "ts-patch": "^3.3.0",
"typescript": "~5.8.3", "typescript": "~5.8.2",
"typescript-eslint": "^8.31.0", "typescript-eslint": "^8.26.1",
"typia": "^8.2.0", "typia": "^8.0.2",
"vite": "^6.3.2", "vite": "^6.2.2",
}, },
}, },
}, },
@@ -115,19 +115,19 @@
"@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.1", "", {}, "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ=="], "@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.1", "", {}, "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ=="],
"@eslint/config-array": ["@eslint/config-array@0.20.0", "", { "dependencies": { "@eslint/object-schema": "^2.1.6", "debug": "^4.3.1", "minimatch": "^3.1.2" } }, "sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ=="], "@eslint/config-array": ["@eslint/config-array@0.19.2", "", { "dependencies": { "@eslint/object-schema": "^2.1.6", "debug": "^4.3.1", "minimatch": "^3.1.2" } }, "sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w=="],
"@eslint/config-helpers": ["@eslint/config-helpers@0.2.1", "", {}, "sha512-RI17tsD2frtDu/3dmI7QRrD4bedNKPM08ziRYaC5AhkGrzIAJelm9kJU1TznK+apx6V+cqRz8tfpEeG3oIyjxw=="], "@eslint/config-helpers": ["@eslint/config-helpers@0.1.0", "", {}, "sha512-kLrdPDJE1ckPo94kmPPf9Hfd0DU0Jw6oKYrhe+pwSC0iTUInmTa+w6fw8sGgcfkFJGNdWOUeOaDM4quW4a7OkA=="],
"@eslint/core": ["@eslint/core@0.13.0", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw=="], "@eslint/core": ["@eslint/core@0.12.0", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg=="],
"@eslint/eslintrc": ["@eslint/eslintrc@3.3.1", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ=="], "@eslint/eslintrc": ["@eslint/eslintrc@3.3.0", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "sha512-yaVPAiNAalnCZedKLdR21GOGILMLKPyqSLWaAjQFvYA2i/ciDi8ArYVr69Anohb6cH2Ukhqti4aFnYyPm8wdwQ=="],
"@eslint/js": ["@eslint/js@9.25.1", "", {}, "sha512-dEIwmjntEx8u3Uvv+kr3PDeeArL8Hw07H9kyYxCjnM9pBjfEhk6uLXSchxxzgiwtRhhzVzqmUSDFBOi1TuZ7qg=="], "@eslint/js": ["@eslint/js@9.22.0", "", {}, "sha512-vLFajx9o8d1/oL2ZkpMYbkLv8nDB6yaIwFNt7nI4+I80U/z03SxmfOMsLbvWr3p7C+Wnoh//aOu2pQW8cS0HCQ=="],
"@eslint/object-schema": ["@eslint/object-schema@2.1.6", "", {}, "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA=="], "@eslint/object-schema": ["@eslint/object-schema@2.1.6", "", {}, "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA=="],
"@eslint/plugin-kit": ["@eslint/plugin-kit@0.2.8", "", { "dependencies": { "@eslint/core": "^0.13.0", "levn": "^0.4.1" } }, "sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA=="], "@eslint/plugin-kit": ["@eslint/plugin-kit@0.2.7", "", { "dependencies": { "@eslint/core": "^0.12.0", "levn": "^0.4.1" } }, "sha512-JubJ5B2pJ4k4yGxaNLdbjrnk9d/iDz6/q8wOilpIowd6PJPgaxCuHBnBszq7Ce2TyMrywm5r4PnKm6V3iiZF+g=="],
"@floating-ui/core": ["@floating-ui/core@1.6.8", "", { "dependencies": { "@floating-ui/utils": "^0.2.8" } }, "sha512-7XJ9cPU+yI2QeLS+FCSlqNFZJq8arvswefkZrYI1yQBbftw6FyrZOxYSh+9S7z7TpeWlRt9zJ5IhM1WIL334jA=="], "@floating-ui/core": ["@floating-ui/core@1.6.8", "", { "dependencies": { "@floating-ui/utils": "^0.2.8" } }, "sha512-7XJ9cPU+yI2QeLS+FCSlqNFZJq8arvswefkZrYI1yQBbftw6FyrZOxYSh+9S7z7TpeWlRt9zJ5IhM1WIL334jA=="],
@@ -181,7 +181,7 @@
"@libsql/win32-x64-msvc": ["@libsql/win32-x64-msvc@0.4.7", "", { "os": "win32", "cpu": "x64" }, "sha512-7pJzOWzPm6oJUxml+PCDRzYQ4A1hTMHAciTAHfFK4fkbDZX33nWPVG7Y3vqdKtslcwAzwmrNDc6sXy2nwWnbiw=="], "@libsql/win32-x64-msvc": ["@libsql/win32-x64-msvc@0.4.7", "", { "os": "win32", "cpu": "x64" }, "sha512-7pJzOWzPm6oJUxml+PCDRzYQ4A1hTMHAciTAHfFK4fkbDZX33nWPVG7Y3vqdKtslcwAzwmrNDc6sXy2nwWnbiw=="],
"@lucide/svelte": ["@lucide/svelte@0.487.0", "", { "peerDependencies": { "svelte": "^5" } }, "sha512-27b/wUzWrqDJu97+1iSV2X8L2JGRWH/mAWAjHgazWxhGxVu/kS0p3SbNu6w3skNmQNEku33EKU1v44IVwULzbw=="], "@melt-ui/svelte": ["@melt-ui/svelte@0.76.2", "", { "dependencies": { "@floating-ui/core": "^1.3.1", "@floating-ui/dom": "^1.4.5", "@internationalized/date": "^3.5.0", "dequal": "^2.0.3", "focus-trap": "^7.5.2", "nanoid": "^5.0.4" }, "peerDependencies": { "svelte": ">=3 <5" } }, "sha512-7SbOa11tXUS95T3fReL+dwDs5FyJtCEqrqG3inRziDws346SYLsxOQ6HmX+4BkIsQh1R8U3XNa+EMmdMt38lMA=="],
"@neon-rs/load": ["@neon-rs/load@0.0.4", "", {}, "sha512-kTPhdZyTQxB+2wpiRcFWrDcejc4JI6tkPuS7UZCG4l6Zvc5kU/gGQ/ozvHTh1XR5tS+UlfAfGuPajjzQjCiHCw=="], "@neon-rs/load": ["@neon-rs/load@0.0.4", "", {}, "sha512-kTPhdZyTQxB+2wpiRcFWrDcejc4JI6tkPuS7UZCG4l6Zvc5kU/gGQ/ozvHTh1XR5tS+UlfAfGuPajjzQjCiHCw=="],
@@ -241,8 +241,6 @@
"@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.29.1", "", { "os": "linux", "cpu": "none" }, "sha512-G5pn0NChlbRM8OJWpJFMX4/i8OEU538uiSv0P6roZcbpe/WfhEO+AT8SHVKfp8qhDQzaz7Q+1/ixMy7hBRidnQ=="], "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.29.1", "", { "os": "linux", "cpu": "none" }, "sha512-G5pn0NChlbRM8OJWpJFMX4/i8OEU538uiSv0P6roZcbpe/WfhEO+AT8SHVKfp8qhDQzaz7Q+1/ixMy7hBRidnQ=="],
"@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.40.0", "", { "os": "linux", "cpu": "none" }, "sha512-rKmSj6EXQRnhSkE22+WvrqOqRtk733x3p5sWpZilhmjnkHkpeCgWsFFo0dGnUGeA+OZjRl3+VYq+HyCOEuwcxQ=="],
"@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.29.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-WM9lIkNdkhVwiArmLxFXpWndFGuOka4oJOZh8EP3Vb8q5lzdSCBuhjavJsw68Q9AKDGeOOIHYzYm4ZFvmWez5g=="], "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.29.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-WM9lIkNdkhVwiArmLxFXpWndFGuOka4oJOZh8EP3Vb8q5lzdSCBuhjavJsw68Q9AKDGeOOIHYzYm4ZFvmWez5g=="],
"@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.29.1", "", { "os": "linux", "cpu": "x64" }, "sha512-87xYCwb0cPGZFoGiErT1eDcssByaLX4fc0z2nRM6eMtV9njAfEE6OW3UniAoDhX4Iq5xQVpE6qO9aJbCFumKYQ=="], "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.29.1", "", { "os": "linux", "cpu": "x64" }, "sha512-87xYCwb0cPGZFoGiErT1eDcssByaLX4fc0z2nRM6eMtV9njAfEE6OW3UniAoDhX4Iq5xQVpE6qO9aJbCFumKYQ=="],
@@ -257,7 +255,7 @@
"@ryoppippi/unplugin-typia": ["@jsr/ryoppippi__unplugin-typia@1.2.0", "https://npm.jsr.io/~/11/@jsr/ryoppippi__unplugin-typia/1.2.0.tgz", { "dependencies": { "@rollup/pluginutils": "^5.1.3", "consola": "^3.2.3", "defu": "^6.1.4", "diff-match-patch": "^1.0.5", "find-cache-dir": "^5.0.0", "magic-string": "^0.30.14", "pathe": "^1.1.2", "pkg-types": "^1.2.1", "type-fest": "^4.30.0", "typescript": "~5.6.3", "typia": "^7.6.0", "unplugin": "^1.16.0", "vite": "^6.0.2" } }, "sha512-WslO8hg5nbTRn1LD+fYpHub1CnwOg1y3+ezjrRH6gdAXdamr9n4Vr3COe5ejE8EjM6Ai+5WgTlOT0NJMu7w3MQ=="], "@ryoppippi/unplugin-typia": ["@jsr/ryoppippi__unplugin-typia@1.2.0", "https://npm.jsr.io/~/11/@jsr/ryoppippi__unplugin-typia/1.2.0.tgz", { "dependencies": { "@rollup/pluginutils": "^5.1.3", "consola": "^3.2.3", "defu": "^6.1.4", "diff-match-patch": "^1.0.5", "find-cache-dir": "^5.0.0", "magic-string": "^0.30.14", "pathe": "^1.1.2", "pkg-types": "^1.2.1", "type-fest": "^4.30.0", "typescript": "~5.6.3", "typia": "^7.6.0", "unplugin": "^1.16.0", "vite": "^6.0.2" } }, "sha512-WslO8hg5nbTRn1LD+fYpHub1CnwOg1y3+ezjrRH6gdAXdamr9n4Vr3COe5ejE8EjM6Ai+5WgTlOT0NJMu7w3MQ=="],
"@samchon/openapi": ["@samchon/openapi@3.3.0", "", {}, "sha512-f8HMS0PVAKTGR0TwgiBX4PKlZRPfdtH5fJbtpUth3fMUZmikjZ7CBey8gX7HZgY4n/aYHyNQKcf/W/E2267oYw=="], "@samchon/openapi": ["@samchon/openapi@3.0.0", "", {}, "sha512-eVQlyKRYv1/C2Mikc1xZr7c0jMjg1vjPkeY/gheKB4c5WOOWyTNZ1uvnXR+ETpPHwaQ54I9NrQZhoNk6BEGuuw=="],
"@sveltejs/acorn-typescript": ["@sveltejs/acorn-typescript@1.0.5", "", { "peerDependencies": { "acorn": "^8.9.0" } }, "sha512-IwQk4yfwLdibDlrXVE04jTZYlLnwsTT2PIOQQGNLWfjavGifnk1JD1LcZjZaBTRcxZu2FfPfNLOE04DSu9lqtQ=="], "@sveltejs/acorn-typescript": ["@sveltejs/acorn-typescript@1.0.5", "", { "peerDependencies": { "acorn": "^8.9.0" } }, "sha512-IwQk4yfwLdibDlrXVE04jTZYlLnwsTT2PIOQQGNLWfjavGifnk1JD1LcZjZaBTRcxZu2FfPfNLOE04DSu9lqtQ=="],
@@ -265,7 +263,7 @@
"@sveltejs/adapter-node": ["@sveltejs/adapter-node@5.2.12", "", { "dependencies": { "@rollup/plugin-commonjs": "^28.0.1", "@rollup/plugin-json": "^6.1.0", "@rollup/plugin-node-resolve": "^16.0.0", "rollup": "^4.9.5" }, "peerDependencies": { "@sveltejs/kit": "^2.4.0" } }, "sha512-0bp4Yb3jKIEcZWVcJC/L1xXp9zzJS4hDwfb4VITAkfT4OVdkspSHsx7YhqJDbb2hgLl6R9Vs7VQR+fqIVOxPUQ=="], "@sveltejs/adapter-node": ["@sveltejs/adapter-node@5.2.12", "", { "dependencies": { "@rollup/plugin-commonjs": "^28.0.1", "@rollup/plugin-json": "^6.1.0", "@rollup/plugin-node-resolve": "^16.0.0", "rollup": "^4.9.5" }, "peerDependencies": { "@sveltejs/kit": "^2.4.0" } }, "sha512-0bp4Yb3jKIEcZWVcJC/L1xXp9zzJS4hDwfb4VITAkfT4OVdkspSHsx7YhqJDbb2hgLl6R9Vs7VQR+fqIVOxPUQ=="],
"@sveltejs/kit": ["@sveltejs/kit@2.20.7", "", { "dependencies": { "@types/cookie": "^0.6.0", "cookie": "^0.6.0", "devalue": "^5.1.0", "esm-env": "^1.2.2", "import-meta-resolve": "^4.1.0", "kleur": "^4.1.5", "magic-string": "^0.30.5", "mrmime": "^2.0.0", "sade": "^1.8.1", "set-cookie-parser": "^2.6.0", "sirv": "^3.0.0" }, "peerDependencies": { "@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0", "svelte": "^4.0.0 || ^5.0.0-next.0", "vite": "^5.0.3 || ^6.0.0" }, "bin": { "svelte-kit": "svelte-kit.js" } }, "sha512-dVbLMubpJJSLI4OYB+yWYNHGAhgc2bVevWuBjDj8jFUXIJOAnLwYP3vsmtcgoxNGUXoq0rHS5f7MFCsryb6nzg=="], "@sveltejs/kit": ["@sveltejs/kit@2.19.1", "", { "dependencies": { "@types/cookie": "^0.6.0", "cookie": "^0.6.0", "devalue": "^5.1.0", "esm-env": "^1.2.2", "import-meta-resolve": "^4.1.0", "kleur": "^4.1.5", "magic-string": "^0.30.5", "mrmime": "^2.0.0", "sade": "^1.8.1", "set-cookie-parser": "^2.6.0", "sirv": "^3.0.0" }, "peerDependencies": { "@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0", "svelte": "^4.0.0 || ^5.0.0-next.0", "vite": "^5.0.3 || ^6.0.0" }, "bin": { "svelte-kit": "svelte-kit.js" } }, "sha512-1u8FGWtT+V0eBSQpDtsjINhQd6RTjadvEgVApdNVxbUeOXmQTDENTeRiZw2i1lNUx1/5Wa65CHzxtMh3P3yviw=="],
"@sveltejs/vite-plugin-svelte": ["@sveltejs/vite-plugin-svelte@5.0.3", "", { "dependencies": { "@sveltejs/vite-plugin-svelte-inspector": "^4.0.1", "debug": "^4.4.0", "deepmerge": "^4.3.1", "kleur": "^4.1.5", "magic-string": "^0.30.15", "vitefu": "^1.0.4" }, "peerDependencies": { "svelte": "^5.0.0", "vite": "^6.0.0" } }, "sha512-MCFS6CrQDu1yGwspm4qtli0e63vaPCehf6V7pIMP15AsWgMKrqDGCPFF/0kn4SP0ii4aySu4Pa62+fIRGFMjgw=="], "@sveltejs/vite-plugin-svelte": ["@sveltejs/vite-plugin-svelte@5.0.3", "", { "dependencies": { "@sveltejs/vite-plugin-svelte-inspector": "^4.0.1", "debug": "^4.4.0", "deepmerge": "^4.3.1", "kleur": "^4.1.5", "magic-string": "^0.30.15", "vitefu": "^1.0.4" }, "peerDependencies": { "svelte": "^5.0.0", "vite": "^6.0.0" } }, "sha512-MCFS6CrQDu1yGwspm4qtli0e63vaPCehf6V7pIMP15AsWgMKrqDGCPFF/0kn4SP0ii4aySu4Pa62+fIRGFMjgw=="],
@@ -279,7 +277,7 @@
"@tailwindcss/typography": ["@tailwindcss/typography@0.5.16", "", { "dependencies": { "lodash.castarray": "^4.4.0", "lodash.isplainobject": "^4.0.6", "lodash.merge": "^4.6.2", "postcss-selector-parser": "6.0.10" }, "peerDependencies": { "tailwindcss": ">=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1" } }, "sha512-0wDLwCVF5V3x3b1SGXPCDcdsbDHMBe+lkFzBRaHeLvNi+nrrnZ1lA18u+OTWO8iSWU2GxUOCvlXtDuqftc1oiA=="], "@tailwindcss/typography": ["@tailwindcss/typography@0.5.16", "", { "dependencies": { "lodash.castarray": "^4.4.0", "lodash.isplainobject": "^4.0.6", "lodash.merge": "^4.6.2", "postcss-selector-parser": "6.0.10" }, "peerDependencies": { "tailwindcss": ">=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1" } }, "sha512-0wDLwCVF5V3x3b1SGXPCDcdsbDHMBe+lkFzBRaHeLvNi+nrrnZ1lA18u+OTWO8iSWU2GxUOCvlXtDuqftc1oiA=="],
"@types/better-sqlite3": ["@types/better-sqlite3@7.6.13", "", { "dependencies": { "@types/node": "*" } }, "sha512-NMv9ASNARoKksWtsq/SHakpYAYnhBrQgGD8zkLYk/jaK8jUGn08CfEdTRgYhMypUQAfzSP8W6gNLe0q19/t4VA=="], "@types/better-sqlite3": ["@types/better-sqlite3@7.6.12", "", { "dependencies": { "@types/node": "*" } }, "sha512-fnQmj8lELIj7BSrZQAdBMHEHX8OZLYIHXqAKT1O7tDfLxaINzf00PMjw22r3N/xXh0w/sGHlO6SVaCQ2mj78lg=="],
"@types/cookie": ["@types/cookie@0.6.0", "", {}, "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA=="], "@types/cookie": ["@types/cookie@0.6.0", "", {}, "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA=="],
@@ -297,21 +295,21 @@
"@types/ws": ["@types/ws@8.5.13", "", { "dependencies": { "@types/node": "*" } }, "sha512-osM/gWBTPKgHV8XkTunnegTRIsvF6owmf5w+JtAfOw472dptdm0dlGv4xCt6GwQRcC2XVOvvRE/0bAoQcL2QkA=="], "@types/ws": ["@types/ws@8.5.13", "", { "dependencies": { "@types/node": "*" } }, "sha512-osM/gWBTPKgHV8XkTunnegTRIsvF6owmf5w+JtAfOw472dptdm0dlGv4xCt6GwQRcC2XVOvvRE/0bAoQcL2QkA=="],
"@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.31.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.31.0", "@typescript-eslint/type-utils": "8.31.0", "@typescript-eslint/utils": "8.31.0", "@typescript-eslint/visitor-keys": "8.31.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-evaQJZ/J/S4wisevDvC1KFZkPzRetH8kYZbkgcTRyql3mcKsf+ZFDV1BVWUGTCAW5pQHoqn5gK5b8kn7ou9aFQ=="], "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.26.1", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.26.1", "@typescript-eslint/type-utils": "8.26.1", "@typescript-eslint/utils": "8.26.1", "@typescript-eslint/visitor-keys": "8.26.1", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-2X3mwqsj9Bd3Ciz508ZUtoQQYpOhU/kWoUqIf49H8Z0+Vbh6UF/y0OEYp0Q0axOGzaBGs7QxRwq0knSQ8khQNA=="],
"@typescript-eslint/parser": ["@typescript-eslint/parser@8.31.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.31.0", "@typescript-eslint/types": "8.31.0", "@typescript-eslint/typescript-estree": "8.31.0", "@typescript-eslint/visitor-keys": "8.31.0", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-67kYYShjBR0jNI5vsf/c3WG4u+zDnCTHTPqVMQguffaWWFs7artgwKmfwdifl+r6XyM5LYLas/dInj2T0SgJyw=="], "@typescript-eslint/parser": ["@typescript-eslint/parser@8.26.1", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.26.1", "@typescript-eslint/types": "8.26.1", "@typescript-eslint/typescript-estree": "8.26.1", "@typescript-eslint/visitor-keys": "8.26.1", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-w6HZUV4NWxqd8BdeFf81t07d7/YV9s7TCWrQQbG5uhuvGUAW+fq1usZ1Hmz9UPNLniFnD8GLSsDpjP0hm1S4lQ=="],
"@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.31.0", "", { "dependencies": { "@typescript-eslint/types": "8.31.0", "@typescript-eslint/visitor-keys": "8.31.0" } }, "sha512-knO8UyF78Nt8O/B64i7TlGXod69ko7z6vJD9uhSlm0qkAbGeRUSudcm0+K/4CrRjrpiHfBCjMWlc08Vav1xwcw=="], "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.26.1", "", { "dependencies": { "@typescript-eslint/types": "8.26.1", "@typescript-eslint/visitor-keys": "8.26.1" } }, "sha512-6EIvbE5cNER8sqBu6V7+KeMZIC1664d2Yjt+B9EWUXrsyWpxx4lEZrmvxgSKRC6gX+efDL/UY9OpPZ267io3mg=="],
"@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.31.0", "", { "dependencies": { "@typescript-eslint/typescript-estree": "8.31.0", "@typescript-eslint/utils": "8.31.0", "debug": "^4.3.4", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-DJ1N1GdjI7IS7uRlzJuEDCgDQix3ZVYVtgeWEyhyn4iaoitpMBX6Ndd488mXSx0xah/cONAkEaYyylDyAeHMHg=="], "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.26.1", "", { "dependencies": { "@typescript-eslint/typescript-estree": "8.26.1", "@typescript-eslint/utils": "8.26.1", "debug": "^4.3.4", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-Kcj/TagJLwoY/5w9JGEFV0dclQdyqw9+VMndxOJKtoFSjfZhLXhYjzsQEeyza03rwHx2vFEGvrJWJBXKleRvZg=="],
"@typescript-eslint/types": ["@typescript-eslint/types@8.31.0", "", {}, "sha512-Ch8oSjVyYyJxPQk8pMiP2FFGYatqXQfQIaMp+TpuuLlDachRWpUAeEu1u9B/v/8LToehUIWyiKcA/w5hUFRKuQ=="], "@typescript-eslint/types": ["@typescript-eslint/types@8.26.1", "", {}, "sha512-n4THUQW27VmQMx+3P+B0Yptl7ydfceUj4ON/AQILAASwgYdZ/2dhfymRMh5egRUrvK5lSmaOm77Ry+lmXPOgBQ=="],
"@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.31.0", "", { "dependencies": { "@typescript-eslint/types": "8.31.0", "@typescript-eslint/visitor-keys": "8.31.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "typescript": ">=4.8.4 <5.9.0" } }, "sha512-xLmgn4Yl46xi6aDSZ9KkyfhhtnYI15/CvHbpOy/eR5NWhK/BK8wc709KKwhAR0m4ZKRP7h07bm4BWUYOCuRpQQ=="], "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.26.1", "", { "dependencies": { "@typescript-eslint/types": "8.26.1", "@typescript-eslint/visitor-keys": "8.26.1", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "typescript": ">=4.8.4 <5.9.0" } }, "sha512-yUwPpUHDgdrv1QJ7YQal3cMVBGWfnuCdKbXw1yyjArax3353rEJP1ZA+4F8nOlQ3RfS2hUN/wze3nlY+ZOhvoA=="],
"@typescript-eslint/utils": ["@typescript-eslint/utils@8.31.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@typescript-eslint/scope-manager": "8.31.0", "@typescript-eslint/types": "8.31.0", "@typescript-eslint/typescript-estree": "8.31.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-qi6uPLt9cjTFxAb1zGNgTob4x9ur7xC6mHQJ8GwEzGMGE9tYniublmJaowOJ9V2jUzxrltTPfdG2nKlWsq0+Ww=="], "@typescript-eslint/utils": ["@typescript-eslint/utils@8.26.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@typescript-eslint/scope-manager": "8.26.1", "@typescript-eslint/types": "8.26.1", "@typescript-eslint/typescript-estree": "8.26.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-V4Urxa/XtSUroUrnI7q6yUTD3hDtfJ2jzVfeT3VK0ciizfK2q/zGC0iDh1lFMUZR8cImRrep6/q0xd/1ZGPQpg=="],
"@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.31.0", "", { "dependencies": { "@typescript-eslint/types": "8.31.0", "eslint-visitor-keys": "^4.2.0" } }, "sha512-QcGHmlRHWOl93o64ZUMNewCdwKGU6WItOU52H0djgNmn1EOrhVudrDzXz4OycCRSCPwFCDrE2iIt5vmuUdHxuQ=="], "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.26.1", "", { "dependencies": { "@typescript-eslint/types": "8.26.1", "eslint-visitor-keys": "^4.2.0" } }, "sha512-AjOC3zfnxd6S4Eiy3jwktJPclqhFHNyd8L6Gycf9WUPoKZpgM5PjkxY1X7uSy61xVpiJDhhk7XT2NVsN3ALTWg=="],
"acorn": ["acorn@8.14.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA=="], "acorn": ["acorn@8.14.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA=="],
@@ -349,7 +347,7 @@
"binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="], "binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="],
"bits-ui": ["bits-ui@1.3.19", "", { "dependencies": { "@floating-ui/core": "^1.6.4", "@floating-ui/dom": "^1.6.7", "@internationalized/date": "^3.5.6", "esm-env": "^1.1.2", "runed": "^0.23.2", "svelte-toolbelt": "^0.7.1", "tabbable": "^6.2.0" }, "peerDependencies": { "svelte": "^5.11.0" } }, "sha512-2blb6dkgedHUsDXqCjvmtUi4Advgd9MhaJDT8r7bEWDzHI8HGsOoYsLeh8CxpEWWEYPrlGN+7k+kpxRhIDdFrQ=="], "bits-ui": ["bits-ui@0.22.0", "", { "dependencies": { "@internationalized/date": "^3.5.1", "@melt-ui/svelte": "0.76.2", "nanoid": "^5.0.5" }, "peerDependencies": { "svelte": "^4.0.0 || ^5.0.0" } }, "sha512-r7Fw1HNgA4YxZBRcozl7oP0bheQ8EHh+kfMBZJgyFISix8t4p/nqDcHLmBgIiJ3T5XjYnJRorYDjIWaCfhb5fw=="],
"bl": ["bl@4.1.0", "", { "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", "readable-stream": "^3.4.0" } }, "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w=="], "bl": ["bl@4.1.0", "", { "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", "readable-stream": "^3.4.0" } }, "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w=="],
@@ -423,6 +421,8 @@
"defu": ["defu@6.1.4", "", {}, "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg=="], "defu": ["defu@6.1.4", "", {}, "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg=="],
"dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="],
"detect-libc": ["detect-libc@2.0.2", "", {}, "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw=="], "detect-libc": ["detect-libc@2.0.2", "", {}, "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw=="],
"devalue": ["devalue@5.1.1", "", {}, "sha512-maua5KUiapvEwiEAe+XnlZ3Rh0GD+qI1J/nb9vrJc3muPXvcF/8gXYTWF76+5DAqHyDUtOIImEuo0YKE9mshVw=="], "devalue": ["devalue@5.1.1", "", {}, "sha512-maua5KUiapvEwiEAe+XnlZ3Rh0GD+qI1J/nb9vrJc3muPXvcF/8gXYTWF76+5DAqHyDUtOIImEuo0YKE9mshVw=="],
@@ -435,7 +435,7 @@
"drange": ["drange@1.1.1", "", {}, "sha512-pYxfDYpued//QpnLIm4Avk7rsNtAtQkUES2cwAYSvD/wd2pKD71gN2Ebj3e7klzXwjocvE8c5vx/1fxwpqmSxA=="], "drange": ["drange@1.1.1", "", {}, "sha512-pYxfDYpued//QpnLIm4Avk7rsNtAtQkUES2cwAYSvD/wd2pKD71gN2Ebj3e7klzXwjocvE8c5vx/1fxwpqmSxA=="],
"drizzle-kit": ["drizzle-kit@0.30.6", "", { "dependencies": { "@drizzle-team/brocli": "^0.10.2", "@esbuild-kit/esm-loader": "^2.5.5", "esbuild": "^0.19.7", "esbuild-register": "^3.5.0", "gel": "^2.0.0" }, "bin": { "drizzle-kit": "bin.cjs" } }, "sha512-U4wWit0fyZuGuP7iNmRleQyK2V8wCuv57vf5l3MnG4z4fzNTjY/U13M8owyQ5RavqvqxBifWORaR3wIUzlN64g=="], "drizzle-kit": ["drizzle-kit@0.30.5", "", { "dependencies": { "@drizzle-team/brocli": "^0.10.2", "@esbuild-kit/esm-loader": "^2.5.5", "esbuild": "^0.19.7", "esbuild-register": "^3.5.0", "gel": "^2.0.0" }, "bin": { "drizzle-kit": "bin.cjs" } }, "sha512-l6dMSE100u7sDaTbLczibrQZjA35jLsHNqIV+jmhNVO3O8jzM6kywMOmV9uOz9ZVSCMPQhAZEFjL/qDPVrqpUA=="],
"drizzle-orm": ["drizzle-orm@0.38.4", "", { "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=4", "@electric-sql/pglite": ">=0.2.0", "@libsql/client": ">=0.10.0", "@libsql/client-wasm": ">=0.10.0", "@neondatabase/serverless": ">=0.10.0", "@op-engineering/op-sqlite": ">=2", "@opentelemetry/api": "^1.4.1", "@planetscale/database": ">=1", "@prisma/client": "*", "@tidbcloud/serverless": "*", "@types/better-sqlite3": "*", "@types/pg": "*", "@types/react": ">=18", "@types/sql.js": "*", "@vercel/postgres": ">=0.8.0", "@xata.io/client": "*", "better-sqlite3": ">=7", "bun-types": "*", "expo-sqlite": ">=14.0.0", "knex": "*", "kysely": "*", "mysql2": ">=2", "pg": ">=8", "postgres": ">=3", "react": ">=18", "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/react", "@types/sql.js", "@vercel/postgres", "@xata.io/client", "better-sqlite3", "bun-types", "expo-sqlite", "knex", "kysely", "mysql2", "pg", "postgres", "react", "sql.js", "sqlite3"] }, "sha512-s7/5BpLKO+WJRHspvpqTydxFob8i1vo2rEx4pY6TGY7QSMuUfWUuzaY0DIpXCkgHOo37BaFC+SJQb99dDUXT3Q=="], "drizzle-orm": ["drizzle-orm@0.38.4", "", { "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=4", "@electric-sql/pglite": ">=0.2.0", "@libsql/client": ">=0.10.0", "@libsql/client-wasm": ">=0.10.0", "@neondatabase/serverless": ">=0.10.0", "@op-engineering/op-sqlite": ">=2", "@opentelemetry/api": "^1.4.1", "@planetscale/database": ">=1", "@prisma/client": "*", "@tidbcloud/serverless": "*", "@types/better-sqlite3": "*", "@types/pg": "*", "@types/react": ">=18", "@types/sql.js": "*", "@vercel/postgres": ">=0.8.0", "@xata.io/client": "*", "better-sqlite3": ">=7", "bun-types": "*", "expo-sqlite": ">=14.0.0", "knex": "*", "kysely": "*", "mysql2": ">=2", "pg": ">=8", "postgres": ">=3", "react": ">=18", "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/react", "@types/sql.js", "@vercel/postgres", "@xata.io/client", "better-sqlite3", "bun-types", "expo-sqlite", "knex", "kysely", "mysql2", "pg", "postgres", "react", "sql.js", "sqlite3"] }, "sha512-s7/5BpLKO+WJRHspvpqTydxFob8i1vo2rEx4pY6TGY7QSMuUfWUuzaY0DIpXCkgHOo37BaFC+SJQb99dDUXT3Q=="],
@@ -455,7 +455,7 @@
"escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], "escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="],
"eslint": ["eslint@9.25.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.20.0", "@eslint/config-helpers": "^0.2.1", "@eslint/core": "^0.13.0", "@eslint/eslintrc": "^3.3.1", "@eslint/js": "9.25.1", "@eslint/plugin-kit": "^0.2.8", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.3.0", "eslint-visitor-keys": "^4.2.0", "espree": "^10.3.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-E6Mtz9oGQWDCpV12319d59n4tx9zOTXSTmc8BLVxBx+G/0RdM5MvEEJLU9c0+aleoePYYgVTOsRblx433qmhWQ=="], "eslint": ["eslint@9.22.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.19.2", "@eslint/config-helpers": "^0.1.0", "@eslint/core": "^0.12.0", "@eslint/eslintrc": "^3.3.0", "@eslint/js": "9.22.0", "@eslint/plugin-kit": "^0.2.7", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.3.0", "eslint-visitor-keys": "^4.2.0", "espree": "^10.3.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-9V/QURhsRN40xuHXWjV64yvrzMjcz7ZyNoF2jJFmy9j/SLk0u1OLSZgXi28MrXjymnjEGSR80WCdab3RGMDveQ=="],
"eslint-compat-utils": ["eslint-compat-utils@0.5.1", "", { "dependencies": { "semver": "^7.5.4" }, "peerDependencies": { "eslint": ">=6.0.0" } }, "sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q=="], "eslint-compat-utils": ["eslint-compat-utils@0.5.1", "", { "dependencies": { "semver": "^7.5.4" }, "peerDependencies": { "eslint": ">=6.0.0" } }, "sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q=="],
@@ -475,7 +475,7 @@
"esquery": ["esquery@1.6.0", "", { "dependencies": { "estraverse": "^5.1.0" } }, "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg=="], "esquery": ["esquery@1.6.0", "", { "dependencies": { "estraverse": "^5.1.0" } }, "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg=="],
"esrap": ["esrap@1.4.6", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" } }, "sha512-F/D2mADJ9SHY3IwksD4DAXjTt7qt7GWUf3/8RhCNWmC/67tyb55dpimHmy7EplakFaflV0R/PC+fdSPqrRHAQw=="], "esrap": ["esrap@1.4.5", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" } }, "sha512-CjNMjkBWWZeHn+VX+gS8YvFwJ5+NDhg8aWZBSFJPR8qQduDNjbJodA2WcwCm7uQa5Rjqj+nZvVmceg1RbHFB9g=="],
"esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "^5.2.0" } }, "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="], "esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "^5.2.0" } }, "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="],
@@ -515,6 +515,8 @@
"flatted": ["flatted@3.3.2", "", {}, "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA=="], "flatted": ["flatted@3.3.2", "", {}, "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA=="],
"focus-trap": ["focus-trap@7.6.2", "", { "dependencies": { "tabbable": "^6.2.0" } }, "sha512-9FhUxK1hVju2+AiQIDJ5Dd//9R2n2RAfJ0qfhF4IHGHgcoEUTMpbTeG/zbEuwaiYXfuAH6XE0/aCyxDdRM+W5w=="],
"foreground-child": ["foreground-child@3.3.0", "", { "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" } }, "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg=="], "foreground-child": ["foreground-child@3.3.0", "", { "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" } }, "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg=="],
"formdata-polyfill": ["formdata-polyfill@4.0.10", "", { "dependencies": { "fetch-blob": "^3.1.2" } }, "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g=="], "formdata-polyfill": ["formdata-polyfill@4.0.10", "", { "dependencies": { "fetch-blob": "^3.1.2" } }, "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g=="],
@@ -561,8 +563,6 @@
"ini": ["ini@4.1.3", "", {}, "sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg=="], "ini": ["ini@4.1.3", "", {}, "sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg=="],
"inline-style-parser": ["inline-style-parser@0.2.4", "", {}, "sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q=="],
"inquirer": ["inquirer@8.2.6", "", { "dependencies": { "ansi-escapes": "^4.2.1", "chalk": "^4.1.1", "cli-cursor": "^3.1.0", "cli-width": "^3.0.0", "external-editor": "^3.0.3", "figures": "^3.0.0", "lodash": "^4.17.21", "mute-stream": "0.0.8", "ora": "^5.4.1", "run-async": "^2.4.0", "rxjs": "^7.5.5", "string-width": "^4.1.0", "strip-ansi": "^6.0.0", "through": "^2.3.6", "wrap-ansi": "^6.0.1" } }, "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg=="], "inquirer": ["inquirer@8.2.6", "", { "dependencies": { "ansi-escapes": "^4.2.1", "chalk": "^4.1.1", "cli-cursor": "^3.1.0", "cli-width": "^3.0.0", "external-editor": "^3.0.3", "figures": "^3.0.0", "lodash": "^4.17.21", "mute-stream": "0.0.8", "ora": "^5.4.1", "run-async": "^2.4.0", "rxjs": "^7.5.5", "string-width": "^4.1.0", "strip-ansi": "^6.0.0", "through": "^2.3.6", "wrap-ansi": "^6.0.1" } }, "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg=="],
"ip-address": ["ip-address@10.0.1", "", {}, "sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA=="], "ip-address": ["ip-address@10.0.1", "", {}, "sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA=="],
@@ -635,6 +635,8 @@
"lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], "lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
"lucide-svelte": ["lucide-svelte@0.469.0", "", { "peerDependencies": { "svelte": "^3 || ^4 || ^5.0.0-next.42" } }, "sha512-PMIJ8jrFqVUsXJz4d1yfAQplaGhNOahwwkzbunha8DhpiD73xqX24n8dE1dPpUk3vcrdWVsHc1y/liHHotOnGQ=="],
"magic-string": ["magic-string@0.30.17", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } }, "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA=="], "magic-string": ["magic-string@0.30.17", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } }, "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA=="],
"merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="], "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="],
@@ -663,7 +665,7 @@
"mz": ["mz@2.7.0", "", { "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", "thenify-all": "^1.0.0" } }, "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q=="], "mz": ["mz@2.7.0", "", { "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", "thenify-all": "^1.0.0" } }, "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q=="],
"nanoid": ["nanoid@3.3.8", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w=="], "nanoid": ["nanoid@5.0.9", "", { "bin": { "nanoid": "bin/nanoid.js" } }, "sha512-Aooyr6MXU6HpvvWXKoVoXwKMs/KyVakWwg7xQfv5/S/RIgJMy0Ifa45H9qqYy7pTCszrHzP21Uk4PZq2HpEM8Q=="],
"natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="], "natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="],
@@ -785,8 +787,6 @@
"run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="],
"runed": ["runed@0.23.4", "", { "dependencies": { "esm-env": "^1.0.0" }, "peerDependencies": { "svelte": "^5.7.0" } }, "sha512-9q8oUiBYeXIDLWNK5DfCWlkL0EW3oGbk845VdKlPeia28l751VpfesaB/+7pI6rnbx1I6rqoZ2fZxptOJLxILA=="],
"rxjs": ["rxjs@7.8.2", "", { "dependencies": { "tslib": "^2.1.0" } }, "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA=="], "rxjs": ["rxjs@7.8.2", "", { "dependencies": { "tslib": "^2.1.0" } }, "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA=="],
"sade": ["sade@1.8.1", "", { "dependencies": { "mri": "^1.1.0" } }, "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A=="], "sade": ["sade@1.8.1", "", { "dependencies": { "mri": "^1.1.0" } }, "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A=="],
@@ -827,22 +827,18 @@
"strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="], "strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="],
"style-to-object": ["style-to-object@1.0.8", "", { "dependencies": { "inline-style-parser": "0.2.4" } }, "sha512-xT47I/Eo0rwJmaXC4oilDGDWLohVhR6o/xAQcPQN8q6QBuZVL8qMYL85kLmST5cPjAorwvqIA4qXTRQoYHaL6g=="],
"sucrase": ["sucrase@3.35.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", "glob": "^10.3.10", "lines-and-columns": "^1.1.6", "mz": "^2.7.0", "pirates": "^4.0.1", "ts-interface-checker": "^0.1.9" }, "bin": { "sucrase": "bin/sucrase", "sucrase-node": "bin/sucrase-node" } }, "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA=="], "sucrase": ["sucrase@3.35.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", "glob": "^10.3.10", "lines-and-columns": "^1.1.6", "mz": "^2.7.0", "pirates": "^4.0.1", "ts-interface-checker": "^0.1.9" }, "bin": { "sucrase": "bin/sucrase", "sucrase-node": "bin/sucrase-node" } }, "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA=="],
"supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], "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=="], "supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="],
"svelte": ["svelte@5.28.1", "", { "dependencies": { "@ampproject/remapping": "^2.3.0", "@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": "^1.4.6", "is-reference": "^3.0.3", "locate-character": "^3.0.0", "magic-string": "^0.30.11", "zimmerframe": "^1.1.2" } }, "sha512-iOa9WmfNG95lSOSJdMhdjJ4Afok7IRAQYXpbnxhd5EINnXseG0GVa9j6WPght4eX78XfFez45Fi+uRglGKPV/Q=="], "svelte": ["svelte@5.23.0", "", { "dependencies": { "@ampproject/remapping": "^2.3.0", "@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": "^1.4.3", "is-reference": "^3.0.3", "locate-character": "^3.0.0", "magic-string": "^0.30.11", "zimmerframe": "^1.1.2" } }, "sha512-v0lL3NuKontiCxholEiAXCB+BYbndlKbwlDMK0DS86WgGELMJSpyqCSbJeMEMBDwOglnS7Ar2Rq0wwa/z2L8Vg=="],
"svelte-check": ["svelte-check@4.1.6", "", { "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-P7w/6tdSfk3zEVvfsgrp3h3DFC75jCdZjTQvgGJtjPORs1n7/v2VMPIoty3PWv7jnfEm3x0G/p9wH4pecTb0Wg=="], "svelte-check": ["svelte-check@4.1.5", "", { "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-Gb0T2IqBNe1tLB9EB1Qh+LOe+JB8wt2/rNBDGvkxQVvk8vNeAoG+vZgFB/3P5+zC7RWlyBlzm9dVjZFph/maIg=="],
"svelte-eslint-parser": ["svelte-eslint-parser@0.43.0", "", { "dependencies": { "eslint-scope": "^7.2.2", "eslint-visitor-keys": "^3.4.3", "espree": "^9.6.1", "postcss": "^8.4.39", "postcss-scss": "^4.0.9" }, "peerDependencies": { "svelte": "^3.37.0 || ^4.0.0 || ^5.0.0" }, "optionalPeers": ["svelte"] }, "sha512-GpU52uPKKcVnh8tKN5P4UZpJ/fUDndmq7wfsvoVXsyP+aY0anol7Yqo01fyrlaWGMFfm4av5DyrjlaXdLRJvGA=="], "svelte-eslint-parser": ["svelte-eslint-parser@0.43.0", "", { "dependencies": { "eslint-scope": "^7.2.2", "eslint-visitor-keys": "^3.4.3", "espree": "^9.6.1", "postcss": "^8.4.39", "postcss-scss": "^4.0.9" }, "peerDependencies": { "svelte": "^3.37.0 || ^4.0.0 || ^5.0.0" }, "optionalPeers": ["svelte"] }, "sha512-GpU52uPKKcVnh8tKN5P4UZpJ/fUDndmq7wfsvoVXsyP+aY0anol7Yqo01fyrlaWGMFfm4av5DyrjlaXdLRJvGA=="],
"svelte-toolbelt": ["svelte-toolbelt@0.7.1", "", { "dependencies": { "clsx": "^2.1.1", "runed": "^0.23.2", "style-to-object": "^1.0.8" }, "peerDependencies": { "svelte": "^5.0.0" } }, "sha512-HcBOcR17Vx9bjaOceUvxkY3nGmbBmCBBbuWLLEWO6jtmWH8f/QoWmbyUfQZrpDINH39en1b8mptfPQT9VKQ1xQ=="],
"tabbable": ["tabbable@6.2.0", "", {}, "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew=="], "tabbable": ["tabbable@6.2.0", "", {}, "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew=="],
"tailwind-merge": ["tailwind-merge@2.6.0", "", {}, "sha512-P+Vu1qXfzediirmHOC3xKGAYeZtPcV9g76X+xg2FD4tYgR71ewMA35Y3sCz3zhiN/dwefRpJX0yBcgwi1fXNQA=="], "tailwind-merge": ["tailwind-merge@2.6.0", "", {}, "sha512-P+Vu1qXfzediirmHOC3xKGAYeZtPcV9g76X+xg2FD4tYgR71ewMA35Y3sCz3zhiN/dwefRpJX0yBcgwi1fXNQA=="],
@@ -859,8 +855,6 @@
"through": ["through@2.3.8", "", {}, "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg=="], "through": ["through@2.3.8", "", {}, "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg=="],
"tinyglobby": ["tinyglobby@0.2.13", "", { "dependencies": { "fdir": "^6.4.4", "picomatch": "^4.0.2" } }, "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw=="],
"tmp": ["tmp@0.0.33", "", { "dependencies": { "os-tmpdir": "~1.0.2" } }, "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw=="], "tmp": ["tmp@0.0.33", "", { "dependencies": { "os-tmpdir": "~1.0.2" } }, "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw=="],
"to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="],
@@ -879,11 +873,11 @@
"type-fest": ["type-fest@4.37.0", "", {}, "sha512-S/5/0kFftkq27FPNye0XM1e2NsnoD/3FS+pBmbjmmtLT6I+i344KoOf7pvXreaFsDamWeaJX55nczA1m5PsBDg=="], "type-fest": ["type-fest@4.37.0", "", {}, "sha512-S/5/0kFftkq27FPNye0XM1e2NsnoD/3FS+pBmbjmmtLT6I+i344KoOf7pvXreaFsDamWeaJX55nczA1m5PsBDg=="],
"typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="], "typescript": ["typescript@5.8.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ=="],
"typescript-eslint": ["typescript-eslint@8.31.0", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.31.0", "@typescript-eslint/parser": "8.31.0", "@typescript-eslint/utils": "8.31.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-u+93F0sB0An8WEAPtwxVhFby573E8ckdjwUUQUj9QA4v8JAvgtoDdIyYR3XFwFHq2W1KJ1AurwJCO+w+Y1ixyQ=="], "typescript-eslint": ["typescript-eslint@8.26.1", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.26.1", "@typescript-eslint/parser": "8.26.1", "@typescript-eslint/utils": "8.26.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-t/oIs9mYyrwZGRpDv3g+3K6nZ5uhKEMt2oNmAPwaY4/ye0+EH4nXIPYNtkYFS6QHm+1DFg34DbglYBz5P9Xysg=="],
"typia": ["typia@8.2.0", "", { "dependencies": { "@samchon/openapi": "^3.3.0", "commander": "^10.0.0", "comment-json": "^4.2.3", "inquirer": "^8.2.5", "package-manager-detector": "^0.2.0", "randexp": "^0.5.3" }, "peerDependencies": { "typescript": ">=4.8.0 <5.9.0" }, "bin": { "typia": "lib/executable/typia.js" } }, "sha512-DAQl9CLItDwMd4k4HnaExxv6wjBFLW04WqGBQEnOpylq2YmZsM6HTj4Bfxxp3wtgAsMXZTugAdQRPsFOxMiRrQ=="], "typia": ["typia@8.0.2", "", { "dependencies": { "@samchon/openapi": "^3.0.0", "commander": "^10.0.0", "comment-json": "^4.2.3", "inquirer": "^8.2.5", "package-manager-detector": "^0.2.0", "randexp": "^0.5.3" }, "peerDependencies": { "typescript": ">=4.8.0 <5.9.0" }, "bin": { "typia": "lib/executable/typia.js" } }, "sha512-xDacELBticuXx17TtPWhSd1thyE2MF74LZhhDoCFkpCKhiElnB40X/Jb3zMLRx86WUkqCH60rwm3ghaJdBs7hA=="],
"ufo": ["ufo@1.5.4", "", {}, "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ=="], "ufo": ["ufo@1.5.4", "", {}, "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ=="],
@@ -897,7 +891,7 @@
"util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="],
"vite": ["vite@6.3.2", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.3", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.12" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "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-ZSvGOXKGceizRQIZSz7TGJ0pS3QLlVY/9hwxVh17W3re67je1RKYzFHivZ/t0tubU78Vkyb9WnHPENSBCzbckg=="], "vite": ["vite@6.2.2", "", { "dependencies": { "esbuild": "^0.25.0", "postcss": "^8.5.3", "rollup": "^4.30.1" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "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-yW7PeMM+LkDzc7CgJuRLMW2Jz0FxMOsVJ8Lv3gpgW9WLcb9cTW+121UEr1hvmfR7w3SegR5ItvYyzVz1vxNJgQ=="],
"vitefu": ["vitefu@1.0.4", "", { "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0" }, "optionalPeers": ["vite"] }, "sha512-y6zEE3PQf6uu/Mt6DTJ9ih+kyJLr4XcSgHR2zUkM8SWDhuixEJxfJ6CZGMHh1Ec3vPLoEA0IHU5oWzVqw8ulow=="], "vitefu": ["vitefu@1.0.4", "", { "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0" }, "optionalPeers": ["vite"] }, "sha512-y6zEE3PQf6uu/Mt6DTJ9ih+kyJLr4XcSgHR2zUkM8SWDhuixEJxfJ6CZGMHh1Ec3vPLoEA0IHU5oWzVqw8ulow=="],
@@ -945,8 +939,6 @@
"@ryoppippi/unplugin-typia/typia": ["typia@7.6.4", "", { "dependencies": { "@samchon/openapi": "^2.4.2", "commander": "^10.0.0", "comment-json": "^4.2.3", "inquirer": "^8.2.5", "package-manager-detector": "^0.2.0", "randexp": "^0.5.3" }, "peerDependencies": { "typescript": ">=4.8.0 <5.8.0" }, "bin": { "typia": "lib/executable/typia.js" } }, "sha512-Z3AcvGBjS7Dc7+iAG2VhsT0NIv3HMoXVTJ3F7Pgth8z7rhQu1JnyS8GGqqWdKk5ROvOgALEVEWmWv3Lym2eBIg=="], "@ryoppippi/unplugin-typia/typia": ["typia@7.6.4", "", { "dependencies": { "@samchon/openapi": "^2.4.2", "commander": "^10.0.0", "comment-json": "^4.2.3", "inquirer": "^8.2.5", "package-manager-detector": "^0.2.0", "randexp": "^0.5.3" }, "peerDependencies": { "typescript": ">=4.8.0 <5.8.0" }, "bin": { "typia": "lib/executable/typia.js" } }, "sha512-Z3AcvGBjS7Dc7+iAG2VhsT0NIv3HMoXVTJ3F7Pgth8z7rhQu1JnyS8GGqqWdKk5ROvOgALEVEWmWv3Lym2eBIg=="],
"@ryoppippi/unplugin-typia/vite": ["vite@6.2.2", "", { "dependencies": { "esbuild": "^0.25.0", "postcss": "^8.5.3", "rollup": "^4.30.1" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "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-yW7PeMM+LkDzc7CgJuRLMW2Jz0FxMOsVJ8Lv3gpgW9WLcb9cTW+121UEr1hvmfR7w3SegR5ItvYyzVz1vxNJgQ=="],
"@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], "@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
"ansi-escapes/type-fest": ["type-fest@0.21.3", "", {}, "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w=="], "ansi-escapes/type-fest": ["type-fest@0.21.3", "", {}, "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w=="],
@@ -977,6 +969,8 @@
"pkg-types/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], "pkg-types/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
"postcss/nanoid": ["nanoid@3.3.8", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w=="],
"postcss-load-config/lilconfig": ["lilconfig@2.1.0", "", {}, "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ=="], "postcss-load-config/lilconfig": ["lilconfig@2.1.0", "", {}, "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ=="],
"postcss-nested/postcss-selector-parser": ["postcss-selector-parser@6.1.2", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg=="], "postcss-nested/postcss-selector-parser": ["postcss-selector-parser@6.1.2", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg=="],
@@ -1003,11 +997,7 @@
"tailwindcss/postcss-selector-parser": ["postcss-selector-parser@6.1.2", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg=="], "tailwindcss/postcss-selector-parser": ["postcss-selector-parser@6.1.2", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg=="],
"tinyglobby/fdir": ["fdir@6.4.4", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg=="], "vite/rollup": ["rollup@4.34.8", "", { "dependencies": { "@types/estree": "1.0.6" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.34.8", "@rollup/rollup-android-arm64": "4.34.8", "@rollup/rollup-darwin-arm64": "4.34.8", "@rollup/rollup-darwin-x64": "4.34.8", "@rollup/rollup-freebsd-arm64": "4.34.8", "@rollup/rollup-freebsd-x64": "4.34.8", "@rollup/rollup-linux-arm-gnueabihf": "4.34.8", "@rollup/rollup-linux-arm-musleabihf": "4.34.8", "@rollup/rollup-linux-arm64-gnu": "4.34.8", "@rollup/rollup-linux-arm64-musl": "4.34.8", "@rollup/rollup-linux-loongarch64-gnu": "4.34.8", "@rollup/rollup-linux-powerpc64le-gnu": "4.34.8", "@rollup/rollup-linux-riscv64-gnu": "4.34.8", "@rollup/rollup-linux-s390x-gnu": "4.34.8", "@rollup/rollup-linux-x64-gnu": "4.34.8", "@rollup/rollup-linux-x64-musl": "4.34.8", "@rollup/rollup-win32-arm64-msvc": "4.34.8", "@rollup/rollup-win32-ia32-msvc": "4.34.8", "@rollup/rollup-win32-x64-msvc": "4.34.8", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-489gTVMzAYdiZHFVA/ig/iYFllCcWFHMvUHI1rpFmkoUtRlQxqh6/yiNqnYibjMZ2b/+FUQwldG+aLsEt6bglQ=="],
"vite/fdir": ["fdir@6.4.4", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg=="],
"vite/rollup": ["rollup@4.40.0", "", { "dependencies": { "@types/estree": "1.0.7" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.40.0", "@rollup/rollup-android-arm64": "4.40.0", "@rollup/rollup-darwin-arm64": "4.40.0", "@rollup/rollup-darwin-x64": "4.40.0", "@rollup/rollup-freebsd-arm64": "4.40.0", "@rollup/rollup-freebsd-x64": "4.40.0", "@rollup/rollup-linux-arm-gnueabihf": "4.40.0", "@rollup/rollup-linux-arm-musleabihf": "4.40.0", "@rollup/rollup-linux-arm64-gnu": "4.40.0", "@rollup/rollup-linux-arm64-musl": "4.40.0", "@rollup/rollup-linux-loongarch64-gnu": "4.40.0", "@rollup/rollup-linux-powerpc64le-gnu": "4.40.0", "@rollup/rollup-linux-riscv64-gnu": "4.40.0", "@rollup/rollup-linux-riscv64-musl": "4.40.0", "@rollup/rollup-linux-s390x-gnu": "4.40.0", "@rollup/rollup-linux-x64-gnu": "4.40.0", "@rollup/rollup-linux-x64-musl": "4.40.0", "@rollup/rollup-win32-arm64-msvc": "4.40.0", "@rollup/rollup-win32-ia32-msvc": "4.40.0", "@rollup/rollup-win32-x64-msvc": "4.40.0", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-Noe455xmA96nnqH5piFtLobsGbCij7Tu+tb3c1vYjNbTkfzGqXqQXG3wJaYXkRZuQ0vEYN4bhwg7QnIrqB5B+w=="],
"@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-arm": ["@esbuild/android-arm@0.18.20", "", { "os": "android", "cpu": "arm" }, "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw=="],
@@ -1061,8 +1051,6 @@
"@ryoppippi/unplugin-typia/typia/@samchon/openapi": ["@samchon/openapi@2.5.3", "", {}, "sha512-gLcGqPGsr/V43yNrhC+5E8ZR8y1JdLZDgkC6ULg+B03uvmdS2C7qIXpIWUe19MUPvXt5SCpjhvOykomEspinaw=="], "@ryoppippi/unplugin-typia/typia/@samchon/openapi": ["@samchon/openapi@2.5.3", "", {}, "sha512-gLcGqPGsr/V43yNrhC+5E8ZR8y1JdLZDgkC6ULg+B03uvmdS2C7qIXpIWUe19MUPvXt5SCpjhvOykomEspinaw=="],
"@ryoppippi/unplugin-typia/vite/rollup": ["rollup@4.34.8", "", { "dependencies": { "@types/estree": "1.0.6" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.34.8", "@rollup/rollup-android-arm64": "4.34.8", "@rollup/rollup-darwin-arm64": "4.34.8", "@rollup/rollup-darwin-x64": "4.34.8", "@rollup/rollup-freebsd-arm64": "4.34.8", "@rollup/rollup-freebsd-x64": "4.34.8", "@rollup/rollup-linux-arm-gnueabihf": "4.34.8", "@rollup/rollup-linux-arm-musleabihf": "4.34.8", "@rollup/rollup-linux-arm64-gnu": "4.34.8", "@rollup/rollup-linux-arm64-musl": "4.34.8", "@rollup/rollup-linux-loongarch64-gnu": "4.34.8", "@rollup/rollup-linux-powerpc64le-gnu": "4.34.8", "@rollup/rollup-linux-riscv64-gnu": "4.34.8", "@rollup/rollup-linux-s390x-gnu": "4.34.8", "@rollup/rollup-linux-x64-gnu": "4.34.8", "@rollup/rollup-linux-x64-musl": "4.34.8", "@rollup/rollup-win32-arm64-msvc": "4.34.8", "@rollup/rollup-win32-ia32-msvc": "4.34.8", "@rollup/rollup-win32-x64-msvc": "4.34.8", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-489gTVMzAYdiZHFVA/ig/iYFllCcWFHMvUHI1rpFmkoUtRlQxqh6/yiNqnYibjMZ2b/+FUQwldG+aLsEt6bglQ=="],
"@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="], "@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
"drizzle-kit/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.19.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA=="], "drizzle-kit/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.19.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA=="],
@@ -1111,6 +1099,8 @@
"drizzle-kit/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.19.12", "", { "os": "win32", "cpu": "x64" }, "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA=="], "drizzle-kit/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.19.12", "", { "os": "win32", "cpu": "x64" }, "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA=="],
"eslint-plugin-svelte/postcss/nanoid": ["nanoid@3.3.8", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w=="],
"gel/which/isexe": ["isexe@3.1.1", "", {}, "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ=="], "gel/which/isexe": ["isexe@3.1.1", "", {}, "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ=="],
"glob/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="], "glob/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
@@ -1121,89 +1111,53 @@
"pkg-dir/find-up/path-exists": ["path-exists@5.0.0", "", {}, "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ=="], "pkg-dir/find-up/path-exists": ["path-exists@5.0.0", "", {}, "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ=="],
"svelte-eslint-parser/postcss/nanoid": ["nanoid@3.3.8", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w=="],
"tailwindcss/chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], "tailwindcss/chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
"tailwindcss/chokidar/readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], "tailwindcss/chokidar/readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="],
"tailwindcss/postcss/nanoid": ["nanoid@3.3.8", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w=="],
"tailwindcss/postcss-load-config/yaml": ["yaml@2.6.1", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-7r0XPzioN/Q9kXBro/XPnA6kznR73DHq+GXh5ON7ZozRO6aMjbmiBuKste2wslTFkC5d1dw0GooOCepZXJ2SAg=="], "tailwindcss/postcss-load-config/yaml": ["yaml@2.6.1", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-7r0XPzioN/Q9kXBro/XPnA6kznR73DHq+GXh5ON7ZozRO6aMjbmiBuKste2wslTFkC5d1dw0GooOCepZXJ2SAg=="],
"vite/rollup/@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.40.0", "", { "os": "android", "cpu": "arm" }, "sha512-+Fbls/diZ0RDerhE8kyC6hjADCXA1K4yVNlH0EYfd2XjyH0UGgzaQ8MlT0pCXAThfxv3QUAczHaL+qSv1E4/Cg=="], "vite/rollup/@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.34.8", "", { "os": "android", "cpu": "arm" }, "sha512-q217OSE8DTp8AFHuNHXo0Y86e1wtlfVrXiAlwkIvGRQv9zbc6mE3sjIVfwI8sYUyNxwOg0j/Vm1RKM04JcWLJw=="],
"vite/rollup/@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.40.0", "", { "os": "android", "cpu": "arm64" }, "sha512-PPA6aEEsTPRz+/4xxAmaoWDqh67N7wFbgFUJGMnanCFs0TV99M0M8QhhaSCks+n6EbQoFvLQgYOGXxlMGQe/6w=="], "vite/rollup/@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.34.8", "", { "os": "android", "cpu": "arm64" }, "sha512-Gigjz7mNWaOL9wCggvoK3jEIUUbGul656opstjaUSGC3eT0BM7PofdAJaBfPFWWkXNVAXbaQtC99OCg4sJv70Q=="],
"vite/rollup/@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.40.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-GwYOcOakYHdfnjjKwqpTGgn5a6cUX7+Ra2HeNj/GdXvO2VJOOXCiYYlRFU4CubFM67EhbmzLOmACKEfvp3J1kQ=="], "vite/rollup/@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.34.8", "", { "os": "darwin", "cpu": "arm64" }, "sha512-02rVdZ5tgdUNRxIUrFdcMBZQoaPMrxtwSb+/hOfBdqkatYHR3lZ2A2EGyHq2sGOd0Owk80oV3snlDASC24He3Q=="],
"vite/rollup/@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.40.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-CoLEGJ+2eheqD9KBSxmma6ld01czS52Iw0e2qMZNpPDlf7Z9mj8xmMemxEucinev4LgHalDPczMyxzbq+Q+EtA=="], "vite/rollup/@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.34.8", "", { "os": "darwin", "cpu": "x64" }, "sha512-qIP/elwR/tq/dYRx3lgwK31jkZvMiD6qUtOycLhTzCvrjbZ3LjQnEM9rNhSGpbLXVJYQ3rq39A6Re0h9tU2ynw=="],
"vite/rollup/@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.40.0", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-r7yGiS4HN/kibvESzmrOB/PxKMhPTlz+FcGvoUIKYoTyGd5toHp48g1uZy1o1xQvybwwpqpe010JrcGG2s5nkg=="], "vite/rollup/@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.34.8", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-IQNVXL9iY6NniYbTaOKdrlVP3XIqazBgJOVkddzJlqnCpRi/yAeSOa8PLcECFSQochzqApIOE1GHNu3pCz+BDA=="],
"vite/rollup/@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.40.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-mVDxzlf0oLzV3oZOr0SMJ0lSDd3xC4CmnWJ8Val8isp9jRGl5Dq//LLDSPFrasS7pSm6m5xAcKaw3sHXhBjoRw=="], "vite/rollup/@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.34.8", "", { "os": "freebsd", "cpu": "x64" }, "sha512-TYXcHghgnCqYFiE3FT5QwXtOZqDj5GmaFNTNt3jNC+vh22dc/ukG2cG+pi75QO4kACohZzidsq7yKTKwq/Jq7Q=="],
"vite/rollup/@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.40.0", "", { "os": "linux", "cpu": "arm" }, "sha512-y/qUMOpJxBMy8xCXD++jeu8t7kzjlOCkoxxajL58G62PJGBZVl/Gwpm7JK9+YvlB701rcQTzjUZ1JgUoPTnoQA=="], "vite/rollup/@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.34.8", "", { "os": "linux", "cpu": "arm" }, "sha512-A4iphFGNkWRd+5m3VIGuqHnG3MVnqKe7Al57u9mwgbyZ2/xF9Jio72MaY7xxh+Y87VAHmGQr73qoKL9HPbXj1g=="],
"vite/rollup/@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.40.0", "", { "os": "linux", "cpu": "arm" }, "sha512-GoCsPibtVdJFPv/BOIvBKO/XmwZLwaNWdyD8TKlXuqp0veo2sHE+A/vpMQ5iSArRUz/uaoj4h5S6Pn0+PdhRjg=="], "vite/rollup/@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.34.8", "", { "os": "linux", "cpu": "arm" }, "sha512-S0lqKLfTm5u+QTxlFiAnb2J/2dgQqRy/XvziPtDd1rKZFXHTyYLoVL58M/XFwDI01AQCDIevGLbQrMAtdyanpA=="],
"vite/rollup/@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.40.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-L5ZLphTjjAD9leJzSLI7rr8fNqJMlGDKlazW2tX4IUF9P7R5TMQPElpH82Q7eNIDQnQlAyiNVfRPfP2vM5Avvg=="], "vite/rollup/@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.34.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-jpz9YOuPiSkL4G4pqKrus0pn9aYwpImGkosRKwNi+sJSkz+WU3anZe6hi73StLOQdfXYXC7hUfsQlTnjMd3s1A=="],
"vite/rollup/@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.40.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-ATZvCRGCDtv1Y4gpDIXsS+wfFeFuLwVxyUBSLawjgXK2tRE6fnsQEkE4csQQYWlBlsFztRzCnBvWVfcae/1qxQ=="], "vite/rollup/@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.34.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-KdSfaROOUJXgTVxJNAZ3KwkRc5nggDk+06P6lgi1HLv1hskgvxHUKZ4xtwHkVYJ1Rep4GNo+uEfycCRRxht7+Q=="],
"vite/rollup/@rollup/rollup-linux-loongarch64-gnu": ["@rollup/rollup-linux-loongarch64-gnu@4.40.0", "", { "os": "linux", "cpu": "none" }, "sha512-wG9e2XtIhd++QugU5MD9i7OnpaVb08ji3P1y/hNbxrQ3sYEelKJOq1UJ5dXczeo6Hj2rfDEL5GdtkMSVLa/AOg=="], "vite/rollup/@rollup/rollup-linux-loongarch64-gnu": ["@rollup/rollup-linux-loongarch64-gnu@4.34.8", "", { "os": "linux", "cpu": "none" }, "sha512-NyF4gcxwkMFRjgXBM6g2lkT58OWztZvw5KkV2K0qqSnUEqCVcqdh2jN4gQrTn/YUpAcNKyFHfoOZEer9nwo6uQ=="],
"vite/rollup/@rollup/rollup-linux-powerpc64le-gnu": ["@rollup/rollup-linux-powerpc64le-gnu@4.40.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-vgXfWmj0f3jAUvC7TZSU/m/cOE558ILWDzS7jBhiCAFpY2WEBn5jqgbqvmzlMjtp8KlLcBlXVD2mkTSEQE6Ixw=="], "vite/rollup/@rollup/rollup-linux-powerpc64le-gnu": ["@rollup/rollup-linux-powerpc64le-gnu@4.34.8", "", { "os": "linux", "cpu": "ppc64" }, "sha512-LMJc999GkhGvktHU85zNTDImZVUCJ1z/MbAJTnviiWmmjyckP5aQsHtcujMjpNdMZPT2rQEDBlJfubhs3jsMfw=="],
"vite/rollup/@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.40.0", "", { "os": "linux", "cpu": "none" }, "sha512-uJkYTugqtPZBS3Z136arevt/FsKTF/J9dEMTX/cwR7lsAW4bShzI2R0pJVw+hcBTWF4dxVckYh72Hk3/hWNKvA=="], "vite/rollup/@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.34.8", "", { "os": "linux", "cpu": "none" }, "sha512-xAQCAHPj8nJq1PI3z8CIZzXuXCstquz7cIOL73HHdXiRcKk8Ywwqtx2wrIy23EcTn4aZ2fLJNBB8d0tQENPCmw=="],
"vite/rollup/@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.40.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-SpnYlAfKPOoVsQqmTFJ0usx0z84bzGOS9anAC0AZ3rdSo3snecihbhFTlJZ8XMwzqAcodjFU4+/SM311dqE5Sw=="], "vite/rollup/@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.34.8", "", { "os": "linux", "cpu": "s390x" }, "sha512-DdePVk1NDEuc3fOe3dPPTb+rjMtuFw89gw6gVWxQFAuEqqSdDKnrwzZHrUYdac7A7dXl9Q2Vflxpme15gUWQFA=="],
"vite/rollup/@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.40.0", "", { "os": "linux", "cpu": "x64" }, "sha512-RcDGMtqF9EFN8i2RYN2W+64CdHruJ5rPqrlYw+cgM3uOVPSsnAQps7cpjXe9be/yDp8UC7VLoCoKC8J3Kn2FkQ=="], "vite/rollup/@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.34.8", "", { "os": "linux", "cpu": "x64" }, "sha512-8y7ED8gjxITUltTUEJLQdgpbPh1sUQ0kMTmufRF/Ns5tI9TNMNlhWtmPKKHCU0SilX+3MJkZ0zERYYGIVBYHIA=="],
"vite/rollup/@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.40.0", "", { "os": "linux", "cpu": "x64" }, "sha512-HZvjpiUmSNx5zFgwtQAV1GaGazT2RWvqeDi0hV+AtC8unqqDSsaFjPxfsO6qPtKRRg25SisACWnJ37Yio8ttaw=="], "vite/rollup/@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.34.8", "", { "os": "linux", "cpu": "x64" }, "sha512-SCXcP0ZpGFIe7Ge+McxY5zKxiEI5ra+GT3QRxL0pMMtxPfpyLAKleZODi1zdRHkz5/BhueUrYtYVgubqe9JBNQ=="],
"vite/rollup/@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.40.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-UtZQQI5k/b8d7d3i9AZmA/t+Q4tk3hOC0tMOMSq2GlMYOfxbesxG4mJSeDp0EHs30N9bsfwUvs3zF4v/RzOeTQ=="], "vite/rollup/@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.34.8", "", { "os": "win32", "cpu": "arm64" }, "sha512-YHYsgzZgFJzTRbth4h7Or0m5O74Yda+hLin0irAIobkLQFRQd1qWmnoVfwmKm9TXIZVAD0nZ+GEb2ICicLyCnQ=="],
"vite/rollup/@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.40.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-+m03kvI2f5syIqHXCZLPVYplP8pQch9JHyXKZ3AGMKlg8dCyr2PKHjwRLiW53LTrN/Nc3EqHOKxUxzoSPdKddA=="], "vite/rollup/@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.34.8", "", { "os": "win32", "cpu": "ia32" }, "sha512-r3NRQrXkHr4uWy5TOjTpTYojR9XmF0j/RYgKCef+Ag46FWUTltm5ziticv8LdNsDMehjJ543x/+TJAek/xBA2w=="],
"vite/rollup/@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.40.0", "", { "os": "win32", "cpu": "x64" }, "sha512-lpPE1cLfP5oPzVjKMx10pgBmKELQnFJXHgvtHCtuJWOv8MxqdEIMNtgHgBFf7Ea2/7EuVwa9fodWUfXAlXZLZQ=="], "vite/rollup/@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.34.8", "", { "os": "win32", "cpu": "x64" }, "sha512-U0FaE5O1BCpZSeE6gBl3c5ObhePQSfk9vDRToMmTkbhCOgW4jqvtS5LGyQ76L1fH8sM0keRp4uDTsbjiUyjk0g=="],
"vite/rollup/@types/estree": ["@types/estree@1.0.7", "", {}, "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ=="],
"@ryoppippi/unplugin-typia/vite/rollup/@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.34.8", "", { "os": "android", "cpu": "arm" }, "sha512-q217OSE8DTp8AFHuNHXo0Y86e1wtlfVrXiAlwkIvGRQv9zbc6mE3sjIVfwI8sYUyNxwOg0j/Vm1RKM04JcWLJw=="],
"@ryoppippi/unplugin-typia/vite/rollup/@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.34.8", "", { "os": "android", "cpu": "arm64" }, "sha512-Gigjz7mNWaOL9wCggvoK3jEIUUbGul656opstjaUSGC3eT0BM7PofdAJaBfPFWWkXNVAXbaQtC99OCg4sJv70Q=="],
"@ryoppippi/unplugin-typia/vite/rollup/@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.34.8", "", { "os": "darwin", "cpu": "arm64" }, "sha512-02rVdZ5tgdUNRxIUrFdcMBZQoaPMrxtwSb+/hOfBdqkatYHR3lZ2A2EGyHq2sGOd0Owk80oV3snlDASC24He3Q=="],
"@ryoppippi/unplugin-typia/vite/rollup/@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.34.8", "", { "os": "darwin", "cpu": "x64" }, "sha512-qIP/elwR/tq/dYRx3lgwK31jkZvMiD6qUtOycLhTzCvrjbZ3LjQnEM9rNhSGpbLXVJYQ3rq39A6Re0h9tU2ynw=="],
"@ryoppippi/unplugin-typia/vite/rollup/@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.34.8", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-IQNVXL9iY6NniYbTaOKdrlVP3XIqazBgJOVkddzJlqnCpRi/yAeSOa8PLcECFSQochzqApIOE1GHNu3pCz+BDA=="],
"@ryoppippi/unplugin-typia/vite/rollup/@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.34.8", "", { "os": "freebsd", "cpu": "x64" }, "sha512-TYXcHghgnCqYFiE3FT5QwXtOZqDj5GmaFNTNt3jNC+vh22dc/ukG2cG+pi75QO4kACohZzidsq7yKTKwq/Jq7Q=="],
"@ryoppippi/unplugin-typia/vite/rollup/@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.34.8", "", { "os": "linux", "cpu": "arm" }, "sha512-A4iphFGNkWRd+5m3VIGuqHnG3MVnqKe7Al57u9mwgbyZ2/xF9Jio72MaY7xxh+Y87VAHmGQr73qoKL9HPbXj1g=="],
"@ryoppippi/unplugin-typia/vite/rollup/@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.34.8", "", { "os": "linux", "cpu": "arm" }, "sha512-S0lqKLfTm5u+QTxlFiAnb2J/2dgQqRy/XvziPtDd1rKZFXHTyYLoVL58M/XFwDI01AQCDIevGLbQrMAtdyanpA=="],
"@ryoppippi/unplugin-typia/vite/rollup/@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.34.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-jpz9YOuPiSkL4G4pqKrus0pn9aYwpImGkosRKwNi+sJSkz+WU3anZe6hi73StLOQdfXYXC7hUfsQlTnjMd3s1A=="],
"@ryoppippi/unplugin-typia/vite/rollup/@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.34.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-KdSfaROOUJXgTVxJNAZ3KwkRc5nggDk+06P6lgi1HLv1hskgvxHUKZ4xtwHkVYJ1Rep4GNo+uEfycCRRxht7+Q=="],
"@ryoppippi/unplugin-typia/vite/rollup/@rollup/rollup-linux-loongarch64-gnu": ["@rollup/rollup-linux-loongarch64-gnu@4.34.8", "", { "os": "linux", "cpu": "none" }, "sha512-NyF4gcxwkMFRjgXBM6g2lkT58OWztZvw5KkV2K0qqSnUEqCVcqdh2jN4gQrTn/YUpAcNKyFHfoOZEer9nwo6uQ=="],
"@ryoppippi/unplugin-typia/vite/rollup/@rollup/rollup-linux-powerpc64le-gnu": ["@rollup/rollup-linux-powerpc64le-gnu@4.34.8", "", { "os": "linux", "cpu": "ppc64" }, "sha512-LMJc999GkhGvktHU85zNTDImZVUCJ1z/MbAJTnviiWmmjyckP5aQsHtcujMjpNdMZPT2rQEDBlJfubhs3jsMfw=="],
"@ryoppippi/unplugin-typia/vite/rollup/@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.34.8", "", { "os": "linux", "cpu": "none" }, "sha512-xAQCAHPj8nJq1PI3z8CIZzXuXCstquz7cIOL73HHdXiRcKk8Ywwqtx2wrIy23EcTn4aZ2fLJNBB8d0tQENPCmw=="],
"@ryoppippi/unplugin-typia/vite/rollup/@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.34.8", "", { "os": "linux", "cpu": "s390x" }, "sha512-DdePVk1NDEuc3fOe3dPPTb+rjMtuFw89gw6gVWxQFAuEqqSdDKnrwzZHrUYdac7A7dXl9Q2Vflxpme15gUWQFA=="],
"@ryoppippi/unplugin-typia/vite/rollup/@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.34.8", "", { "os": "linux", "cpu": "x64" }, "sha512-8y7ED8gjxITUltTUEJLQdgpbPh1sUQ0kMTmufRF/Ns5tI9TNMNlhWtmPKKHCU0SilX+3MJkZ0zERYYGIVBYHIA=="],
"@ryoppippi/unplugin-typia/vite/rollup/@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.34.8", "", { "os": "linux", "cpu": "x64" }, "sha512-SCXcP0ZpGFIe7Ge+McxY5zKxiEI5ra+GT3QRxL0pMMtxPfpyLAKleZODi1zdRHkz5/BhueUrYtYVgubqe9JBNQ=="],
"@ryoppippi/unplugin-typia/vite/rollup/@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.34.8", "", { "os": "win32", "cpu": "arm64" }, "sha512-YHYsgzZgFJzTRbth4h7Or0m5O74Yda+hLin0irAIobkLQFRQd1qWmnoVfwmKm9TXIZVAD0nZ+GEb2ICicLyCnQ=="],
"@ryoppippi/unplugin-typia/vite/rollup/@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.34.8", "", { "os": "win32", "cpu": "ia32" }, "sha512-r3NRQrXkHr4uWy5TOjTpTYojR9XmF0j/RYgKCef+Ag46FWUTltm5ziticv8LdNsDMehjJ543x/+TJAek/xBA2w=="],
"@ryoppippi/unplugin-typia/vite/rollup/@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.34.8", "", { "os": "win32", "cpu": "x64" }, "sha512-U0FaE5O1BCpZSeE6gBl3c5ObhePQSfk9vDRToMmTkbhCOgW4jqvtS5LGyQ76L1fH8sM0keRp4uDTsbjiUyjk0g=="],
"pkg-dir/find-up/locate-path/p-locate": ["p-locate@6.0.0", "", { "dependencies": { "p-limit": "^4.0.0" } }, "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw=="], "pkg-dir/find-up/locate-path/p-locate": ["p-locate@6.0.0", "", { "dependencies": { "p-limit": "^4.0.0" } }, "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw=="],

View File

@@ -1 +0,0 @@
ALTER TABLE `devices` DROP COLUMN `opnsense_id`;

View File

@@ -1,222 +0,0 @@
{
"version": "6",
"dialect": "sqlite",
"id": "0b364191-58d0-46a3-8372-4a30b0b88d85",
"prevId": "cc1fa973-1e9c-4bd6-b082-d7cf36f7342c",
"tables": {
"devices": {
"name": "devices",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true,
"autoincrement": true
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"public_key": {
"name": "public_key",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"private_key": {
"name": "private_key",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"pre_shared_key": {
"name": "pre_shared_key",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"devices_public_key_unique": {
"name": "devices_public_key_unique",
"columns": [
"public_key"
],
"isUnique": true
}
},
"foreignKeys": {
"devices_user_id_users_id_fk": {
"name": "devices_user_id_users_id_fk",
"tableFrom": "devices",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"ip_allocations": {
"name": "ip_allocations",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true,
"autoincrement": true
},
"device_id": {
"name": "device_id",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"ip_allocations_device_id_unique": {
"name": "ip_allocations_device_id_unique",
"columns": [
"device_id"
],
"isUnique": true
}
},
"foreignKeys": {
"ip_allocations_device_id_devices_id_fk": {
"name": "ip_allocations_device_id_devices_id_fk",
"tableFrom": "ip_allocations",
"tableTo": "devices",
"columnsFrom": [
"device_id"
],
"columnsTo": [
"id"
],
"onDelete": "set null",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"sessions": {
"name": "sessions",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"expires_at": {
"name": "expires_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"sessions_user_id_users_id_fk": {
"name": "sessions_user_id_users_id_fk",
"tableFrom": "sessions",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"users": {
"name": "users",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"auth_source": {
"name": "auth_source",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "'authentik'"
},
"username": {
"name": "username",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
}
},
"views": {},
"enums": {},
"_meta": {
"schemas": {},
"tables": {},
"columns": {}
},
"internal": {
"indexes": {}
}
}

View File

@@ -15,13 +15,6 @@
"when": 1741936760967, "when": 1741936760967,
"tag": "0001_equal_unicorn", "tag": "0001_equal_unicorn",
"breakpoints": true "breakpoints": true
},
{
"idx": 2,
"version": "6",
"when": 1743389268079,
"tag": "0002_minor_black_panther",
"breakpoints": true
} }
] ]
} }

View File

@@ -19,48 +19,48 @@
"prepare": "ts-patch install" "prepare": "ts-patch install"
}, },
"devDependencies": { "devDependencies": {
"@lucide/svelte": "^0.487.0",
"@oslojs/crypto": "^1.0.1", "@oslojs/crypto": "^1.0.1",
"@oslojs/encoding": "^1.1.0", "@oslojs/encoding": "^1.1.0",
"@ryoppippi/unplugin-typia": "npm:@jsr/ryoppippi__unplugin-typia", "@ryoppippi/unplugin-typia": "npm:@jsr/ryoppippi__unplugin-typia",
"@sveltejs/adapter-auto": "^3.3.1", "@sveltejs/adapter-auto": "^3.3.1",
"@sveltejs/adapter-node": "^5.2.12", "@sveltejs/adapter-node": "^5.2.12",
"@sveltejs/kit": "^2.20.7", "@sveltejs/kit": "^2.19.1",
"@sveltejs/vite-plugin-svelte": "^5.0.3", "@sveltejs/vite-plugin-svelte": "^5.0.3",
"@tailwindcss/container-queries": "^0.1.1", "@tailwindcss/container-queries": "^0.1.1",
"@tailwindcss/forms": "^0.5.10", "@tailwindcss/forms": "^0.5.10",
"@tailwindcss/typography": "^0.5.16", "@tailwindcss/typography": "^0.5.16",
"@types/better-sqlite3": "^7.6.13", "@types/better-sqlite3": "^7.6.12",
"@types/eslint": "^9.6.1", "@types/eslint": "^9.6.1",
"@types/qrcode-svg": "^1.1.5", "@types/qrcode-svg": "^1.1.5",
"arctic": "^2.3.4", "arctic": "^2.3.4",
"autoprefixer": "^10.4.21", "autoprefixer": "^10.4.21",
"bits-ui": "^1.3.19", "bits-ui": "^0.22.0",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"eslint": "^9.25.1", "eslint": "^9.22.0",
"eslint-config-prettier": "^9.1.0", "eslint-config-prettier": "^9.1.0",
"eslint-plugin-svelte": "^2.46.1", "eslint-plugin-svelte": "^2.46.1",
"globals": "^15.15.0", "globals": "^15.15.0",
"ip-address": "^10.0.1", "ip-address": "^10.0.1",
"lucide-svelte": "^0.469.0",
"prettier": "^3.5.3", "prettier": "^3.5.3",
"prettier-plugin-svelte": "^3.3.3", "prettier-plugin-svelte": "^3.3.3",
"prettier-plugin-tailwindcss": "^0.6.11", "prettier-plugin-tailwindcss": "^0.6.11",
"qrcode-svg": "^1.1.0", "qrcode-svg": "^1.1.0",
"svelte": "^5.28.1", "svelte": "^5.23.0",
"svelte-check": "^4.1.6", "svelte-check": "^4.1.5",
"tailwind-merge": "^2.6.0", "tailwind-merge": "^2.6.0",
"tailwind-variants": "^0.3.1", "tailwind-variants": "^0.3.1",
"tailwindcss": "^3.4.17", "tailwindcss": "^3.4.17",
"tailwindcss-animate": "^1.0.7", "tailwindcss-animate": "^1.0.7",
"ts-patch": "^3.3.0", "ts-patch": "^3.3.0",
"typescript": "~5.8.3", "typescript": "~5.8.2",
"typescript-eslint": "^8.31.0", "typescript-eslint": "^8.26.1",
"typia": "^8.2.0", "typia": "^8.0.2",
"vite": "^6.3.2" "vite": "^6.2.2"
}, },
"dependencies": { "dependencies": {
"@libsql/client": "^0.14.0", "@libsql/client": "^0.14.0",
"drizzle-kit": "^0.30.6", "drizzle-kit": "^0.30.5",
"drizzle-orm": "^0.38.4" "drizzle-orm": "^0.38.4"
} }
} }

View File

@@ -2,9 +2,23 @@ import { type Handle, redirect } from '@sveltejs/kit';
import { sequence } from '@sveltejs/kit/hooks'; import { sequence } from '@sveltejs/kit/hooks';
import { dev } from '$app/environment'; import { dev } from '$app/environment';
import * as auth from '$lib/server/auth'; import * as auth from '$lib/server/auth';
import wgProvider from '$lib/server/wg-provider'; import { WgProviderOpnsense } from '$lib/server/providers/opnsense';
import { env } from '$env/dynamic/private';
await wgProvider.init(); // TODO: probably move this to a separate file,
// without injecting the provider into the event
const provider = new WgProviderOpnsense({
opnsenseUrl: env.OPNSENSE_API_URL,
opnsenseApiKey: env.OPNSENSE_API_KEY,
opnsenseApiSecret: env.OPNSENSE_API_SECRET,
opnsenseWgIfname: env.OPNSENSE_WG_IFNAME,
});
await provider.init();
const injectWgProvider: Handle = ({ event, resolve }) => {
event.locals.wgProvider = provider;
return resolve(event);
}
const handleAuth: Handle = async ({ event, resolve }) => { const handleAuth: Handle = async ({ event, resolve }) => {
const sessionId = event.cookies.get(auth.sessionCookieName); const sessionId = event.cookies.get(auth.sessionCookieName);
@@ -49,4 +63,4 @@ const handleProtectedPaths: Handle = ({ event, resolve }) => {
return resolve(event); return resolve(event);
} }
export const handle: Handle = sequence(handleAuth, handleProtectedPaths); export const handle: Handle = sequence(injectWgProvider, handleAuth, handleProtectedPaths);

View File

@@ -1,9 +0,0 @@
import { envToBool } from '$lib/utils';
import { env } from '$env/dynamic/public';
export type AuthProvider = 'authentik' | 'google';
export const enabledAuthProviders: Record<AuthProvider, boolean> = {
authentik: envToBool(env.PUBLIC_AUTH_AUTHENTIK_ENABLE),
google: envToBool(env.PUBLIC_AUTH_GOOGLE_ENABLE),
};

View File

@@ -1,26 +1,24 @@
<script lang="ts"> <script lang="ts">
import { LucideLoaderCircle } from '@lucide/svelte'; import { LucideLoaderCircle } from 'lucide-svelte';
import { Button } from '$lib/components/ui/button'; import { Button } from '$lib/components/ui/button';
import { cn } from '$lib/utils.js'; import { cn } from '$lib/utils.js';
import googleIcon from '$lib/assets/google.svg'; import googleIcon from '$lib/assets/google.svg';
import { enabledAuthProviders } from '$lib/auth';
let { inviteToken, class: className, ...rest }: { let { inviteToken, class: className, ...rest }: { inviteToken?: string; class?: string; rest?: { [p: string]: unknown } } = $props();
inviteToken?: string;
class?: string;
rest?: { [p: string]: unknown }
} = $props();
let submitted = $state(false); let isLoading = $state(false);
</script> </script>
<div class={cn('flex gap-6', className)} {...rest}> <div class={cn('flex gap-6', className)} {...rest}>
{#if enabledAuthProviders.authentik } <form method="get" action="/auth/authentik{inviteToken ? `?invite=${inviteToken}` : ''}">
<form method="get" onsubmit={() => submitted = true}
action="/auth/authentik{inviteToken ? `?invite=${inviteToken}` : ''}">
<input type="hidden" value={inviteToken} name="invite" /> <input type="hidden" value={inviteToken} name="invite" />
<Button type="submit" disabled={submitted}> <Button
{#if submitted} type="submit"
onclick={() => {
isLoading = true;
}}
>
{#if isLoading}
<LucideLoaderCircle class="mr-2 h-4 w-4 animate-spin" /> <LucideLoaderCircle class="mr-2 h-4 w-4 animate-spin" />
{:else} {:else}
<img <img
@@ -32,13 +30,15 @@
Sign in with Authentik Sign in with Authentik
</Button> </Button>
</form> </form>
{/if} <form method="get" action="/auth/google">
{#if enabledAuthProviders.google }
<form method="get" onsubmit={() => submitted = true}
action="/auth/google{inviteToken ? `?invite=${inviteToken}` : ''}">
<input type="hidden" value={inviteToken} name="invite" /> <input type="hidden" value={inviteToken} name="invite" />
<Button type="submit" disabled={submitted}> <Button
{#if submitted} type="submit"
onclick={() => {
isLoading = true;
}}
>
{#if isLoading}
<LucideLoaderCircle class="mr-2 h-4 w-4 animate-spin" /> <LucideLoaderCircle class="mr-2 h-4 w-4 animate-spin" />
{:else} {:else}
<img <img
@@ -50,5 +50,4 @@
Sign in with Google Sign in with Google
</Button> </Button>
</form> </form>
{/if}
</div> </div>

View File

@@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import { Button } from '$lib/components/ui/button'; import { Button } from '$lib/components/ui/button';
import { LucideClipboardCopy, LucideDownload } from '@lucide/svelte'; import { LucideClipboardCopy, LucideDownload } from 'lucide-svelte';
const { const {
data, data,

View File

@@ -43,7 +43,7 @@
this={href ? "a" : "span"} this={href ? "a" : "span"}
bind:this={ref} bind:this={ref}
{href} {href}
class={cn(badgeVariants({ variant }), className)} class={cn(badgeVariants({ variant, className }))}
{...restProps} {...restProps}
> >
{@render children?.()} {@render children?.()}

View File

@@ -56,7 +56,7 @@
{#if href} {#if href}
<a <a
bind:this={ref} bind:this={ref}
class={cn(buttonVariants({ variant, size }), className)} class={cn(buttonVariants({ variant, size, className }))}
{href} {href}
{...restProps} {...restProps}
> >
@@ -65,7 +65,7 @@
{:else} {:else}
<button <button
bind:this={ref} bind:this={ref}
class={cn(buttonVariants({ variant, size }), className)} class={cn(buttonVariants({ variant, size, className }))}
{type} {type}
{...restProps} {...restProps}
> >

View File

@@ -1,7 +1,7 @@
<script lang="ts"> <script lang="ts">
import { Checkbox as CheckboxPrimitive, type WithoutChildrenOrChild } from "bits-ui"; import { Checkbox as CheckboxPrimitive, type WithoutChildrenOrChild } from "bits-ui";
import Check from "@lucide/svelte/icons/check"; import Check from "lucide-svelte/icons/check";
import Minus from "@lucide/svelte/icons/minus"; import Minus from "lucide-svelte/icons/minus";
import { cn } from "$lib/utils.js"; import { cn } from "$lib/utils.js";
let { let {

View File

@@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import { Dialog as DialogPrimitive, type WithoutChildrenOrChild } from "bits-ui"; import { Dialog as DialogPrimitive, type WithoutChildrenOrChild } from "bits-ui";
import X from "@lucide/svelte/icons/x"; import X from "lucide-svelte/icons/x";
import type { Snippet } from "svelte"; import type { Snippet } from "svelte";
import * as Dialog from "./index.js"; import * as Dialog from "./index.js";
import { cn } from "$lib/utils.js"; import { cn } from "$lib/utils.js";
@@ -17,7 +17,7 @@
} = $props(); } = $props();
</script> </script>
<Dialog.Portal {...portalProps}> <Dialog.Portal class="absolute" {...portalProps}>
<Dialog.Overlay /> <Dialog.Overlay />
<DialogPrimitive.Content <DialogPrimitive.Content
bind:ref bind:ref

View File

@@ -5,6 +5,7 @@
let { let {
ref = $bindable(null), ref = $bindable(null),
class: className, class: className,
children,
...restProps ...restProps
}: DialogPrimitive.DescriptionProps = $props(); }: DialogPrimitive.DescriptionProps = $props();
</script> </script>
@@ -13,4 +14,6 @@
bind:ref bind:ref
class={cn("text-muted-foreground text-sm", className)} class={cn("text-muted-foreground text-sm", className)}
{...restProps} {...restProps}
/> >
{@render children?.()}
</DialogPrimitive.Description>

View File

@@ -5,6 +5,7 @@
let { let {
ref = $bindable(null), ref = $bindable(null),
class: className, class: className,
children,
...restProps ...restProps
}: DialogPrimitive.OverlayProps = $props(); }: DialogPrimitive.OverlayProps = $props();
</script> </script>
@@ -16,4 +17,6 @@
className className
)} )}
{...restProps} {...restProps}
/> >
{@render children?.()}
</DialogPrimitive.Overlay>

View File

@@ -5,6 +5,7 @@
let { let {
ref = $bindable(null), ref = $bindable(null),
class: className, class: className,
children,
...restProps ...restProps
}: DialogPrimitive.TitleProps = $props(); }: DialogPrimitive.TitleProps = $props();
</script> </script>
@@ -13,4 +14,6 @@
bind:ref bind:ref
class={cn("text-lg font-semibold leading-none tracking-tight", className)} class={cn("text-lg font-semibold leading-none tracking-tight", className)}
{...restProps} {...restProps}
/> >
{@render children?.()}
</DialogPrimitive.Title>

View File

@@ -1,46 +1,22 @@
<script lang="ts"> <script lang="ts">
import type { HTMLInputAttributes, HTMLInputTypeAttribute } from "svelte/elements"; import type { HTMLInputAttributes } from "svelte/elements";
import type { WithElementRef } from "bits-ui"; import type { WithElementRef } from "bits-ui";
import { cn } from "$lib/utils.js"; import { cn } from "$lib/utils.js";
type InputType = Exclude<HTMLInputTypeAttribute, "file">;
type Props = WithElementRef<
Omit<HTMLInputAttributes, "type"> &
({ type: "file"; files?: FileList } | { type?: InputType; files?: undefined })
>;
let { let {
ref = $bindable(null), ref = $bindable(null),
value = $bindable(), value = $bindable(),
type,
files = $bindable(),
class: className, class: className,
...restProps ...restProps
}: Props = $props(); }: WithElementRef<HTMLInputAttributes> = $props();
</script> </script>
{#if type === "file"} <input
<input bind:this={ref}
bind:this={ref} class={cn(
class={cn( "border-input bg-background ring-offset-background placeholder:text-muted-foreground focus-visible:ring-ring flex h-10 w-full rounded-md border px-3 py-2 text-base file:border-0 file:bg-transparent file:text-sm file:font-medium focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
"border-input bg-background ring-offset-background placeholder:text-muted-foreground focus-visible:ring-ring flex h-10 w-full rounded-md border px-3 py-2 text-base file:border-0 file:bg-transparent file:text-sm file:font-medium focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm", className
className )}
)} bind:value
type="file" {...restProps}
bind:files />
bind:value
{...restProps}
/>
{:else}
<input
bind:this={ref}
class={cn(
"border-input bg-background ring-offset-background placeholder:text-muted-foreground focus-visible:ring-ring flex h-10 w-full rounded-md border px-3 py-2 text-base file:border-0 file:bg-transparent file:text-sm file:font-medium focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
className
)}
{type}
bind:value
{...restProps}
/>
{/if}

View File

@@ -5,6 +5,7 @@
let { let {
ref = $bindable(null), ref = $bindable(null),
class: className, class: className,
children,
...restProps ...restProps
}: LabelPrimitive.RootProps = $props(); }: LabelPrimitive.RootProps = $props();
</script> </script>
@@ -16,4 +17,6 @@
className className
)} )}
{...restProps} {...restProps}
/> >
{@render children?.()}
</LabelPrimitive.Root>

View File

@@ -5,6 +5,7 @@
let { let {
ref = $bindable(null), ref = $bindable(null),
class: className, class: className,
children,
...restProps ...restProps
}: TabsPrimitive.ContentProps = $props(); }: TabsPrimitive.ContentProps = $props();
</script> </script>
@@ -16,4 +17,6 @@
className className
)} )}
{...restProps} {...restProps}
/> >
{@render children?.()}
</TabsPrimitive.Content>

View File

@@ -5,6 +5,7 @@
let { let {
ref = $bindable(null), ref = $bindable(null),
class: className, class: className,
children,
...restProps ...restProps
}: TabsPrimitive.ListProps = $props(); }: TabsPrimitive.ListProps = $props();
</script> </script>
@@ -16,4 +17,6 @@
className className
)} )}
{...restProps} {...restProps}
/> >
{@render children?.()}
</TabsPrimitive.List>

View File

@@ -5,6 +5,7 @@
let { let {
ref = $bindable(null), ref = $bindable(null),
class: className, class: className,
children,
...restProps ...restProps
}: TabsPrimitive.TriggerProps = $props(); }: TabsPrimitive.TriggerProps = $props();
</script> </script>
@@ -16,4 +17,6 @@
className className
)} )}
{...restProps} {...restProps}
/> >
{@render children?.()}
</TabsPrimitive.Trigger>

View File

@@ -0,0 +1,3 @@
export function opnsenseSanitezedUsername(username: string) {
return username.slice(0, 63).replace(/[^a-zA-Z0-9_-]/g, '_');
}

View File

@@ -3,7 +3,7 @@ import { sha256 } from '@oslojs/crypto/sha2';
import { encodeBase32LowerCaseNoPadding, encodeHexLowerCase } from '@oslojs/encoding'; import { encodeBase32LowerCaseNoPadding, encodeHexLowerCase } from '@oslojs/encoding';
import { db } from '$lib/server/db'; import { db } from '$lib/server/db';
import * as table from '$lib/server/db/schema'; import * as table from '$lib/server/db/schema';
import type { Cookies } from '@sveltejs/kit'; import type { RequestEvent } from '@sveltejs/kit';
import { dev } from '$app/environment'; import { dev } from '$app/environment';
import { env } from '$env/dynamic/private'; import { env } from '$env/dynamic/private';
@@ -22,14 +22,14 @@ export async function createSession(userId: string): Promise<table.Session> {
const session: table.Session = { const session: table.Session = {
id: sessionId, id: sessionId,
userId, userId,
expiresAt: new Date(Date.now() + DAY_IN_MS * 30), expiresAt: new Date(Date.now() + DAY_IN_MS * 30)
}; };
await db.insert(table.sessions).values(session); await db.insert(table.sessions).values(session);
return session; return session;
} }
export function setSessionTokenCookie(cookies: Cookies, sessionId: string, expiresAt: Date) { export function setSessionTokenCookie(event: RequestEvent, sessionId: string, expiresAt: Date) {
cookies.set(sessionCookieName, sessionId, { event.cookies.set(sessionCookieName, sessionId, {
path: '/', path: '/',
sameSite: 'lax', sameSite: 'lax',
httpOnly: true, httpOnly: true,
@@ -42,21 +42,16 @@ export async function invalidateSession(sessionId: string): Promise<void> {
await db.delete(table.sessions).where(eq(table.sessions.id, sessionId)); await db.delete(table.sessions).where(eq(table.sessions.id, sessionId));
} }
export function deleteSessionTokenCookie(cookies: Cookies) { export function deleteSessionTokenCookie(event: RequestEvent) {
cookies.delete(sessionCookieName, { path: '/' }); event.cookies.delete(sessionCookieName, { path: '/' });
} }
export async function validateSession(sessionId: string) { export async function validateSession(sessionId: string) {
const [result] = await db const [result] = await db
.select({ .select({
// Adjust user table here to tweak returned data // Adjust user table here to tweak returned data
user: { user: { id: table.users.id, authSource: table.users.authSource, username: table.users.username, name: table.users.name },
id: table.users.id, session: table.sessions
authSource: table.users.authSource,
username: table.users.username,
name: table.users.name,
},
session: table.sessions,
}) })
.from(table.sessions) .from(table.sessions)
.innerJoin(table.users, eq(table.sessions.userId, table.users.id)) .innerJoin(table.users, eq(table.sessions.userId, table.users.id))
@@ -86,7 +81,7 @@ export async function validateSession(sessionId: string) {
} }
export function isValidInviteToken(inviteToken: string) { export function isValidInviteToken(inviteToken: string) {
return inviteToken === env.AUTH_INVITE_TOKEN; return inviteToken === env.INVITE_TOKEN;
} }
export type SessionValidationResult = Awaited<ReturnType<typeof validateSession>>; export type SessionValidationResult = Awaited<ReturnType<typeof validateSession>>;

View File

@@ -36,6 +36,8 @@ export const devices = sqliteTable('devices', {
.notNull() .notNull()
.references(() => users.id), .references(() => users.id),
name: text('name').notNull(), name: text('name').notNull(),
// questioning whether this should be nullable
opnsenseId: text('opnsense_id'),
publicKey: text('public_key').notNull().unique(), publicKey: text('public_key').notNull().unique(),
// nullable for the possibility of a user supplying their own private key // nullable for the possibility of a user supplying their own private key
privateKey: text('private_key'), privateKey: text('private_key'),

View File

@@ -4,9 +4,9 @@ import { db } from '$lib/server/db';
import { count, eq, isNull } from 'drizzle-orm'; import { count, eq, isNull } from 'drizzle-orm';
import { env } from '$env/dynamic/private'; import { env } from '$env/dynamic/private';
import { getIpsFromIndex } from './utils'; import { getIpsFromIndex } from './utils';
import wgProvider from '$lib/server/wg-provider'; import type { IWgProvider } from '$lib/server/types';
export async function createDevice(params: { export async function createDevice(wgProvider: IWgProvider, params: {
name: string; name: string;
user: User; user: User;
}): Promise<Result<number, [400 | 500, string]>> { }): Promise<Result<number, [400 | 500, string]>> {
@@ -18,14 +18,16 @@ export async function createDevice(params: {
if (deviceCount >= parseInt(env.MAX_CLIENTS_PER_USER)) if (deviceCount >= parseInt(env.MAX_CLIENTS_PER_USER))
return err([400, 'Maximum number of devices reached'] as [400, string]); return err([400, 'Maximum number of devices reached'] as [400, string]);
// 1. fetch params for new device from provider // this is going to be quite long
// 1. fetch params for new device from opnsense api
// 2.1 get an allocation for the device // 2.1 get an allocation for the device
// 2.2. insert new device into db // 2.2. insert new device into db
// 2.3. update the allocation with the device id // 2.3. update the allocation with the device id
// 3. create the client in provider // 3. create the client in opnsense
// 4. reconfigure opnsense to enable the new client
return await db.transaction(async (tx) => { return await db.transaction(async (tx) => {
const [keysResult, availableAllocation, lastAllocation] = await Promise.all([ const [keysResult, availableAllocation, lastAllocation] = await Promise.all([
// fetch params for new device from provider // fetch params for new device from opnsense api
wgProvider.generateKeys(), wgProvider.generateKeys(),
// find first unallocated IP // find first unallocated IP
await tx.query.ipAllocations.findFirst({ await tx.query.ipAllocations.findFirst({
@@ -77,7 +79,7 @@ export async function createDevice(params: {
.set({ deviceId: newDevice.id }) .set({ deviceId: newDevice.id })
.where(eq(ipAllocations.id, ipAllocationId)); .where(eq(ipAllocations.id, ipAllocationId));
// create client in provider // create client in opnsense
const providerRes = await wgProvider.createClient({ const providerRes = await wgProvider.createClient({
user: params.user, user: params.user,
publicKey: keys.publicKey, publicKey: keys.publicKey,
@@ -86,7 +88,7 @@ export async function createDevice(params: {
}); });
if (providerRes._tag === 'err') { if (providerRes._tag === 'err') {
tx2.rollback(); tx2.rollback();
return err([500, 'Failed to create client in provider']); return err([500, 'Failed to create client in OPNsense']);
} }
return ok(newDevice.id); return ok(newDevice.id);
}); });

View File

@@ -2,7 +2,6 @@ import { and, eq } from 'drizzle-orm';
import { db } from '$lib/server/db'; import { db } from '$lib/server/db';
import { devices } from '$lib/server/db/schema'; import { devices } from '$lib/server/db/schema';
import { err, ok, type Result } from '$lib/types'; import { err, ok, type Result } from '$lib/types';
import wgProvider from '$lib/server/wg-provider';
export async function deleteDevice( export async function deleteDevice(
userId: string, userId: string,
@@ -15,13 +14,59 @@ export async function deleteDevice(
where: and(eq(devices.userId, userId), eq(devices.id, deviceId)), where: and(eq(devices.userId, userId), eq(devices.id, deviceId)),
}); });
if (!device) return err([400, 'Device not found']); if (!device) return err([400, 'Device not found']);
const opnsenseClientUuid = (await opnsenseFindClient(device.publicKey))?.['uuid'];
if (typeof opnsenseClientUuid !== 'string') {
console.error(
'failed to get OPNsense client for deletion for device',
deviceId,
device.publicKey,
);
return err([500, 'Error getting client from OPNsense']);
}
const providerDeletionResult = await wgProvider.deleteClient(device.publicKey); const opnsenseDeletionResult = await opnsenseDeleteClient(opnsenseClientUuid);
if (providerDeletionResult._tag === 'err') { if (opnsenseDeletionResult?.['result'] !== 'deleted') {
console.error('failed to delete provider client for device', deviceId, device.publicKey); console.error(
return err([500, 'Error deleting client in provider']); 'failed to delete OPNsense client for device',
deviceId,
device.publicKey,
'\n',
'OPNsense client uuid:',
opnsenseClientUuid,
);
return err([500, 'Error deleting client in OPNsense']);
} }
await db.delete(devices).where(eq(devices.id, deviceId)); await db.delete(devices).where(eq(devices.id, deviceId));
return ok(null); return ok(null);
} }
async function opnsenseFindClient(pubkey: string) {
const res = await fetch(`${opnsenseUrl}/api/wireguard/client/searchClient`, {
method: 'POST',
headers: {
Authorization: opnsenseAuth,
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
current: 1,
// "rowCount": 7,
sort: {},
searchPhrase: pubkey,
type: ['peer'],
}),
});
return (await res.json())?.rows?.[0] ?? null;
}
async function opnsenseDeleteClient(clientUuid: string) {
const res = await fetch(`${opnsenseUrl}/api/wireguard/client/delClient/${clientUuid}`, {
method: 'POST',
headers: {
Authorization: opnsenseAuth,
Accept: 'application/json',
},
});
return res.json();
}

View File

@@ -4,7 +4,6 @@ import { devices } from '$lib/server/db/schema';
import type { DeviceDetails } from '$lib/devices'; import type { DeviceDetails } from '$lib/devices';
import { env } from '$env/dynamic/private'; import { env } from '$env/dynamic/private';
import { getIpsFromIndex } from '$lib/server/devices/index'; import { getIpsFromIndex } from '$lib/server/devices/index';
import wgProvider from '$lib/server/wg-provider';
export async function findDevices(userId: string) { export async function findDevices(userId: string) {
return db.query.devices.findMany({ return db.query.devices.findMany({
@@ -49,7 +48,7 @@ export function mapDeviceToDetails(
privateKey: device.privateKey, privateKey: device.privateKey,
preSharedKey: device.preSharedKey, preSharedKey: device.preSharedKey,
ips, ips,
vpnPublicKey: wgProvider.getServerPublicKey(), vpnPublicKey: '', // TODO: fix
vpnEndpoint: env.VPN_ENDPOINT, vpnEndpoint: env.VPN_ENDPOINT,
vpnDns: env.VPN_DNS, vpnDns: env.VPN_DNS,
}; };

View File

@@ -1,34 +0,0 @@
import { envToBool } from '$lib/utils';
import { env } from '$env/dynamic/private';
import { Authentik, decodeIdToken } from 'arctic';
import { assertGuard } from 'typia';
import type { IOAuthProvider } from '$lib/server/oauth';
const authentikProvider = new Authentik(
env.AUTH_AUTHENTIK_DOMAIN,
env.AUTH_AUTHENTIK_CLIENT_ID,
env.AUTH_AUTHENTIK_CLIENT_SECRET,
`${env.ORIGIN}/auth/authentik/callback`,
);
export const authentik: IOAuthProvider = {
requireInvite: envToBool(env.AUTH_AUTHENTIK_REQUIRE_INVITE, true),
createAuthorizationURL: (state: string, codeVerifier: string) => {
const scopes = ['openid', 'profile'];
return authentikProvider.createAuthorizationURL(state, codeVerifier, scopes);
},
validateAuthorizationCode: async (code: string, codeVerifier: string) => {
const tokens = await authentikProvider.validateAuthorizationCode(code, codeVerifier);
const claims = decodeIdToken(tokens.idToken());
assertGuard<{
sub: string;
name: string;
preferred_username: string;
}>(claims);
return {
sub: claims.sub,
name: claims.name,
username: claims.preferred_username,
};
},
};

View File

@@ -1,33 +0,0 @@
import { decodeIdToken, Google } from 'arctic';
import { env } from '$env/dynamic/private';
import { envToBool } from '$lib/utils';
import { assertGuard } from 'typia';
import type { IOAuthProvider } from '$lib/server/oauth';
const googleProvider = new Google(
env.AUTH_GOOGLE_CLIENT_ID,
env.AUTH_GOOGLE_CLIENT_SECRET,
`${env.ORIGIN}/auth/google/callback`,
);
export const google: IOAuthProvider = {
requireInvite: envToBool(env.AUTH_GOOGLE_REQUIRE_INVITE, true),
createAuthorizationURL: (state: string, codeVerifier: string) => {
const scopes = ['openid', 'profile', 'email'];
return googleProvider.createAuthorizationURL(state, codeVerifier, scopes);
},
validateAuthorizationCode: async (code: string, codeVerifier: string) => {
const tokens = await googleProvider.validateAuthorizationCode(code, codeVerifier);
const claims = decodeIdToken(tokens.idToken());
assertGuard<{
sub: string;
email: string;
name: string;
}>(claims);
return {
sub: claims.sub,
name: claims.name,
username: claims.email,
};
},
};

View File

@@ -1,2 +0,0 @@
export { authentik } from './authentik';
export { google } from './google';

View File

@@ -1,19 +1,15 @@
import type { AuthProvider } from '$lib/auth'; import { Authentik, Google } from 'arctic';
import { authentik, google } from '$lib/server/oauth-providers'; import { env } from '$env/dynamic/private';
export interface IOAuthClaims { export const authentik = new Authentik(
sub: string; env.AUTH_DOMAIN,
name: string; env.AUTH_CLIENT_ID,
username: string; env.AUTH_CLIENT_SECRET,
} `${env.ORIGIN}/auth/authentik/callback`,
);
export interface IOAuthProvider { export const google = new Google(
readonly requireInvite: boolean; env.GOOGLE_CLIENT_ID,
createAuthorizationURL(state: string, codeVerifier: string): URL; env.GOOGLE_CLIENT_SECRET,
validateAuthorizationCode(code: string, codeVerifier: string): Promise<IOAuthClaims>; `${env.ORIGIN}/auth/google/callback`,
} );
export const oauthProviders: Record<AuthProvider, IOAuthProvider> = {
authentik,
google,
};

View File

@@ -0,0 +1,49 @@
import { env } from '$env/dynamic/private';
import assert from 'node:assert';
import { encodeBasicCredentials } from 'arctic/dist/request';
import { dev } from '$app/environment';
import type { OpnsenseWgServers } from '$lib/opnsense/wg';
export const opnsenseUrl = env.OPNSENSE_API_URL;
export const opnsenseAuth =
'Basic ' + encodeBasicCredentials(env.OPNSENSE_API_KEY, env.OPNSENSE_API_SECRET);
export const opnsenseIfname = env.OPNSENSE_WG_IFNAME;
// unset secret for security
if (!dev) env.OPNSENSE_API_SECRET = '';
export let serverUuid: string, serverPublicKey: string;
export async function fetchOpnsenseServer() {
// this might be pretty bad if the server is down and in a bunch of other cases
// TODO: write a retry loop later
const resServers = await fetch(`${opnsenseUrl}/api/wireguard/client/list_servers`, {
method: 'GET',
headers: {
Authorization: opnsenseAuth,
Accept: 'application/json',
},
});
assert(resServers.ok, 'Failed to fetch OPNsense WireGuard servers');
const servers = (await resServers.json()) as OpnsenseWgServers;
assert.equal(servers.status, 'ok', 'Failed to fetch OPNsense WireGuard servers');
const uuid = servers.rows.find((server) => server.name === opnsenseIfname)?.uuid;
assert(uuid, 'Failed to find server UUID for OPNsense WireGuard server');
serverUuid = uuid;
console.log('OPNsense WireGuard server UUID:', serverUuid);
const resServerInfo = await fetch(
`${opnsenseUrl}/api/wireguard/client/get_server_info/${serverUuid}`,
{
method: 'GET',
headers: {
Authorization: opnsenseAuth,
Accept: 'application/json',
},
},
);
assert(resServerInfo.ok, 'Failed to fetch OPNsense WireGuard server info');
const serverInfo = await resServerInfo.json();
assert.equal(serverInfo.status, 'ok', 'Failed to fetch OPNsense WireGuard server info');
serverPublicKey = serverInfo['pubkey'];
}

View File

@@ -1,26 +1,24 @@
import type { ClientConnection, CreateClientParams, IWgProvider, WgKeys } from '$lib/server/types'; import type { IWgProvider } from '$lib/server/types';
import { encodeBasicCredentials } from 'arctic/dist/request'; import { encodeBasicCredentials } from 'arctic/dist/request';
import { is } from 'typia'; import { is } from 'typia';
import type { OpnsenseWgPeers, OpnsenseWgServers } from '$lib/server/wg-providers/opnsense/types'; import type { OpnsenseWgPeers, OpnsenseWgServers } from '$lib/opnsense/wg';
import { err, ok, type Result } from '$lib/types'; import { err, ok } from '$lib/types';
import { opnsenseSanitezedUsername } from '$lib/opnsense';
import assert from 'node:assert'; import assert from 'node:assert';
import type { User } from '$lib/server/db/schema';
export class WgProviderOpnsense implements IWgProvider { export class WgProviderOpnsense implements IWgProvider {
private opnsenseUrl: string; private opnsenseUrl: string;
private opnsenseAuth: string; private opnsenseAuth: string;
private opnsenseIfname: string; private opnsenseIfname: string;
private opnsenseWgServerUuid: string | undefined; private opnsenseWgServerUuid: string | undefined;
private opnsenseWgServerPublicKey: string | undefined;
public constructor(params: OpnsenseParams) { public constructor(params: OpnsenseParams) {
this.opnsenseUrl = params.opnsenseUrl; this.opnsenseUrl = params.opnsenseUrl;
this.opnsenseAuth = this.opnsenseAuth = 'Basic ' + encodeBasicCredentials(params.opnsenseApiKey, params.opnsenseApiSecret);
'Basic ' + encodeBasicCredentials(params.opnsenseApiKey, params.opnsenseApiSecret);
this.opnsenseIfname = params.opnsenseWgIfname; this.opnsenseIfname = params.opnsenseWgIfname;
} }
public async init(): Promise<Result<null, Error>> { public async init() {
const resServers = await fetch(`${this.opnsenseUrl}/api/wireguard/client/list_servers`, { const resServers = await fetch(`${this.opnsenseUrl}/api/wireguard/client/list_servers`, {
method: 'GET', method: 'GET',
headers: { headers: {
@@ -41,39 +39,12 @@ export class WgProviderOpnsense implements IWgProvider {
return err(new Error('Failed to find server UUID for OPNsense WireGuard server')); return err(new Error('Failed to find server UUID for OPNsense WireGuard server'));
} }
const resServerInfo = await fetch(
`${this.opnsenseUrl}/api/wireguard/client/get_server_info/${uuid}`,
{
method: 'GET',
headers: {
Authorization: this.opnsenseAuth,
Accept: 'application/json',
},
},
);
const serverInfo = await resServerInfo.json();
const serverPublicKey = serverInfo['pubkey'];
if (serverInfo['status'] !== 'ok' || typeof serverPublicKey !== 'string') {
console.error('Failed to fetch OPNsense WireGuard server info', serverInfo);
return err(new Error('Failed to fetch OPNsense WireGuard server info'));
}
console.debug('OPNsense WireGuard server UUID:', uuid); console.debug('OPNsense WireGuard server UUID:', uuid);
console.debug('OPNsense WireGuard server public key:', serverPublicKey);
this.opnsenseWgServerUuid = uuid; this.opnsenseWgServerUuid = uuid;
this.opnsenseWgServerPublicKey = serverPublicKey;
return ok(null); return ok(null);
} }
getServerPublicKey(): string { public async generateKeys() {
assert(
this.opnsenseWgServerPublicKey,
'OPNsense server public key not set, init() must be called first',
);
return this.opnsenseWgServerPublicKey;
}
public async generateKeys(): Promise<Result<WgKeys, Error>> {
const options: RequestInit = { const options: RequestInit = {
method: 'GET', method: 'GET',
headers: { headers: {
@@ -102,31 +73,28 @@ export class WgProviderOpnsense implements IWgProvider {
}); });
} }
async createClient(params: CreateClientParams): Promise<Result<null, Error>> { async createClient(params) {
assert(this.opnsenseWgServerUuid, 'OPNsense server UUID not set, init() must be called first'); assert(this.opnsenseWgServerUuid, 'OPNsense server UUID not set, init() must be called first');
const createClientRes = await fetch( const createClientRes = await fetch(`${this.opnsenseUrl}/api/wireguard/client/addClientBuilder`, {
`${this.opnsenseUrl}/api/wireguard/client/addClientBuilder`, method: 'POST',
{ headers: {
method: 'POST', Authorization: this.opnsenseAuth,
headers: { Accept: 'application/json',
Authorization: this.opnsenseAuth, 'Content-Type': 'application/json',
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
configbuilder: {
enabled: '1',
name: `vpgen-${opnsenseSanitezedUsername(params.user.username)}`,
pubkey: params.publicKey,
psk: params.preSharedKey,
tunneladdress: params.allowedIps,
server: this.opnsenseWgServerUuid,
endpoint: '',
},
}),
}, },
); body: JSON.stringify({
configbuilder: {
enabled: '1',
name: `vpgen-${opnsenseSanitezedUsername(params.user.username)}`,
pubkey: params.publicKey,
psk: params.preSharedKey,
tunneladdress: params.allowedIps,
server: this.opnsenseWgServerUuid,
endpoint: '',
},
}),
});
const createClientResJson = await createClientRes.json(); const createClientResJson = await createClientRes.json();
if (createClientResJson['result'] !== 'saved') { if (createClientResJson['result'] !== 'saved') {
console.error('Error creating client in OPNsense', createClientResJson); console.error('Error creating client in OPNsense', createClientResJson);
@@ -149,7 +117,7 @@ export class WgProviderOpnsense implements IWgProvider {
return ok(null); return ok(null);
} }
async findConnections(user: User): Promise<Result<ClientConnection[], Error>> { async findConnections(user) {
const res = await fetch(`${this.opnsenseUrl}/api/wireguard/service/show`, { const res = await fetch(`${this.opnsenseUrl}/api/wireguard/service/show`, {
method: 'POST', method: 'POST',
headers: { headers: {
@@ -175,65 +143,21 @@ export class WgProviderOpnsense implements IWgProvider {
return err(new Error('Failed to fetch OPNsense WireGuard peers')); return err(new Error('Failed to fetch OPNsense WireGuard peers'));
} }
return ok( return ok(peers.rows.map((peer) => {
peers.rows.map((peer) => { return {
return { publicKey: peer['public-key'],
publicKey: peer['public-key'], endpoint: peer['endpoint'],
endpoint: peer['endpoint'], allowedIps: peer['allowed-ips'],
allowedIps: peer['allowed-ips'], transferRx: peer['transfer-tx'],
transferRx: peer['transfer-rx'], transferTx: peer['transfer-rx'],
transferTx: peer['transfer-tx'], latestHandshake: peer['latest-handshake'] * 1000,
latestHandshake: peer['latest-handshake'] * 1000, };
}; }))
}),
);
} }
async deleteClient(publicKey: string): Promise<Result<null, Error>> { async deleteClient(publicKey) {
const client = await this.findOpnsenseClient(publicKey); return err(new Error('OPNsense deleteClient not implemented'));
const clientUuid = client?.uuid;
if (typeof clientUuid !== 'string') {
console.error('Failed to get OPNsense client UUID for deletion', client);
return err(new Error('Failed to get OPNsense client UUID for deletion'));
}
const res = await fetch(`${this.opnsenseUrl}/api/wireguard/client/delClient/${clientUuid}`, {
method: 'POST',
headers: {
Authorization: this.opnsenseAuth,
Accept: 'application/json',
},
});
const resJson = await res.json();
if (resJson['result'] !== 'deleted') {
console.error('Failed to delete OPNsense client', resJson);
return err(new Error('Failed to delete OPNsense client'));
}
return ok(null);
} }
private async findOpnsenseClient(publicKey: string) {
const res = await fetch(`${this.opnsenseUrl}/api/wireguard/client/searchClient`, {
method: 'POST',
headers: {
Authorization: this.opnsenseAuth,
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
current: 1,
sort: {},
searchPhrase: publicKey,
type: ['peer'],
}),
});
return (await res.json())?.rows?.[0] ?? null;
}
}
function opnsenseSanitezedUsername(username: string) {
return username.slice(0, 63).replace(/[^a-zA-Z0-9_-]/g, '_');
} }
export type OpnsenseParams = { export type OpnsenseParams = {

View File

@@ -1,14 +1,22 @@
import type { Result } from '$lib/types'; import type { Result } from '$lib/types';
import type { User } from '$lib/server/db/schema'; import type { User } from '$lib/server/db/schema';
import type { ConnectionDetails } from '$lib/connections';
export interface IWgProvider { export interface IWgProvider {
init(): Promise<Result<null, Error>>; init(): Promise<Result<null, Error>>;
getServerPublicKey(): string; // TODO: might be better to not make this a result type
getServerPublicKey(): Promise<Result<string, Error>>;
// TODO: might be better to not make this a result type
generateKeys(): Promise<Result<WgKeys, Error>>; generateKeys(): Promise<Result<WgKeys, Error>>;
createClient(params: CreateClientParams): Promise<Result<null, Error>>; createClient(params: {
user: User;
publicKey: string;
preSharedKey: string;
allowedIps: string;
}): Promise<Result<null, Error>>;
findConnections(user: User): Promise<Result<ClientConnection[], Error>>; findConnections(user: User): Promise<Result<ClientConnection[], Error>>;
@@ -21,13 +29,6 @@ export type WgKeys = {
preSharedKey: string; preSharedKey: string;
}; };
export type CreateClientParams = {
user: User;
publicKey: string;
preSharedKey: string;
allowedIps: string;
}
export type ClientConnection = { export type ClientConnection = {
publicKey: string; publicKey: string;
endpoint: string; endpoint: string;

View File

@@ -1,12 +0,0 @@
import { WgProviderOpnsense } from '$lib/server/wg-providers/opnsense';
import { env } from '$env/dynamic/private';
import type { IWgProvider } from '$lib/server/types';
const wgProvider: IWgProvider = new WgProviderOpnsense({
opnsenseUrl: env.OPNSENSE_API_URL,
opnsenseApiKey: env.OPNSENSE_API_KEY,
opnsenseApiSecret: env.OPNSENSE_API_SECRET,
opnsenseWgIfname: env.OPNSENSE_WG_IFNAME,
});
export default wgProvider;

View File

@@ -1,2 +1,17 @@
import type { Address4, Address6 } from 'ip-address';
export type { Result } from './result'; export type { Result } from './result';
export { ok, err } from './result'; export { ok, err } from './result';
export interface IWGProviderConfig {
ipv4?: {
startingAddr: Address4;
};
ipv6?: {
startingAddr: Address6;
clientPrefixSize: number;
}
endpoint: string;
dns: string;
addrMaxIndex: number;
}

View File

@@ -4,11 +4,3 @@ import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) { export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs)); return twMerge(clsx(inputs));
} }
export function envToBool(value: string | undefined, defaultValue = false): boolean {
if (typeof value === "undefined") {
return defaultValue;
}
return ['true', '1', 'yes'].includes(value.toLowerCase());
}

View File

@@ -4,7 +4,6 @@ import { findDevices } from '$lib/server/devices';
import type { ConnectionDetails } from '$lib/connections'; import type { ConnectionDetails } from '$lib/connections';
import type { Result } from '$lib/types'; import type { Result } from '$lib/types';
import type { ClientConnection } from '$lib/server/types'; import type { ClientConnection } from '$lib/server/types';
import wgProvider from '$lib/server/wg-provider';
export const GET: RequestHandler = async (event) => { export const GET: RequestHandler = async (event) => {
if (!event.locals.user) { if (!event.locals.user) {
@@ -12,7 +11,7 @@ export const GET: RequestHandler = async (event) => {
} }
console.debug('/api/connections'); console.debug('/api/connections');
const peersResult: Result<ClientConnection[], Error> = await wgProvider.findConnections(event.locals.user); const peersResult: Result<ClientConnection[], Error> = await event.locals.wgProvider.findConnections(event.locals.user);
if (peersResult._tag === 'err') return error(500, peersResult.error.message); if (peersResult._tag === 'err') return error(500, peersResult.error.message);
const devices = await findDevices(event.locals.user.id); const devices = await findDevices(event.locals.user.id);

View File

@@ -1,14 +1,14 @@
import { fail, redirect } from '@sveltejs/kit'; import { fail, redirect } from "@sveltejs/kit";
import { invalidateSession, deleteSessionTokenCookie } from '$lib/server/auth'; import { invalidateSession, deleteSessionTokenCookie } from "$lib/server/auth";
import type { Actions } from './$types'; import type { Actions } from "./$types";
export const actions: Actions = { export const actions: Actions = {
logout: async ({ locals, cookies }) => { logout: async (event) => {
if (locals.session === null) { if (event.locals.session === null) {
return fail(401); return fail(401);
} }
await invalidateSession(locals.session.id); await invalidateSession(event.locals.session.id);
deleteSessionTokenCookie(cookies); deleteSessionTokenCookie(event);
redirect(302, '/'); return redirect(302, "/");
}, }
}; };

View File

@@ -1,36 +0,0 @@
import { generateCodeVerifier, generateState } from 'arctic';
import { oauthProviders } from '$lib/server/oauth';
import { is } from 'typia';
import { type AuthProvider, enabledAuthProviders } from '$lib/auth';
export async function GET({ params: { provider }, url, cookies }) {
if (!is<AuthProvider>(provider) || !enabledAuthProviders[provider]) {
return new Response(null, { status: 404 });
}
const oauthProvider = oauthProviders[provider];
const inviteToken = url.searchParams.get('invite') ?? '';
const state = generateState();
const codeVerifier = generateCodeVerifier();
const authUrl = oauthProvider.createAuthorizationURL(state + inviteToken, codeVerifier);
cookies.set(`${provider}_oauth_state`, state, {
path: '/',
httpOnly: true,
maxAge: 60 * 10, // 10 minutes
sameSite: 'lax',
});
cookies.set(`${provider}_code_verifier`, codeVerifier, {
path: '/',
httpOnly: true,
maxAge: 60 * 10, // 10 minutes
sameSite: 'lax',
});
return new Response(null, {
status: 302,
headers: {
Location: authUrl.toString(),
},
});
}

View File

@@ -1,76 +0,0 @@
import { is } from 'typia';
import type { PageServerLoad } from './$types';
import { error, redirect } from '@sveltejs/kit';
import { type AuthProvider, enabledAuthProviders } from '$lib/auth';
import { oauthProviders } from '$lib/server/oauth';
import { ArcticFetchError, OAuth2RequestError } from 'arctic';
import { db } from '$lib/server/db';
import * as table from '$lib/server/db/schema';
import { eq } from 'drizzle-orm';
import { createSession, isValidInviteToken, setSessionTokenCookie } from '$lib/server/auth';
export const load: PageServerLoad = async ({ params: { provider }, url, cookies }) => {
if (!is<AuthProvider>(provider) || !enabledAuthProviders[provider]) {
error(404);
}
const oauthProvider = oauthProviders[provider];
const code = url.searchParams.get('code');
const state = url.searchParams.get('state');
const storedState = cookies.get(`${provider}_oauth_state`) ?? null;
const codeVerifier = cookies.get(`${provider}_code_verifier`) ?? null;
if (code === null || state === null || storedState === null || codeVerifier === null) {
error(400, 'Missing url parameters');
}
const stateGeneratedToken = state.slice(0, storedState.length);
const stateInviteToken = state.slice(storedState.length);
if (stateGeneratedToken !== storedState) {
error(400, 'Invalid state in url');
}
let claims;
try {
claims = await oauthProvider.validateAuthorizationCode(code, codeVerifier);
} catch (e) {
if (e instanceof OAuth2RequestError) {
console.debug('Arctic: OAuth: invalid authorization code, credentials, or redirect URI', e);
error(400, 'Invalid authorization code');
}
if (e instanceof ArcticFetchError) {
console.debug('Arctic: failed to call `fetch()`', e);
error(400, 'Failed to validate authorization code');
}
console.error('Unexpected error validating authorization code', code, e);
error(500);
}
const existingUser = await db.query.users.findFirst({ where: eq(table.users.id, claims.sub) });
if (existingUser) {
const session = await createSession(existingUser.id);
setSessionTokenCookie(cookies, session.id, session.expiresAt);
redirect(302, '/');
}
if (oauthProvider.requireInvite && !isValidInviteToken(stateInviteToken)) {
const message =
stateInviteToken.length === 0 ? 'sign up with an invite link first' : 'invalid invite link';
error(403, 'Not Authorized: ' + message);
}
const user: table.User = {
id: claims.sub,
authSource: provider,
username: claims.username,
name: claims.name,
};
await db.insert(table.users).values(user);
console.log('created user', user, 'using provider', provider, 'with invite token', stateInviteToken);
const session = await createSession(user.id);
setSessionTokenCookie(cookies, session.id, session.expiresAt);
redirect(302, '/');
};

View File

@@ -0,0 +1,30 @@
import { generateState, generateCodeVerifier } from "arctic";
import { authentik } from "$lib/server/oauth";
import type { RequestEvent } from "@sveltejs/kit";
export async function GET(event: RequestEvent): Promise<Response> {
const state = generateState();
const codeVerifier = generateCodeVerifier();
const url = authentik.createAuthorizationURL(state, codeVerifier, ["openid", "profile"]);
event.cookies.set("authentik_oauth_state", state, {
path: "/",
httpOnly: true,
maxAge: 60 * 10, // 10 minutes
sameSite: "lax"
});
event.cookies.set("authentik_code_verifier", codeVerifier, {
path: "/",
httpOnly: true,
maxAge: 60 * 10, // 10 minutes
sameSite: "lax"
});
return new Response(null, {
status: 302,
headers: {
Location: url.toString()
}
});
}

View File

@@ -0,0 +1,84 @@
import { createSession, setSessionTokenCookie } from '$lib/server/auth';
import { authentik } from '$lib/server/oauth';
import { decodeIdToken } from 'arctic';
import type { RequestEvent } from '@sveltejs/kit';
import type { OAuth2Tokens } from 'arctic';
import { db } from '$lib/server/db';
import { eq } from 'drizzle-orm';
import * as table from '$lib/server/db/schema';
export async function GET(event: RequestEvent): Promise<Response> {
const code = event.url.searchParams.get('code');
const state = event.url.searchParams.get('state');
const storedState = event.cookies.get('authentik_oauth_state') ?? null;
const codeVerifier = event.cookies.get('authentik_code_verifier') ?? null;
if (code === null || state === null || storedState === null || codeVerifier === null) {
return new Response(null, {
status: 400,
});
}
if (state !== storedState) {
return new Response(null, {
status: 400,
});
}
let tokens: OAuth2Tokens;
try {
tokens = await authentik.validateAuthorizationCode(code, codeVerifier);
} catch (e) {
// Invalid code or client credentials
return new Response(null, {
status: 400,
});
}
const claims = decodeIdToken(tokens.idToken()) as {
sub: string;
preferred_username: string;
name: string;
};
console.log('claims', claims);
const userId: string = claims.sub;
const username: string = claims.preferred_username;
const existingUser = await db.query.users.findFirst({ where: eq(table.users.id, userId) });
if (existingUser) {
const session = await createSession(existingUser.id);
setSessionTokenCookie(event, session.id, session.expiresAt);
return new Response(null, {
status: 302,
headers: {
Location: '/',
},
});
}
const user: table.User = {
id: userId,
authSource: 'authentik',
username,
name: claims.name as string,
};
try {
await db.insert(table.users).values(user);
const session = await createSession(user.id);
setSessionTokenCookie(event, session.id, session.expiresAt);
} catch (e) {
console.error('failed to create user', e);
return new Response(null, {
status: 500,
});
}
return new Response(null, {
status: 302,
headers: {
Location: '/',
},
});
}

View File

@@ -0,0 +1,38 @@
import type { RequestHandler } from './$types';
import { generateCodeVerifier, generateState } from 'arctic';
import { google } from '$lib/server/oauth';
export const GET: RequestHandler = ({ url, cookies }) => {
const inviteToken = url.searchParams.get('invite');
const state = generateState();
const codeVerifier = generateCodeVerifier();
const scopes = ['openid', 'profile', 'email'];
const authUrl = google.createAuthorizationURL(state, codeVerifier, scopes);
cookies.set('google_oauth_state', state, {
path: '/',
httpOnly: true,
maxAge: 60 * 10, // 10 minutes
sameSite: 'lax',
});
cookies.set('google_code_verifier', codeVerifier, {
path: '/',
httpOnly: true,
maxAge: 60 * 10, // 10 minutes
sameSite: 'lax',
});
if (inviteToken !== null) cookies.set('invite_token', inviteToken, {
path: '/',
httpOnly: true,
maxAge: 60 * 10, // 10 minutes
sameSite: 'lax',
});
return new Response(null, {
status: 302,
headers: {
Location: authUrl.toString(),
},
});
};

View File

@@ -0,0 +1,100 @@
import type { RequestHandler } from './$types';
import * as arctic from 'arctic';
import { google } from '$lib/server/oauth';
import { db } from '$lib/server/db';
import { eq } from 'drizzle-orm';
import * as table from '$lib/server/db/schema';
import { createSession, isValidInviteToken, setSessionTokenCookie } from '$lib/server/auth';
import type { OAuth2Tokens } from 'arctic';
import { assertGuard } from 'typia';
export const GET: RequestHandler = async (event) => {
const { url, cookies } = event;
const code = url.searchParams.get('code');
const state = url.searchParams.get('state');
const storedState = cookies.get('google_oauth_state') ?? null;
const codeVerifier = cookies.get('google_code_verifier', ) ?? null;
const inviteToken = cookies.get('invite_token') ?? null;
if (code === null || state === null || storedState === null || codeVerifier === null) {
return new Response(null, {
status: 400,
});
}
let tokens: OAuth2Tokens;
try {
tokens = await google.validateAuthorizationCode(code, codeVerifier);
} catch (e) {
if (e instanceof arctic.OAuth2RequestError) {
console.debug('Arctic: OAuth: invalid authorization code, credentials, or redirect URI', e);
return new Response(null, {
status: 400,
});
}
if (e instanceof arctic.ArcticFetchError) {
console.debug('Arctic: failed to call `fetch()`', e);
return new Response(null, {
status: 400,
});
}
return new Response(null, {
status: 500,
});
}
const idToken = tokens.idToken();
const claims = arctic.decodeIdToken(idToken);
console.log('claims', claims);
assertGuard<{
sub: string;
email: string;
name: string;
}>(claims);
const userId = claims.sub;
const existingUser = await db.query.users.findFirst({ where: eq(table.users.id, userId) });
if (existingUser) {
const session = await createSession(existingUser.id);
setSessionTokenCookie(event, session.id, session.expiresAt);
return new Response(null, {
status: 302,
headers: {
Location: '/',
},
});
}
// TODO: proper error page
if (inviteToken === null || !isValidInviteToken(inviteToken)) {
return new Response(null, {
status: 400,
});
}
const user: table.User = {
id: userId,
authSource: 'google',
username: claims.email,
name: claims.name,
};
// TODO: proper error handling, delete cookies
await db.insert(table.users).values(user);
console.log('created user', user, 'with invite token', inviteToken);
const session = await createSession(user.id);
setSessionTokenCookie(event, session.id, session.expiresAt);
return new Response(null, {
status: 302,
headers: {
Location: '/',
},
});
};

View File

@@ -1,7 +1,6 @@
import type { Actions } from './$types'; import type { Actions } from './$types';
import { createDevice } from '$lib/server/devices'; import { createDevice } from '$lib/server/devices';
import { error, fail, redirect } from '@sveltejs/kit'; import { error, fail, redirect } from '@sveltejs/kit';
import wgProvider from '$lib/server/wg-provider';
export const actions = { export const actions = {
create: async (event) => { create: async (event) => {
@@ -9,7 +8,7 @@ export const actions = {
const formData = await event.request.formData(); const formData = await event.request.formData();
const name = formData.get('name'); const name = formData.get('name');
if (typeof name !== 'string' || name.trim() === '') return fail(400, { name, invalid: true }); if (typeof name !== 'string' || name.trim() === '') return fail(400, { name, invalid: true });
const res = await createDevice({ const res = await createDevice(event.locals.wgProvider, {
name: name.trim(), name: name.trim(),
user: event.locals.user, user: event.locals.user,
}); });

View File

@@ -4,7 +4,7 @@
import { Badge } from '$lib/components/ui/badge'; import { Badge } from '$lib/components/ui/badge';
import { Button, buttonVariants } from '$lib/components/ui/button'; import { Button, buttonVariants } from '$lib/components/ui/button';
import { Input } from '$lib/components/ui/input'; import { Input } from '$lib/components/ui/input';
import { LucideLoaderCircle, LucidePlus } from '@lucide/svelte'; import { LucideLoaderCircle, LucidePlus } from 'lucide-svelte';
import type { PageData } from './$types'; import type { PageData } from './$types';
import { Label } from '$lib/components/ui/label'; import { Label } from '$lib/components/ui/label';
import { page } from '$app/state'; import { page } from '$app/state';

View File

@@ -1,7 +1,7 @@
<script> <script>
import { Button, buttonVariants } from '$lib/components/ui/button'; import { Button, buttonVariants } from '$lib/components/ui/button';
import * as Dialog from '$lib/components/ui/dialog'; import * as Dialog from '$lib/components/ui/dialog';
import { LucideLoaderCircle, LucideTrash } from '@lucide/svelte'; import { LucideLoaderCircle, LucideTrash } from 'lucide-svelte';
const { device } = $props(); const { device } = $props();
let submitted = $state(false); let submitted = $state(false);
@@ -26,12 +26,10 @@
<Button type="submit" variant="destructive" disabled={submitted}> <Button type="submit" variant="destructive" disabled={submitted}>
Delete Delete
</Button> </Button>
<Dialog.Close> <Dialog.Close asChild let:builder>
{#snippet child({ props })} <button class={buttonVariants()} disabled={submitted} use:builder.action {...builder}>
<Button {...props} disabled={submitted}> Cancel
Cancel </button>
</Button>
{/snippet}
</Dialog.Close> </Dialog.Close>
</Dialog.Footer> </Dialog.Footer>
</form> </form>

View File

@@ -1,7 +1,7 @@
<script lang="ts"> <script lang="ts">
import { invalidate, invalidateAll } from '$app/navigation'; import { invalidate, invalidateAll } from '$app/navigation';
import { Button } from '$lib/components/ui/button'; import { Button } from '$lib/components/ui/button';
import { LucideLoaderCircle, LucideLogOut, LucideRefreshCw } from '@lucide/svelte'; import { LucideLoaderCircle, LucideLogOut, LucideRefreshCw } from 'lucide-svelte';
import { CodeSnippet } from '$lib/components/app/code-snippet/index.js'; import { CodeSnippet } from '$lib/components/app/code-snippet/index.js';
let { data } = $props(); let { data } = $props();