Compare commits

..

33 commits

Author SHA1 Message Date
routerino
a7f79824bf
Update install-openvscode-server.sh 2025-08-30 11:25:52 +10:00
routerino
3c22ed935d
Update version before release 2025-08-23 11:00:38 +10:00
routerino
c48c0a54fb
210 feature request show user names not just usernames (#211)
* fix: display email if username is too short

* feat: added email field to expanded cards
2025-08-23 10:59:46 +10:00
routerino
fbb8b2b968
test before release 2025-07-12 10:02:00 +10:00
routerino
baffa0024c
fix undocumented headscale ui change (#207) 2025-07-12 10:01:05 +10:00
Eloxt Wang
15c4dd9575
Add route removal functionality and fix code formatting (#206)
- Add removeRouteAction function to allow disabling active routes
- Update approveDeviceRoute to accept full routes array instead of single route
2025-07-11 09:00:47 +10:00
routerino
7dd92ab4ad
Fix: CICD Pipeline for release plugin (#201)
* testing-github-piprline

* fix pipeline

* bump version
2025-05-24 12:57:50 +10:00
Chris Bisset
5e97c52303 update readme 2025-05-22 07:38:40 +00:00
Chris Bisset
9516a519b8 update version before publish 2025-05-22 04:24:21 +00:00
Chris Bisset
625647ed19 fix duplicate tags 2025-05-22 04:23:57 +00:00
Chris Bisset
907ab6af57 remove old route class 2025-05-22 04:13:58 +00:00
Chris Bisset
adef58f27d fix device route for new API 2025-05-22 04:07:22 +00:00
Chris Bisset
38e0de2696 fix api calls for preauth keys 2025-05-20 00:20:22 +00:00
Chris Bisset
84aec5f45a update package version for release 2025-03-20 23:12:41 +00:00
DmitryBoiadji
b9cc07d9de
fixing unknown command headscale (#191)
got an error running docker compose:


[+] Running 2/2
 ⠿ Container headscale-ui  Created                                                                                                   0.0s
 ⠿ Container headscale     Recreated                                                                                                 0.8s
Attaching to headscale, headscale-ui
headscale     | Error: unknown command "headscale" for "headscale"
headscale     | Run 'headscale --help' for usage.
headscale     | unknown command "headscale" for "headscale"
headscale-ui  | Starting Caddy

fixed by removing unnecessary headscale prefix before serve command
2025-03-21 10:09:29 +11:00
routerino
2508507644
remove min length from api and device fields (#198) 2025-03-21 10:09:00 +11:00
routerino
cf682bddbb
fix folder creation 2025-03-15 13:18:55 +11:00
routerino
f3c4a6afbf
fix dev build 2025-03-15 13:01:29 +11:00
routerino
722eaa64ed
fix user permissions on dev image 2025-03-15 12:54:29 +11:00
Chris Bisset
f5df8899ee move development image to debian 2025-03-15 01:41:46 +00:00
routerino
7bb7d1f7cb
Update install-openvscode-server.sh (#195) 2025-03-15 12:15:05 +11:00
routerino
d7a7136897
fix connection token env 2025-03-15 12:13:36 +11:00
Chris Bisset
4bc00fbbfc update readme 2025-03-13 22:23:28 +00:00
Chris Bisset
3bf4bfa2ea update version before release 2025-03-13 22:22:17 +00:00
Chris Bisset
2631785f9f fix api for reassigning user 2025-03-13 22:21:18 +00:00
Guillaume Chx
216a49ec52
fix: headscale 25 uses user's "name" instead of "id" to get/create/expire pre-auth keys (#192) 2025-03-14 09:09:56 +11:00
Chris Bisset
21075b994a update dependencies before release 2025-01-20 10:12:42 +11:00
routerino
25ac133d86
Revert "Update lock file and remove conflicting dependency (#186)" (#188)
This reverts commit b8042250ad.
2025-01-20 09:49:58 +11:00
rohanharikr
b8042250ad
Update lock file and remove conflicting dependency (#186)
* remove conflicting dep

* update lock
2025-01-20 09:12:10 +11:00
Poupapaa
3e5651189e
Make headscale-ui compatible with headscale v0.24 - *BREAKING* (#185) 2025-01-18 10:02:20 +11:00
Vlad Stefan
7a1725daa6
Update configuration.md (#176)
The latest major release of headscale ui change the default container ports from 80 and 443 to 8080 and 8443. Updated the traefik port to reflect changes.
2024-11-09 18:44:36 +11:00
routerino
0c56afac23
Update README.md for latest release warning (#173) 2024-10-22 09:26:45 +11:00
routerino
a387c3fc62
Update README.md for docker compose (#171) 2024-10-16 08:09:00 +11:00
25 changed files with 440 additions and 503 deletions

View file

@ -10,7 +10,7 @@ jobs:
steps:
- name: Checkout Repository
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Variable Gathering
id: gathervars
@ -33,13 +33,13 @@ jobs:
echo "NOT_PREVIOUSLY_PUBLISHED=$NOT_PREVIOUSLY_PUBLISHED" >> $GITHUB_ENV
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
uses: docker/setup-buildx-action@v3
- name: Log in to the Container registry
uses: docker/login-action@v2
uses: docker/login-action@v3
if: ${{ env.NOT_PREVIOUSLY_PUBLISHED != 0 }}
with:
registry: ghcr.io
@ -47,7 +47,7 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push Docker Image
uses: docker/build-push-action@v4
uses: docker/build-push-action@v6
if: ${{ env.NOT_PREVIOUSLY_PUBLISHED != 0 }}
with:
build-args: |
@ -60,7 +60,7 @@ jobs:
push: true
- name: Extract build out of docker image
uses: shrink/actions-docker-extract@v2
uses: shrink/actions-docker-extract@v3
if: ${{ env.NOT_PREVIOUSLY_PUBLISHED != 0 }}
id: extract
with:
@ -73,33 +73,14 @@ jobs:
cd "${{ steps.extract.outputs.destination }}"
7z a headscale-ui.zip web
- name: Create Draft Release
id: create_release
uses: actions/create-release@v1
- name: Create Release
uses: softprops/action-gh-release@v2
if: ${{ env.NOT_PREVIOUSLY_PUBLISHED != 0 }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ env.VERSION }}
release_name: headscale-ui
draft: true
prerelease: false
- name: upload asset to releases
uses: actions/upload-release-asset@v1.0.1
if: ${{ env.NOT_PREVIOUSLY_PUBLISHED != 0 }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ${{ steps.extract.outputs.destination }}/headscale-ui.zip
asset_name: headscale-ui.zip
asset_content_type: application/zip
- name: publish release
uses: eregon/publish-release@v1
if: ${{ env.NOT_PREVIOUSLY_PUBLISHED != 0 }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
release_id: ${{ steps.create_release.outputs.id }}
name: headscale-ui
files: ${{ steps.extract.outputs.destination }}/headscale-ui.zip
generate_release_notes: true
make_latest: true

View file

@ -4,6 +4,9 @@ A web frontend for the [headscale](https://github.com/juanfont/headscale) Tailsc
![](documentation/assets/headscale-ui-demo.gif)
## Installation
> [!WARNING]
> The latest major release of headscale ui change the default container ports from `80` and `443` to `8080` and `8443` respectively. If you are using the `HTTP_PORT` or `HTTPS_PORT` environment variables this does not affect you, otherwise you need to change your ports in your docker-compose or kubernetes manifests.
Headscale-UI is currently released as a static site: just take the release and host with your favorite web server. Headscale-UI expects to be served from the `/web` path to avoid overlap with headscale on the same domain. Note that due to CORS (see https://github.com/juanfont/headscale/issues/623), headscale UI *must* be served on the same subdomain, or CORS headers injected via reverse proxy.
### Docker Installation
@ -20,7 +23,7 @@ services:
- ./container-data/data:/var/lib/headscale
# ports:
# - 27896:8080
command: headscale serve
command: serve
restart: unless-stopped
headscale-ui:
image: ghcr.io/gurucomputing/headscale-ui:latest
@ -88,6 +91,9 @@ See [Other Configurations](/documentation/configuration.md) for further proxy ex
The following versions correspond to the appropriate headscale version
| Headscale Version | HS-UI Version |
|-------------------|---------------|
| 26+ | 2025-05-22+ |
| 25+ | 2025-03-14+ |
| 24+ | 2025-01-20+ |
| 23+ | 2024-10-01+ |
| 19+ | 2023-01-30+ |
| <19 | <2023-01-30 |

View file

@ -1,4 +1,4 @@
FROM fedora:latest
FROM node:lts
# Volumes
VOLUME /data
@ -10,13 +10,12 @@ EXPOSE 3000
# System Environment Variables
ENV PATH="/opt/vscode:${PATH}"
ENV HOME="/data/home"
ENV SHELL="/bin/bash"
# User Set Environment Variables
# Set to false if you do not want to attempt to pull a repository on first load
ENV AUTOINITIALIZE=false
# sets a connection token for VSCode Server. https://github.com/gitpod-io/openvscode-server#securing-access-to-your-ide
ENV USE_CONNECTION_TOKEN=false
ENV USE_CONNECTION_TOKEN=true
#Set to a secret to have some measure of protection for vscode. Randomized if left blank
ENV CONNECTION_TOKEN=
# Project name. Typically the same as the project in the URL
@ -45,8 +44,8 @@ RUN chmod -R 755 scripts
RUN /staging/scripts/1-image-build.sh
# set to the non-root user
USER dev-user
USER 1000:1000
WORKDIR /data
ENTRYPOINT /bin/sh /staging/scripts/2-initialise.sh
ENTRYPOINT /bin/sh /staging/scripts/2-initialise.sh

View file

@ -4,17 +4,17 @@
# turn on bash logging, exit on error
set -ex
# create a non-root user
useradd -m -d /data/home dev-user
# # create a non-root user. Not needed for node image
# useradd -m -d /data/home dev-user
# set the default shell to the chosen shell
usermod --shell ${SHELL} dev-user
# set new home directory
mkdir -p /data/home
usermod -d /data/home node
# Add the ability to set file permissions on /data to the non-privileged user
echo "ALL ALL=NOPASSWD: /bin/chown -R 1000\:1000 /data" >> /etc/sudoers
# install dependencies
/staging/scripts/install-base-dependencies.sh
/staging/scripts/install-container-dependencies.sh
/staging/scripts/install-openvscode-server.sh

View file

@ -1,7 +0,0 @@
# install dependencies
# tmux used for monitoring secondary processes
# sudo for running specific commands as root
# git for source countrol
# pwgen for creating randomized passwords/secrets on the fly
# ncdu file navigation
dnf install -y tmux sudo git pwgen ncdu

View file

@ -1,2 +1,8 @@
# install container dependencies
dnf install -y nodejs caddy
# install dependencies
# tmux used for monitoring secondary processes
# sudo for running specific commands as root
# ncdu file navigation
# caddy web server
apt-get update
apt-get install -y --no-install-recommends tmux sudo git ncdu caddy
apt-get clean

View file

@ -1,5 +1,5 @@
# script variables
OPENVSCODE_VERSION="1.86.2"
OPENVSCODE_VERSION="1.103.1"
OPENVSCODE_URL="https://github.com/gitpod-io/openvscode-server/releases/download/openvscode-server-v$OPENVSCODE_VERSION/openvscode-server-v$OPENVSCODE_VERSION-linux-x64.tar.gz"
OPENVSCODE_RELEASE="openvscode-server-v$OPENVSCODE_VERSION-linux-x64"

View file

@ -13,7 +13,7 @@ services:
pull_policy: always
container_name: headscale
restart: unless-stopped
command: headscale serve
command: serve
volumes:
- ./headscale/config:/etc/headscale
- ./headscale/data:/var/lib/headscale
@ -30,7 +30,7 @@ services:
labels:
- traefik.enable=true
- traefik.http.routers.headscale-ui-rtr.rule=PathPrefix(`/web`) # you might want to add: && Host(`your.domain.name`)"
- traefik.http.services.headscale-ui-svc.loadbalancer.server.port=80
- traefik.http.services.headscale-ui-svc.loadbalancer.server.port=8080
traefik:
image: traefik:latest

521
package-lock.json generated
View file

@ -1,16 +1,17 @@
{
"name": "headscale-ui",
"version": "2024.10.05",
"version": "2025.07.12",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "headscale-ui",
"version": "2024.10.05",
"version": "2025.07.12",
"devDependencies": {
"@sveltejs/adapter-auto": "^3",
"@sveltejs/adapter-auto": "^4",
"@sveltejs/adapter-static": "^3",
"@sveltejs/kit": "^2",
"@sveltejs/vite-plugin-svelte": "^3",
"@tailwindcss/typography": "^0",
"@vitejs/plugin-basic-ssl": "^1",
"autoprefixer": "^10",
@ -487,9 +488,9 @@
}
},
"node_modules/@jridgewell/gen-mapping": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
"integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==",
"version": "0.3.8",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz",
"integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -596,9 +597,9 @@
"license": "MIT"
},
"node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.0.tgz",
"integrity": "sha512-Q6HJd7Y6xdB48x8ZNVDOqsbh2uByBhgK8PiQgPhwkIw/HC/YX5Ghq2mQY5sRMZWHb3VsFkWooUVOZHKr7DmDIA==",
"version": "4.31.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.31.0.tgz",
"integrity": "sha512-9NrR4033uCbUBRgvLcBrJofa2KY9DzxL2UKZ1/4xA/mnTNyhZCWBuD8X3tPm1n4KxcgaraOYgrFKSgwjASfmlA==",
"cpu": [
"arm"
],
@ -611,9 +612,9 @@
"peer": true
},
"node_modules/@rollup/rollup-android-arm64": {
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.24.0.tgz",
"integrity": "sha512-ijLnS1qFId8xhKjT81uBHuuJp2lU4x2yxa4ctFPtG+MqEE6+C5f/+X/bStmxapgmwLwiL3ih122xv8kVARNAZA==",
"version": "4.31.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.31.0.tgz",
"integrity": "sha512-iBbODqT86YBFHajxxF8ebj2hwKm1k8PTBQSojSt3d1FFt1gN+xf4CowE47iN0vOSdnd+5ierMHBbu/rHc7nq5g==",
"cpu": [
"arm64"
],
@ -626,9 +627,9 @@
"peer": true
},
"node_modules/@rollup/rollup-darwin-arm64": {
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.24.0.tgz",
"integrity": "sha512-bIv+X9xeSs1XCk6DVvkO+S/z8/2AMt/2lMqdQbMrmVpgFvXlmde9mLcbQpztXm1tajC3raFDqegsH18HQPMYtA==",
"version": "4.31.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.31.0.tgz",
"integrity": "sha512-WHIZfXgVBX30SWuTMhlHPXTyN20AXrLH4TEeH/D0Bolvx9PjgZnn4H677PlSGvU6MKNsjCQJYczkpvBbrBnG6g==",
"cpu": [
"arm64"
],
@ -641,9 +642,9 @@
"peer": true
},
"node_modules/@rollup/rollup-darwin-x64": {
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.24.0.tgz",
"integrity": "sha512-X6/nOwoFN7RT2svEQWUsW/5C/fYMBe4fnLK9DQk4SX4mgVBiTA9h64kjUYPvGQ0F/9xwJ5U5UfTbl6BEjaQdBQ==",
"version": "4.31.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.31.0.tgz",
"integrity": "sha512-hrWL7uQacTEF8gdrQAqcDy9xllQ0w0zuL1wk1HV8wKGSGbKPVjVUv/DEwT2+Asabf8Dh/As+IvfdU+H8hhzrQQ==",
"cpu": [
"x64"
],
@ -655,10 +656,40 @@
],
"peer": true
},
"node_modules/@rollup/rollup-freebsd-arm64": {
"version": "4.31.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.31.0.tgz",
"integrity": "sha512-S2oCsZ4hJviG1QjPY1h6sVJLBI6ekBeAEssYKad1soRFv3SocsQCzX6cwnk6fID6UQQACTjeIMB+hyYrFacRew==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"peer": true
},
"node_modules/@rollup/rollup-freebsd-x64": {
"version": "4.31.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.31.0.tgz",
"integrity": "sha512-pCANqpynRS4Jirn4IKZH4tnm2+2CqCNLKD7gAdEjzdLGbH1iO0zouHz4mxqg0uEMpO030ejJ0aA6e1PJo2xrPA==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"peer": true
},
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.24.0.tgz",
"integrity": "sha512-0KXvIJQMOImLCVCz9uvvdPgfyWo93aHHp8ui3FrtOP57svqrF/roSSR5pjqL2hcMp0ljeGlU4q9o/rQaAQ3AYA==",
"version": "4.31.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.31.0.tgz",
"integrity": "sha512-0O8ViX+QcBd3ZmGlcFTnYXZKGbFu09EhgD27tgTdGnkcYXLat4KIsBBQeKLR2xZDCXdIBAlWLkiXE1+rJpCxFw==",
"cpu": [
"arm"
],
@ -671,9 +702,9 @@
"peer": true
},
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.24.0.tgz",
"integrity": "sha512-it2BW6kKFVh8xk/BnHfakEeoLPv8STIISekpoF+nBgWM4d55CZKc7T4Dx1pEbTnYm/xEKMgy1MNtYuoA8RFIWw==",
"version": "4.31.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.31.0.tgz",
"integrity": "sha512-w5IzG0wTVv7B0/SwDnMYmbr2uERQp999q8FMkKG1I+j8hpPX2BYFjWe69xbhbP6J9h2gId/7ogesl9hwblFwwg==",
"cpu": [
"arm"
],
@ -686,9 +717,9 @@
"peer": true
},
"node_modules/@rollup/rollup-linux-arm64-gnu": {
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.24.0.tgz",
"integrity": "sha512-i0xTLXjqap2eRfulFVlSnM5dEbTVque/3Pi4g2y7cxrs7+a9De42z4XxKLYJ7+OhE3IgxvfQM7vQc43bwTgPwA==",
"version": "4.31.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.31.0.tgz",
"integrity": "sha512-JyFFshbN5xwy6fulZ8B/8qOqENRmDdEkcIMF0Zz+RsfamEW+Zabl5jAb0IozP/8UKnJ7g2FtZZPEUIAlUSX8cA==",
"cpu": [
"arm64"
],
@ -701,9 +732,9 @@
"peer": true
},
"node_modules/@rollup/rollup-linux-arm64-musl": {
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.24.0.tgz",
"integrity": "sha512-9E6MKUJhDuDh604Qco5yP/3qn3y7SLXYuiC0Rpr89aMScS2UAmK1wHP2b7KAa1nSjWJc/f/Lc0Wl1L47qjiyQw==",
"version": "4.31.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.31.0.tgz",
"integrity": "sha512-kpQXQ0UPFeMPmPYksiBL9WS/BDiQEjRGMfklVIsA0Sng347H8W2iexch+IEwaR7OVSKtr2ZFxggt11zVIlZ25g==",
"cpu": [
"arm64"
],
@ -715,10 +746,25 @@
],
"peer": true
},
"node_modules/@rollup/rollup-linux-loongarch64-gnu": {
"version": "4.31.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.31.0.tgz",
"integrity": "sha512-pMlxLjt60iQTzt9iBb3jZphFIl55a70wexvo8p+vVFK+7ifTRookdoXX3bOsRdmfD+OKnMozKO6XM4zR0sHRrQ==",
"cpu": [
"loong64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"peer": true
},
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.24.0.tgz",
"integrity": "sha512-2XFFPJ2XMEiF5Zi2EBf4h73oR1V/lycirxZxHZNc93SqDN/IWhYYSYj8I9381ikUFXZrz2v7r2tOVk2NBwxrWw==",
"version": "4.31.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.31.0.tgz",
"integrity": "sha512-D7TXT7I/uKEuWiRkEFbed1UUYZwcJDU4vZQdPTcepK7ecPhzKOYk4Er2YR4uHKme4qDeIh6N3XrLfpuM7vzRWQ==",
"cpu": [
"ppc64"
],
@ -731,9 +777,9 @@
"peer": true
},
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.24.0.tgz",
"integrity": "sha512-M3Dg4hlwuntUCdzU7KjYqbbd+BLq3JMAOhCKdBE3TcMGMZbKkDdJ5ivNdehOssMCIokNHFOsv7DO4rlEOfyKpg==",
"version": "4.31.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.31.0.tgz",
"integrity": "sha512-wal2Tc8O5lMBtoePLBYRKj2CImUCJ4UNGJlLwspx7QApYny7K1cUYlzQ/4IGQBLmm+y0RS7dwc3TDO/pmcneTw==",
"cpu": [
"riscv64"
],
@ -746,9 +792,9 @@
"peer": true
},
"node_modules/@rollup/rollup-linux-s390x-gnu": {
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.24.0.tgz",
"integrity": "sha512-mjBaoo4ocxJppTorZVKWFpy1bfFj9FeCMJqzlMQGjpNPY9JwQi7OuS1axzNIk0nMX6jSgy6ZURDZ2w0QW6D56g==",
"version": "4.31.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.31.0.tgz",
"integrity": "sha512-O1o5EUI0+RRMkK9wiTVpk2tyzXdXefHtRTIjBbmFREmNMy7pFeYXCFGbhKFwISA3UOExlo5GGUuuj3oMKdK6JQ==",
"cpu": [
"s390x"
],
@ -761,9 +807,9 @@
"peer": true
},
"node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.24.0.tgz",
"integrity": "sha512-ZXFk7M72R0YYFN5q13niV0B7G8/5dcQ9JDp8keJSfr3GoZeXEoMHP/HlvqROA3OMbMdfr19IjCeNAnPUG93b6A==",
"version": "4.31.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.31.0.tgz",
"integrity": "sha512-zSoHl356vKnNxwOWnLd60ixHNPRBglxpv2g7q0Cd3Pmr561gf0HiAcUBRL3S1vPqRC17Zo2CX/9cPkqTIiai1g==",
"cpu": [
"x64"
],
@ -776,9 +822,9 @@
"peer": true
},
"node_modules/@rollup/rollup-linux-x64-musl": {
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.24.0.tgz",
"integrity": "sha512-w1i+L7kAXZNdYl+vFvzSZy8Y1arS7vMgIy8wusXJzRrPyof5LAb02KGr1PD2EkRcl73kHulIID0M501lN+vobQ==",
"version": "4.31.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.31.0.tgz",
"integrity": "sha512-ypB/HMtcSGhKUQNiFwqgdclWNRrAYDH8iMYH4etw/ZlGwiTVxBz2tDrGRrPlfZu6QjXwtd+C3Zib5pFqID97ZA==",
"cpu": [
"x64"
],
@ -791,9 +837,9 @@
"peer": true
},
"node_modules/@rollup/rollup-win32-arm64-msvc": {
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.24.0.tgz",
"integrity": "sha512-VXBrnPWgBpVDCVY6XF3LEW0pOU51KbaHhccHw6AS6vBWIC60eqsH19DAeeObl+g8nKAz04QFdl/Cefta0xQtUQ==",
"version": "4.31.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.31.0.tgz",
"integrity": "sha512-JuhN2xdI/m8Hr+aVO3vspO7OQfUFO6bKLIRTAy0U15vmWjnZDLrEgCZ2s6+scAYaQVpYSh9tZtRijApw9IXyMw==",
"cpu": [
"arm64"
],
@ -806,9 +852,9 @@
"peer": true
},
"node_modules/@rollup/rollup-win32-ia32-msvc": {
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.24.0.tgz",
"integrity": "sha512-xrNcGDU0OxVcPTH/8n/ShH4UevZxKIO6HJFK0e15XItZP2UcaiLFd5kiX7hJnqCbSztUF8Qot+JWBC/QXRPYWQ==",
"version": "4.31.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.31.0.tgz",
"integrity": "sha512-U1xZZXYkvdf5MIWmftU8wrM5PPXzyaY1nGCI4KI4BFfoZxHamsIe+BtnPLIvvPykvQWlVbqUXdLa4aJUuilwLQ==",
"cpu": [
"ia32"
],
@ -821,9 +867,9 @@
"peer": true
},
"node_modules/@rollup/rollup-win32-x64-msvc": {
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.24.0.tgz",
"integrity": "sha512-fbMkAF7fufku0N2dE5TBXcNlg0pt0cJue4xBRE2Qc5Vqikxr4VCgKj/ht6SMdFcOacVA9rqF70APJ8RN/4vMJw==",
"version": "4.31.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.31.0.tgz",
"integrity": "sha512-ul8rnCsUumNln5YWwz0ted2ZHFhzhRRnkpBZ+YRuHoRAlUji9KChpOUOndY7uykrPEPXVbHLlsdo6v5yXo/TXw==",
"cpu": [
"x64"
],
@ -836,9 +882,9 @@
"peer": true
},
"node_modules/@sveltejs/adapter-auto": {
"version": "3.2.5",
"resolved": "https://registry.npmjs.org/@sveltejs/adapter-auto/-/adapter-auto-3.2.5.tgz",
"integrity": "sha512-27LR+uKccZ62lgq4N/hvyU2G+hTP9fxWEAfnZcl70HnyfAjMSsGk1z/SjAPXNCD1mVJIE7IFu3TQ8cQ/UH3c0A==",
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@sveltejs/adapter-auto/-/adapter-auto-4.0.0.tgz",
"integrity": "sha512-kmuYSQdD2AwThymQF0haQhM8rE5rhutQXG4LNbnbShwhMO4qQGnKaaTy+88DuNSuoQDi58+thpq8XpHc1+oEKQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -849,9 +895,9 @@
}
},
"node_modules/@sveltejs/adapter-static": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/@sveltejs/adapter-static/-/adapter-static-3.0.5.tgz",
"integrity": "sha512-kFJR7RxeB6FBvrKZWAEzIALatgy11ISaaZbcPup8JdWUdrmmfUHHTJ738YHJTEfnCiiXi6aX8Q6ePY7tnSMD6Q==",
"version": "3.0.8",
"resolved": "https://registry.npmjs.org/@sveltejs/adapter-static/-/adapter-static-3.0.8.tgz",
"integrity": "sha512-YaDrquRpZwfcXbnlDsSrBQNCChVOT9MGuSg+dMAyfsAa1SmiAhrA5jUYUiIMC59G92kIbY/AaQOWcBdq+lh+zg==",
"dev": true,
"license": "MIT",
"peerDependencies": {
@ -859,25 +905,23 @@
}
},
"node_modules/@sveltejs/kit": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.6.1.tgz",
"integrity": "sha512-QFlch3GPGZYidYhdRAub0fONw8UTguPICFHUSPxNkA/jdlU1p6C6yqq19J1QWdxIHS2El/ycDCGrHb3EAiMNqg==",
"version": "2.16.0",
"resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.16.0.tgz",
"integrity": "sha512-S9i1ZWKqluzoaJ6riYnEdbe+xJluMTMkhABouBa66GaWcAyCjW/jAc0NdJQJ/DXyK1CnP5quBW25e99MNyvLxA==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
"@types/cookie": "^0.6.0",
"cookie": "^0.6.0",
"devalue": "^5.1.0",
"esm-env": "^1.0.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": "^2.0.4",
"tiny-glob": "^0.2.9"
"sirv": "^3.0.0"
},
"bin": {
"svelte-kit": "svelte-kit.js"
@ -886,9 +930,9 @@
"node": ">=18.13"
},
"peerDependencies": {
"@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1",
"@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"
"vite": "^5.0.3 || ^6.0.0"
}
},
"node_modules/@sveltejs/vite-plugin-svelte": {
@ -897,7 +941,6 @@
"integrity": "sha512-Txsm1tJvtiYeLUVRNqxZGKR/mI+CzuIQuc2gn+YCs9rMTowpNZ2Nqt53JdL8KF9bLhAf2ruR/dr9eZCwdTriRA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@sveltejs/vite-plugin-svelte-inspector": "^2.1.0",
"debug": "^4.3.4",
@ -921,7 +964,6 @@
"integrity": "sha512-9QX28IymvBlSCqsCll5t0kQVxipsfhFFL+L2t3nTWfXnddYwxBuAEtTtlaVQpRz9c37BhJjltSeY4AJSC03SSg==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"debug": "^4.3.4"
},
@ -935,9 +977,9 @@
}
},
"node_modules/@tailwindcss/typography": {
"version": "0.5.15",
"resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.15.tgz",
"integrity": "sha512-AqhlCXl+8grUz8uqExv5OTtgpjuVIwFTSXTrh8y9/pw6q2ek7fJ+Y8ZEVw7EB2DCcuCOtEjf9w3+J3rzts01uA==",
"version": "0.5.16",
"resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.16.tgz",
"integrity": "sha512-0wDLwCVF5V3x3b1SGXPCDcdsbDHMBe+lkFzBRaHeLvNi+nrrnZ1lA18u+OTWO8iSWU2GxUOCvlXtDuqftc1oiA==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -947,7 +989,7 @@
"postcss-selector-parser": "6.0.10"
},
"peerDependencies": {
"tailwindcss": ">=3.0.0 || insiders || >=4.0.0-alpha.20"
"tailwindcss": ">=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1"
}
},
"node_modules/@types/cookie": {
@ -972,22 +1014,22 @@
"license": "MIT"
},
"node_modules/@vitejs/plugin-basic-ssl": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-1.1.0.tgz",
"integrity": "sha512-wO4Dk/rm8u7RNhOf95ZzcEmC9rYOncYgvq4z3duaJrCgjN8BxAnDVyndanfcJZ0O6XZzHz6Q0hTimxTg8Y9g/A==",
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-1.2.0.tgz",
"integrity": "sha512-mkQnxTkcldAzIsomk1UuLfAu9n+kpQ3JbHcpCp7d2Oo6ITtji8pHS3QToOWjhPFvNQSnhlkAjmGbhv2QvwO/7Q==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=14.6.0"
"node": ">=14.21.3"
},
"peerDependencies": {
"vite": "^3.0.0 || ^4.0.0 || ^5.0.0"
"vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0"
}
},
"node_modules/acorn": {
"version": "8.12.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz",
"integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==",
"version": "8.14.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz",
"integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==",
"dev": true,
"license": "MIT",
"bin": {
@ -1154,9 +1196,9 @@
}
},
"node_modules/browserslist": {
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.0.tgz",
"integrity": "sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A==",
"version": "4.24.4",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz",
"integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==",
"dev": true,
"funding": [
{
@ -1174,10 +1216,10 @@
],
"license": "MIT",
"dependencies": {
"caniuse-lite": "^1.0.30001663",
"electron-to-chromium": "^1.5.28",
"node-releases": "^2.0.18",
"update-browserslist-db": "^1.1.0"
"caniuse-lite": "^1.0.30001688",
"electron-to-chromium": "^1.5.73",
"node-releases": "^2.0.19",
"update-browserslist-db": "^1.1.1"
},
"bin": {
"browserslist": "cli.js"
@ -1207,9 +1249,9 @@
}
},
"node_modules/caniuse-lite": {
"version": "1.0.30001667",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001667.tgz",
"integrity": "sha512-7LTwJjcRkzKFmtqGsibMeuXmvFDfZq/nzIjnmgCGzKKRVzjD72selLDK1oPF/Oxzmt4fNcPvTDvGqSDG4tCALw==",
"version": "1.0.30001695",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001695.tgz",
"integrity": "sha512-vHyLade6wTgI2u1ec3WQBxv+2BrTERV28UXQu9LO6lZ9pYeMk34vjXFLOxo1A4UBA8XTL4njRQZdno/yYaSmWw==",
"dev": true,
"funding": [
{
@ -1314,9 +1356,9 @@
}
},
"node_modules/cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -1377,9 +1419,9 @@
}
},
"node_modules/daisyui": {
"version": "4.12.12",
"resolved": "https://registry.npmjs.org/daisyui/-/daisyui-4.12.12.tgz",
"integrity": "sha512-xmCZ4piuWOjhNyB0VDKczB5vKFCipTA7UxaZNOzCz6cT8kvWgv5BDtUo+Hk9gOFufByOlfuBdzLpfhY5GsebTQ==",
"version": "4.12.23",
"resolved": "https://registry.npmjs.org/daisyui/-/daisyui-4.12.23.tgz",
"integrity": "sha512-EM38duvxutJ5PD65lO/AFMpcw+9qEy6XAZrTpzp7WyaPeO/l+F/Qiq0ECHHmFNcFXh5aVoALY4MGrrxtCiaQCQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -1397,12 +1439,11 @@
}
},
"node_modules/debug": {
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
"integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"ms": "^2.1.3"
},
@ -1421,7 +1462,6 @@
"integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
"dev": true,
"license": "MIT",
"peer": true,
"engines": {
"node": ">=0.10.0"
}
@ -1465,9 +1505,9 @@
"license": "MIT"
},
"node_modules/electron-to-chromium": {
"version": "1.5.32",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.32.tgz",
"integrity": "sha512-M+7ph0VGBQqqpTT2YrabjNKSQ2fEl9PVx6AK3N558gDH9NO8O6XN9SXXFWRo9u9PbEg/bWq+tjXQr+eXmxubCw==",
"version": "1.5.83",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.83.tgz",
"integrity": "sha512-LcUDPqSt+V0QmI47XLzZrz5OqILSMGsPFkDYus22rIbgorSvBYEFqq854ltTmUdHkY92FSdAAvsh4jWEULMdfQ==",
"dev": true,
"license": "ISC"
},
@ -1536,9 +1576,9 @@
}
},
"node_modules/esm-env": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.0.0.tgz",
"integrity": "sha512-Cf6VksWPsTuW01vU9Mk/3vRue91Zevka5SjyNf3nEpokFRuqt/KjUQoGAwq9qMmhpLTHmXzSIrFRw8zxWzmFBA==",
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.2.tgz",
"integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==",
"dev": true,
"license": "MIT"
},
@ -1553,9 +1593,9 @@
}
},
"node_modules/fast-glob": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
"integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
"integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -1563,7 +1603,7 @@
"@nodelib/fs.walk": "^1.2.3",
"glob-parent": "^5.1.2",
"merge2": "^1.3.0",
"micromatch": "^4.0.4"
"micromatch": "^4.0.8"
},
"engines": {
"node": ">=8.6.0"
@ -1577,9 +1617,9 @@
"license": "MIT"
},
"node_modules/fastq": {
"version": "1.17.1",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
"integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==",
"version": "1.18.0",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.18.0.tgz",
"integrity": "sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw==",
"dev": true,
"license": "ISC",
"dependencies": {
@ -1707,20 +1747,6 @@
"node": ">= 6"
}
},
"node_modules/globalyzer": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz",
"integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==",
"dev": true,
"license": "MIT"
},
"node_modules/globrex": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz",
"integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==",
"dev": true,
"license": "MIT"
},
"node_modules/graceful-fs": {
"version": "4.2.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
@ -1785,9 +1811,9 @@
}
},
"node_modules/is-core-module": {
"version": "2.15.1",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz",
"integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==",
"version": "2.16.1",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
"integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -1844,13 +1870,13 @@
}
},
"node_modules/is-reference": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz",
"integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==",
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz",
"integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/estree": "*"
"@types/estree": "^1.0.6"
}
},
"node_modules/isexe": {
@ -1877,9 +1903,9 @@
}
},
"node_modules/jiti": {
"version": "1.21.6",
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz",
"integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==",
"version": "1.21.7",
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz",
"integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==",
"dev": true,
"license": "MIT",
"bin": {
@ -1897,9 +1923,9 @@
}
},
"node_modules/lilconfig": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz",
"integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==",
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz",
"integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==",
"dev": true,
"license": "MIT",
"engines": {
@ -1952,9 +1978,9 @@
"license": "ISC"
},
"node_modules/magic-string": {
"version": "0.30.11",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz",
"integrity": "sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==",
"version": "0.30.17",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz",
"integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -2073,8 +2099,7 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"dev": true,
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/mz": {
"version": "2.7.0",
@ -2089,9 +2114,9 @@
}
},
"node_modules/nanoid": {
"version": "3.3.7",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
"version": "3.3.8",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz",
"integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==",
"dev": true,
"funding": [
{
@ -2108,9 +2133,9 @@
}
},
"node_modules/node-releases": {
"version": "2.0.18",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz",
"integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==",
"version": "2.0.19",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz",
"integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==",
"dev": true,
"license": "MIT"
},
@ -2228,9 +2253,9 @@
}
},
"node_modules/picocolors": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz",
"integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==",
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
"dev": true,
"license": "ISC"
},
@ -2268,9 +2293,9 @@
}
},
"node_modules/postcss": {
"version": "8.4.47",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz",
"integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==",
"version": "8.5.1",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.1.tgz",
"integrity": "sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==",
"dev": true,
"funding": [
{
@ -2288,8 +2313,8 @@
],
"license": "MIT",
"dependencies": {
"nanoid": "^3.3.7",
"picocolors": "^1.1.0",
"nanoid": "^3.3.8",
"picocolors": "^1.1.1",
"source-map-js": "^1.2.1"
},
"engines": {
@ -2436,9 +2461,9 @@
"license": "MIT"
},
"node_modules/prettier": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz",
"integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==",
"version": "3.4.2",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz",
"integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==",
"dev": true,
"license": "MIT",
"bin": {
@ -2452,9 +2477,9 @@
}
},
"node_modules/prettier-plugin-svelte": {
"version": "3.2.7",
"resolved": "https://registry.npmjs.org/prettier-plugin-svelte/-/prettier-plugin-svelte-3.2.7.tgz",
"integrity": "sha512-/Dswx/ea0lV34If1eDcG3nulQ63YNr5KPDfMsjbdtpSWOxKKJ7nAc2qlVuYwEvCr4raIuredNoR7K4JCkmTGaQ==",
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/prettier-plugin-svelte/-/prettier-plugin-svelte-3.3.3.tgz",
"integrity": "sha512-yViK9zqQ+H2qZD1w/bH7W8i+bVfKrD8GIFjkFe4Thl6kCT9SlAsXVNmt3jCvQOCsnOhcvYgsoVlRV/Eu6x5nNw==",
"dev": true,
"license": "MIT",
"peerDependencies": {
@ -2507,19 +2532,22 @@
}
},
"node_modules/resolve": {
"version": "1.22.8",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
"integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
"version": "1.22.10",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
"integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==",
"dev": true,
"license": "MIT",
"dependencies": {
"is-core-module": "^2.13.0",
"is-core-module": "^2.16.0",
"path-parse": "^1.0.7",
"supports-preserve-symlinks-flag": "^1.0.0"
},
"bin": {
"resolve": "bin/resolve"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
@ -2550,9 +2578,9 @@
}
},
"node_modules/rollup": {
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.24.0.tgz",
"integrity": "sha512-DOmrlGSXNk1DM0ljiQA+i+o0rSLhtii1je5wgk60j49d1jHT5YYttBv1iWOnYSTG+fZZESUOSNiAl89SIet+Cg==",
"version": "4.31.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.31.0.tgz",
"integrity": "sha512-9cCE8P4rZLx9+PjoyqHLs31V9a9Vpvfo4qNcs6JCiGWYhw2gijSetFbH6SSy1whnkgcefnUwr8sad7tgqsGvnw==",
"dev": true,
"license": "MIT",
"peer": true,
@ -2567,22 +2595,25 @@
"npm": ">=8.0.0"
},
"optionalDependencies": {
"@rollup/rollup-android-arm-eabi": "4.24.0",
"@rollup/rollup-android-arm64": "4.24.0",
"@rollup/rollup-darwin-arm64": "4.24.0",
"@rollup/rollup-darwin-x64": "4.24.0",
"@rollup/rollup-linux-arm-gnueabihf": "4.24.0",
"@rollup/rollup-linux-arm-musleabihf": "4.24.0",
"@rollup/rollup-linux-arm64-gnu": "4.24.0",
"@rollup/rollup-linux-arm64-musl": "4.24.0",
"@rollup/rollup-linux-powerpc64le-gnu": "4.24.0",
"@rollup/rollup-linux-riscv64-gnu": "4.24.0",
"@rollup/rollup-linux-s390x-gnu": "4.24.0",
"@rollup/rollup-linux-x64-gnu": "4.24.0",
"@rollup/rollup-linux-x64-musl": "4.24.0",
"@rollup/rollup-win32-arm64-msvc": "4.24.0",
"@rollup/rollup-win32-ia32-msvc": "4.24.0",
"@rollup/rollup-win32-x64-msvc": "4.24.0",
"@rollup/rollup-android-arm-eabi": "4.31.0",
"@rollup/rollup-android-arm64": "4.31.0",
"@rollup/rollup-darwin-arm64": "4.31.0",
"@rollup/rollup-darwin-x64": "4.31.0",
"@rollup/rollup-freebsd-arm64": "4.31.0",
"@rollup/rollup-freebsd-x64": "4.31.0",
"@rollup/rollup-linux-arm-gnueabihf": "4.31.0",
"@rollup/rollup-linux-arm-musleabihf": "4.31.0",
"@rollup/rollup-linux-arm64-gnu": "4.31.0",
"@rollup/rollup-linux-arm64-musl": "4.31.0",
"@rollup/rollup-linux-loongarch64-gnu": "4.31.0",
"@rollup/rollup-linux-powerpc64le-gnu": "4.31.0",
"@rollup/rollup-linux-riscv64-gnu": "4.31.0",
"@rollup/rollup-linux-s390x-gnu": "4.31.0",
"@rollup/rollup-linux-x64-gnu": "4.31.0",
"@rollup/rollup-linux-x64-musl": "4.31.0",
"@rollup/rollup-win32-arm64-msvc": "4.31.0",
"@rollup/rollup-win32-ia32-msvc": "4.31.0",
"@rollup/rollup-win32-x64-msvc": "4.31.0",
"fsevents": "~2.3.2"
}
},
@ -2637,9 +2668,9 @@
}
},
"node_modules/set-cookie-parser": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.0.tgz",
"integrity": "sha512-lXLOiqpkUumhRdFF3k1osNXCy9akgx/dyPZ5p8qAg9seJzXr5ZrlqZuWIMuY6ejOsVLE6flJ5/h3lsn57fQ/PQ==",
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz",
"integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==",
"dev": true,
"license": "MIT"
},
@ -2680,9 +2711,9 @@
}
},
"node_modules/sirv": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.4.tgz",
"integrity": "sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==",
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.0.tgz",
"integrity": "sha512-BPwJGUeDaDCHihkORDchNyyTvWFhcusy1XMmhEVTQTwGeybFbp8YEmB+njbPnth1FibULBSBVwCQni25XlCUDg==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -2691,7 +2722,7 @@
"totalist": "^3.0.0"
},
"engines": {
"node": ">= 10"
"node": ">=18"
}
},
"node_modules/sorcery": {
@ -2973,7 +3004,6 @@
"integrity": "sha512-Gyc7cOS3VJzLlfj7wKS0ZnzDVdv3Pn2IuVeJPk9m2skfhcu5bq3wtIZyQGggr7/Iim5rH5cncyQft/kRLupcnA==",
"dev": true,
"license": "ISC",
"peer": true,
"engines": {
"node": "^12.20 || ^14.13.1 || >= 16"
},
@ -3045,34 +3075,34 @@
}
},
"node_modules/tailwindcss": {
"version": "3.4.13",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.13.tgz",
"integrity": "sha512-KqjHOJKogOUt5Bs752ykCeiwvi0fKVkr5oqsFNt/8px/tA8scFPIlkygsf6jXrfCqGHz7VflA6+yytWuM+XhFw==",
"version": "3.4.17",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz",
"integrity": "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==",
"dev": true,
"license": "MIT",
"dependencies": {
"@alloc/quick-lru": "^5.2.0",
"arg": "^5.0.2",
"chokidar": "^3.5.3",
"chokidar": "^3.6.0",
"didyoumean": "^1.2.2",
"dlv": "^1.1.3",
"fast-glob": "^3.3.0",
"fast-glob": "^3.3.2",
"glob-parent": "^6.0.2",
"is-glob": "^4.0.3",
"jiti": "^1.21.0",
"lilconfig": "^2.1.0",
"micromatch": "^4.0.5",
"jiti": "^1.21.6",
"lilconfig": "^3.1.3",
"micromatch": "^4.0.8",
"normalize-path": "^3.0.0",
"object-hash": "^3.0.0",
"picocolors": "^1.0.0",
"postcss": "^8.4.23",
"picocolors": "^1.1.1",
"postcss": "^8.4.47",
"postcss-import": "^15.1.0",
"postcss-js": "^4.0.1",
"postcss-load-config": "^4.0.1",
"postcss-nested": "^6.0.1",
"postcss-selector-parser": "^6.0.11",
"resolve": "^1.22.2",
"sucrase": "^3.32.0"
"postcss-load-config": "^4.0.2",
"postcss-nested": "^6.2.0",
"postcss-selector-parser": "^6.1.2",
"resolve": "^1.22.8",
"sucrase": "^3.35.0"
},
"bin": {
"tailwind": "lib/cli.js",
@ -3095,16 +3125,6 @@
"node": ">=10.13.0"
}
},
"node_modules/tailwindcss/node_modules/lilconfig": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
"integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=10"
}
},
"node_modules/tailwindcss/node_modules/postcss-load-config": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz",
@ -3141,19 +3161,6 @@
}
}
},
"node_modules/tailwindcss/node_modules/postcss-load-config/node_modules/lilconfig": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz",
"integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/sponsors/antonk52"
}
},
"node_modules/tailwindcss/node_modules/postcss-selector-parser": {
"version": "6.1.2",
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz",
@ -3191,17 +3198,6 @@
"node": ">=0.8"
}
},
"node_modules/tiny-glob": {
"version": "0.2.9",
"resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz",
"integrity": "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==",
"dev": true,
"license": "MIT",
"dependencies": {
"globalyzer": "0.1.0",
"globrex": "^0.1.2"
}
},
"node_modules/to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
@ -3233,9 +3229,9 @@
"license": "Apache-2.0"
},
"node_modules/typescript": {
"version": "5.6.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz",
"integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==",
"version": "5.7.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz",
"integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==",
"dev": true,
"license": "Apache-2.0",
"bin": {
@ -3247,9 +3243,9 @@
}
},
"node_modules/update-browserslist-db": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz",
"integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==",
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.2.tgz",
"integrity": "sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg==",
"dev": true,
"funding": [
{
@ -3268,7 +3264,7 @@
"license": "MIT",
"dependencies": {
"escalade": "^3.2.0",
"picocolors": "^1.1.0"
"picocolors": "^1.1.1"
},
"bin": {
"update-browserslist-db": "cli.js"
@ -3285,9 +3281,9 @@
"license": "MIT"
},
"node_modules/vite": {
"version": "5.4.8",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.8.tgz",
"integrity": "sha512-FqrItQ4DT1NC4zCUqMB4c4AZORMKIa0m8/URVCZ77OZ/QSNeJ54bU1vrFADbDsuwfIPcgknRkmqakQcgnL4GiQ==",
"version": "5.4.11",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.11.tgz",
"integrity": "sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==",
"dev": true,
"license": "MIT",
"peer": true,
@ -3351,7 +3347,6 @@
"integrity": "sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==",
"dev": true,
"license": "MIT",
"peer": true,
"peerDependencies": {
"vite": "^3.0.0 || ^4.0.0 || ^5.0.0"
},
@ -3483,9 +3478,9 @@
"license": "ISC"
},
"node_modules/yaml": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.1.tgz",
"integrity": "sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q==",
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.0.tgz",
"integrity": "sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==",
"dev": true,
"license": "ISC",
"bin": {

View file

@ -1,6 +1,6 @@
{
"name": "headscale-ui",
"version": "2024.10.10",
"version": "2025.08.23",
"scripts": {
"dev": "vite dev --port 8080 --host 0.0.0.0",
"build": "vite build",
@ -13,9 +13,10 @@
"format": "prettier --write --plugin-search-dir=. ."
},
"devDependencies": {
"@sveltejs/adapter-auto": "^3",
"@sveltejs/adapter-auto": "^4",
"@sveltejs/adapter-static": "^3",
"@sveltejs/kit": "^2",
"@sveltejs/vite-plugin-svelte": "^3",
"@tailwindcss/typography": "^0",
"@vitejs/plugin-basic-ssl": "^1",
"autoprefixer": "^10",
@ -32,4 +33,4 @@
"typescript": "^5"
},
"type": "module"
}
}

View file

@ -51,13 +51,13 @@
filterUsers();
}
export async function editUser(currentUsername: string, newUsername: string): Promise<any> {
export async function editUser(currentUserId: string, newUsername: string): Promise<any> {
// variables in local storage
let headscaleURL = localStorage.getItem('headscaleURL') || '';
let headscaleAPIKey = localStorage.getItem('headscaleAPIKey') || '';
// endpoint url for editing users
let endpointURL = '/api/v1/user/' + currentUsername + '/rename/' + newUsername;
let endpointURL = '/api/v1/user/' + currentUserId + '/rename/' + newUsername;
await fetch(headscaleURL + endpointURL, {
method: 'POST',
@ -184,13 +184,13 @@
});
}
export async function removeUser(currentUsername: string): Promise<any> {
export async function removeUser(currentUserId: string): Promise<any> {
// variables in local storage
let headscaleURL = localStorage.getItem('headscaleURL') || '';
let headscaleAPIKey = localStorage.getItem('headscaleAPIKey') || '';
// endpoint url for editing users
let endpointURL = '/api/v1/user/' + currentUsername;
let endpointURL = '/api/v1/user/' + currentUserId;
await fetch(headscaleURL + endpointURL, {
method: 'DELETE',
@ -329,7 +329,7 @@
return apiKeys;
}
export async function getPreauthKeys(userName: string): Promise<PreAuthKey[]> {
export async function getPreauthKeys(userID: string): Promise<PreAuthKey[]> {
// variables in local storage
let headscaleURL = localStorage.getItem('headscaleURL') || '';
let headscaleAPIKey = localStorage.getItem('headscaleAPIKey') || '';
@ -341,7 +341,7 @@
let headscalePreAuthKey = [new PreAuthKey()];
let headscalePreAuthKeyResponse: Response = new Response();
await fetch(headscaleURL + endpointURL + '?user=' + userName, {
await fetch(headscaleURL + endpointURL + '?user=' + userID, {
method: 'GET',
headers: {
Accept: 'application/json',
@ -367,7 +367,7 @@
return headscalePreAuthKey;
}
export async function newPreAuthKey(userName: string, expiry: string, reusable: boolean, ephemeral: boolean): Promise<any> {
export async function newPreAuthKey(userID: string, expiry: string, reusable: boolean, ephemeral: boolean): Promise<any> {
// variables in local storage
let headscaleURL = localStorage.getItem('headscaleURL') || '';
let headscaleAPIKey = localStorage.getItem('headscaleAPIKey') || '';
@ -381,7 +381,7 @@
Authorization: `Bearer ${headscaleAPIKey}`
},
body: JSON.stringify({
user: userName,
user: userID,
expiration: expiry,
reusable: reusable,
ephemeral: ephemeral
@ -401,7 +401,7 @@
});
}
export async function removePreAuthKey(userName: string, preAuthKey: string): Promise<any> {
export async function removePreAuthKey(userID: string, preAuthKey: string): Promise<any> {
// variables in local storage
let headscaleURL = localStorage.getItem('headscaleURL') || '';
let headscaleAPIKey = localStorage.getItem('headscaleAPIKey') || '';
@ -416,7 +416,7 @@
Authorization: `Bearer ${headscaleAPIKey}`
},
body: JSON.stringify({
user: userName,
user: userID,
key: preAuthKey
})
})
@ -434,7 +434,7 @@
});
}
export async function newDevice(key: string, userName: string): Promise<any> {
export async function newDevice(key: string, userId: string): Promise<any> {
// variables in local storage
let headscaleURL = localStorage.getItem('headscaleURL') || '';
@ -443,7 +443,7 @@
// endpoint url for editing users
let endpointURL = `/api/v1/node/register`;
await fetch(headscaleURL + endpointURL + '?user=' + userName + '&key=' + key, {
await fetch(headscaleURL + endpointURL + '?user=' + userId + '&key=' + key, {
method: 'POST',
headers: {
Accept: 'application/json',
@ -464,21 +464,24 @@
});
}
export async function moveDevice(deviceID: string, user: string): Promise<any> {
export async function moveDevice(deviceID: string, userID: string): Promise<any> {
// variables in local storage
let headscaleURL = localStorage.getItem('headscaleURL') || '';
let headscaleAPIKey = localStorage.getItem('headscaleAPIKey') || '';
// endpoint url for editing users
let endpointURL = `/api/v1/node/${deviceID}/user?user=${user}`;
let endpointURL = `/api/v1/node/${deviceID}/user`;
await fetch(headscaleURL + endpointURL, {
method: 'POST',
headers: {
Accept: 'application/json',
Authorization: `Bearer ${headscaleAPIKey}`
}
},
body: JSON.stringify({
user: parseInt(userID)
})
})
.then((response) => {
if (response.ok) {

View file

@ -7,7 +7,10 @@ export class Device {
public forcedTags: string[] = [];
public validTags: string[] = [];
public invalidTags: string[] = [];
public user: { name: string } = { name: '' };
public approvedRoutes: string[] = [];
public availableRoutes: string[] = [];
public subnetRoutes: string[] = [];
public user: User = new User();
public online?: boolean;
public constructor(init?: Partial<Device>) {
@ -18,19 +21,7 @@ export class Device {
export class ACL {
public groups: { [key: string]: [string] } = {};
public constructor(init?: Partial<Route>) {
Object.assign(this, init);
}
}
export class Route {
// current (hs 18+) method of handling a route
advertised: boolean = true;
prefix: string = '';
enabled: boolean = false;
id: number = 0;
public constructor(init?: Partial<Route>) {
public constructor(init?: Partial<ACL>) {
Object.assign(this, init);
}
}
@ -42,7 +33,7 @@ export class APIKey {
createdAt: string = '';
lastSeen: string = '';
public constructor(init?: Partial<Route>) {
public constructor(init?: Partial<APIKey>) {
Object.assign(this, init);
}
}
@ -65,6 +56,7 @@ export class PreAuthKey {
export class User {
public id: string = '';
public name: string = '';
public email: string = '';
public createdAt: string = '';
public constructor(init?: Partial<User>) {
Object.assign(this, init);

View file

@ -59,13 +59,13 @@
<form class="flex flex-wrap" bind:this={newDeviceForm} on:submit|preventDefault={newDeviceAction}>
<div class="flex-none mr-4">
<label class="block text-secondary text-sm font-bold mb-2" for="text">Device Key</label>
<input bind:value={newDeviceKey} minlength="54" class="card-input" type="text" required placeholder="******************" />
<input bind:value={newDeviceKey} class="card-input" type="text" required placeholder="******************" />
</div>
<div class="flex-none">
<label class="block text-secondary text-sm font-bold mb-2" for="select">Select User</label>
<select class="card-select mr-3" required bind:value={selectedUser}>
{#each $userStore as user}
<option>{user.name}</option>
<option>{user.name.length > 1 ? user.name : user.email}</option>
{/each}
</select>
</div>

View file

@ -1,67 +1,18 @@
<script lang="ts">
import { getDeviceRoutes, modifyDeviceRoutes } from './DeviceRoutesAPI.svelte';
import { Device, Route } from '$lib/common/classes';
import { onMount } from 'svelte';
import { alertStore } from '$lib/common/stores';
import { Device } from '$lib/common/classes';
import DeviceRoute from './DeviceRoutes/DeviceRoute.svelte';
export let device = new Device();
let routesList: Route[] = [];
let routeID = 0;
onMount(async () => {
getDeviceRoutesAction();
});
function getDeviceRoutesAction() {
getDeviceRoutes(device.id)
.then((routes) => {
routesList = routes;
})
.catch((error) => {
$alertStore = error;
});
}
function modifyDeviceRoutesAction() {
modifyDeviceRoutes(device.id, routesList, routeID)
.then((response) => {
getDeviceRoutesAction();
})
.catch((error) => {
$alertStore = error;
});
}
</script>
<th>Device Routes</th>
<td
><ul class="list-disc list-inside">
{#each routesList as route, index}
{#each device.availableRoutes as route}
<li>
{route.prefix}
{#if route.enabled}
<button
on:click={() => {
routesList[index].enabled = false;
routeID = route.id;
modifyDeviceRoutesAction();
}}
type="button"
class="btn btn-xs tooltip capitalize bg-success text-success-content mx-1"
data-tip="press to disable route">active</button
>
{:else}
<button
on:click={() => {
routesList[index].enabled = true;
routeID = route.id
modifyDeviceRoutesAction();
}}
type="button"
class="btn btn-xs tooltip capitalize bg-secondary text-secondary-content mx-1"
data-tip="press to enable route">pending</button
>
{/if}
<DeviceRoute {route} {device}></DeviceRoute>
</li>
{/each}
</ul></td

View file

@ -0,0 +1,60 @@
<script>
import { getDevices } from '$lib/common/apiFunctions.svelte';
import { Device } from '$lib/common/classes';
import { alertStore } from '$lib/common/stores';
import { approveDeviceRoute } from './DeviceRouteAPI.svelte';
export let route = '';
export let device = new Device();
let routeDisabled = false;
function approveRouteAction() {
approveDeviceRoute(device.id, [...device.approvedRoutes, route])
.then(() => {
// refresh users after editing
getDevices();
})
.catch((error) => {
$alertStore = error;
});
}
function removeRouteAction() {
approveDeviceRoute(device.id, device.approvedRoutes.filter((r) => r !== route))
.then(() => {
// refresh users after editing
getDevices();
})
.catch((error) => {
$alertStore = error;
});
}
</script>
{route}
{#if device.approvedRoutes.includes(route)}
<button
on:click={() => {
routeDisabled = true;
removeRouteAction();
routeDisabled = false;
}}
type="button"
class="btn btn-xs tooltip capitalize bg-success text-success-content mx-1">active</button
>
{:else}
<button
on:click={() => {
routeDisabled = true;
approveRouteAction();
routeDisabled = false;
}}
type="button"
class="btn btn-xs tooltip capitalize bg-secondary text-secondary-content mx-1"
class:disabled={routeDisabled}
data-tip="click to enable route">pending</button
>
{/if}
{#if device.subnetRoutes.includes(route)}
<button type="button" class="btn btn-xs tooltip capitalize bg-secondary text-secondary-content mx-1">subnet</button>
{/if}

View file

@ -0,0 +1,34 @@
<script context="module" lang="ts">
export async function approveDeviceRoute(deviceID: string, routes: string[]): Promise<any> {
// variables in local storage
let headscaleURL = localStorage.getItem('headscaleURL') || '';
let headscaleAPIKey = localStorage.getItem('headscaleAPIKey') || '';
let endpointURL = `/api/v1/node/${deviceID}/approve_routes`;
await fetch(headscaleURL + endpointURL, {
method: 'POST',
headers: {
Accept: 'application/json',
Authorization: `Bearer ${headscaleAPIKey}`
},
body: JSON.stringify({
routes: routes
})
})
.then((response) => {
if (response.ok) {
// return the api data
return response;
} else {
return response.text().then((text) => {
throw JSON.parse(text).message;
});
}
})
.catch((error) => {
throw error;
});
}
</script>

View file

@ -1,84 +0,0 @@
<script context="module" lang="ts">
import type { Route } from '$lib/common/classes';
export async function getDeviceRoutes(deviceID: string): Promise<Route[]> {
// variables in local storage
let headscaleURL = localStorage.getItem('headscaleURL') || '';
let headscaleAPIKey = localStorage.getItem('headscaleAPIKey') || '';
// endpoint url for getting users
let endpointURL = `/api/v1/node/${deviceID}/routes`;
//returning variables
let headscaleRouteList: Route[] = [];
let headscaleDeviceResponse: Response = new Response();
await fetch(headscaleURL + endpointURL, {
method: 'GET',
headers: {
Accept: 'application/json',
Authorization: `Bearer ${headscaleAPIKey}`
}
})
.then((response) => {
if (response.ok) {
// return the api data
headscaleDeviceResponse = response;
} else {
return response.text().then((text) => {
throw JSON.parse(text).message;
});
}
})
.catch((error) => {
throw error;
});
await headscaleDeviceResponse.json().then((data) => {
headscaleRouteList = data.routes;
});
return headscaleRouteList;
}
export async function modifyDeviceRoutes(deviceID: string, routeList: Route[], routeID: number): Promise<any> {
// variables in local storage
let headscaleURL = localStorage.getItem('headscaleURL') || '';
let headscaleAPIKey = localStorage.getItem('headscaleAPIKey') || '';
let endpointURL = '';
routeList.forEach((route) => {
if (route.id == routeID) {
endpointURL = `/api/v1/routes/${routeID}/`;
if (route.enabled) {
endpointURL += 'enable';
} else {
endpointURL += 'disable';
}
}
});
//returning variables
let headscaleDeviceResponse: Response = new Response();
await fetch(headscaleURL + endpointURL, {
method: 'POST',
headers: {
Accept: 'application/json',
Authorization: `Bearer ${headscaleAPIKey}`
}
})
.then((response) => {
if (response.ok) {
// return the api data
headscaleDeviceResponse = response;
} else {
return response.text().then((text) => {
throw JSON.parse(text).message;
});
}
})
.catch((error) => {
throw error;
});
}
</script>

View file

@ -34,9 +34,5 @@
>
</span>
{/each}
{#each device.validTags as tag}
<span class="mb-1 mr-1 btn btn-xs btn-secondary normal-case">{tag.replace("tag:","")}</span>
{/each}
</div>

View file

@ -6,7 +6,7 @@
export let device = new Device();
let deviceMoving = false;
let selectedUser = device.user.name;
let selectedUser = device.user.id;
function moveDeviceAction() {
moveDevice(device.id, selectedUser)
@ -39,7 +39,7 @@
<form on:submit|preventDefault={moveDeviceAction}>
<select class="card-select mr-3" required bind:value={selectedUser}>
{#each $userStore as user}
<option>{user.name}</option>
<option value={user.id}>{user.name.length > 1 ? user.name : user.email}</option>
{/each}
</select>
<!-- edit accept symbol -->

View file

@ -47,7 +47,7 @@
{/if}
</label>
<div class="flex relative">
<input bind:value={$APIKeyStore} {...{ type: apiKeyInputState }} minlength="54" maxlength="54" class="form-input" disabled='{apiStatus == 'succeeded'}' required placeholder="******************" />
<input bind:value={$APIKeyStore} {...{ type: apiKeyInputState }} class="form-input" disabled='{apiStatus == 'succeeded'}' required placeholder="******************" />
<button
type="button"
class="absolute right-40"

View file

@ -39,6 +39,10 @@
<div class="overflow-x-auto">
<table class="table table-compact w-full">
<tbody>
<tr>
<th>Email</th>
<td>{user.email}</td>
</tr>
<tr>
<th>User Creation Date</th>
<td>{new Date(user.createdAt)}</td>

View file

@ -22,7 +22,7 @@
}
function getPreauthKeysAction() {
getPreauthKeys(user.name)
getPreauthKeys(user.id)
.then((keys) => {
keyList = keys;
})
@ -107,7 +107,7 @@
<!-- Allow ability to expire if not expired -->
{#if new Date(key.expiration).getTime() > new Date().getTime() && (!key.used || key.reusable)}
<!-- trash symbol -->
<button class="mr-2" on:click={() => {expirePreAuthKeyAction(user.name, key.key)}}
<button class="mr-2" on:click={() => {expirePreAuthKeyAction(user.id, key.key)}}
><svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 inline flex-shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
</svg></button

View file

@ -15,7 +15,7 @@
function NewPreAuthKeyAction() {
let formattedDate = new Date(expiry).toISOString();
newPreAuthKey(user.name, formattedDate, reusable, ephemeral)
newPreAuthKey(user.id, formattedDate, reusable, ephemeral)
.then(() => {
newPreAuthKeyShow = false;
getPreauthKeysAction();
@ -26,7 +26,7 @@
}
function getPreauthKeysAction() {
getPreauthKeys(user.name)
getPreauthKeys(user.id)
.then((keys) => {
keyList = keys;
})

View file

@ -8,7 +8,7 @@
let cardDeleting = false;
function removeUserAction() {
removeUser(user.name)
removeUser(user.id)
.then((response) => {
cardDeleting = false;
// refresh users after editing

View file

@ -16,7 +16,7 @@
function renameUserAction() {
if (editUserForm.reportValidity()) {
editUser(user.name, newUserName)
editUser(user.id, newUserName)
.then((response) => {
cardEditing = false;
// refresh users after editing
@ -32,7 +32,7 @@
</script>
{#if !cardEditing}
<span class="font-bold">{user.id}: {user.name}</span>
<span class="font-bold">{user.id}: {user.name.length > 1 ? user.name : user.email}</span>
<!-- edit symbol -->
<button type="button" on:click|stopPropagation={() => editingUser()} class="ml-2"
><svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 inline flex-shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">