diff --git a/.github/workflows/startos-iso.yaml b/.github/workflows/startos-iso.yaml index 3732ac863..913a25327 100644 --- a/.github/workflows/startos-iso.yaml +++ b/.github/workflows/startos-iso.yaml @@ -28,6 +28,7 @@ on: - aarch64 - aarch64-nonfree - raspberrypi + - riscv64 deploy: type: choice description: Deploy @@ -45,7 +46,7 @@ on: - next/* env: - NODEJS_VERSION: "22.17.1" + NODEJS_VERSION: "24.11.0" ENVIRONMENT: '${{ fromJson(format(''["{0}", ""]'', github.event.inputs.environment || ''dev''))[github.event.inputs.environment == ''NONE''] }}' jobs: @@ -62,6 +63,7 @@ jobs: "aarch64": ["aarch64"], "aarch64-nonfree": ["aarch64"], "raspberrypi": ["aarch64"], + "riscv64": ["riscv64"], "ALL": ["x86_64", "aarch64"] }')[github.event.inputs.platform || 'ALL'] }} @@ -100,6 +102,12 @@ jobs: core.exportVariable('ACTIONS_RESULTS_URL', process.env.ACTIONS_RESULTS_URL || ''); core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); + - name: Use Beta Toolchain + run: rustup default beta + + - name: Setup Cross + run: cargo install cross --git https://github.com/cross-rs/cross + - name: Make run: make ARCH=${{ matrix.arch }} compiled-${{ matrix.arch }}.tar env: @@ -139,6 +147,7 @@ jobs: "aarch64": "buildjet-8vcpu-ubuntu-2204-arm", "aarch64-nonfree": "buildjet-8vcpu-ubuntu-2204-arm", "raspberrypi": "buildjet-8vcpu-ubuntu-2204-arm", + "riscv64": "buildjet-8vcpu-ubuntu-2204", }')[matrix.platform] ) )[github.event.inputs.runner == 'fast'] @@ -152,6 +161,7 @@ jobs: "aarch64": "aarch64", "aarch64-nonfree": "aarch64", "raspberrypi": "aarch64", + "riscv64": "riscv64", }')[matrix.platform] }} steps: diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 7781a60ba..d79e2f597 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -11,7 +11,7 @@ on: - next/* env: - NODEJS_VERSION: "22.17.1" + NODEJS_VERSION: "24.11.0" ENVIRONMENT: dev-unstable jobs: @@ -27,5 +27,11 @@ jobs: with: node-version: ${{ env.NODEJS_VERSION }} + - name: Use Beta Toolchain + run: rustup default beta + + - name: Setup Cross + run: cargo install cross --git https://github.com/cross-rs/cross + - name: Build And Run Tests run: make test diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 3e0029a0f..b56d1756a 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -25,9 +25,9 @@ docker buildx create --use curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh # proceed with default installation curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/master/install.sh | bash source ~/.bashrc -nvm install 22 -nvm use 22 -nvm alias default 22 # this prevents your machine from reverting back to another version +nvm install 24 +nvm use 24 +nvm alias default 24 # this prevents your machine from reverting back to another version ``` ## Cloning the repository diff --git a/Makefile b/Makefile index f7003913b..b437810a9 100644 --- a/Makefile +++ b/Makefile @@ -5,15 +5,17 @@ PLATFORM_FILE := $(shell ./check-platform.sh) ENVIRONMENT_FILE := $(shell ./check-environment.sh) GIT_HASH_FILE := $(shell ./check-git-hash.sh) VERSION_FILE := $(shell ./check-version.sh) -BASENAME := $(shell ./basename.sh) +BASENAME := $(shell PROJECT=startos ./basename.sh) PLATFORM := $(shell if [ -f ./PLATFORM.txt ]; then cat ./PLATFORM.txt; else echo unknown; fi) ARCH := $(shell if [ "$(PLATFORM)" = "raspberrypi" ]; then echo aarch64; else echo $(PLATFORM) | sed 's/-nonfree$$//g'; fi) +RUST_ARCH := $(shell if [ "$(ARCH)" = "riscv64" ]; then echo riscv64gc; else echo $(ARCH); fi) +REGISTRY_BASENAME := $(shell PROJECT=start-registry PLATFORM=$(ARCH) ./basename.sh) +TUNNEL_BASENAME := $(shell PROJECT=start-tunnel PLATFORM=$(ARCH) ./basename.sh) IMAGE_TYPE=$(shell if [ "$(PLATFORM)" = raspberrypi ]; then echo img; else echo iso; fi) WEB_UIS := web/dist/raw/ui/index.html web/dist/raw/setup-wizard/index.html web/dist/raw/install-wizard/index.html COMPRESSED_WEB_UIS := web/dist/static/ui/index.html web/dist/static/setup-wizard/index.html web/dist/static/install-wizard/index.html FIRMWARE_ROMS := ./firmware/$(PLATFORM) $(shell jq --raw-output '.[] | select(.platform[] | contains("$(PLATFORM)")) | "./firmware/$(PLATFORM)/" + .id + ".rom.gz"' build/lib/firmware.json) BUILD_SRC := $(call ls-files, build) build/lib/depends build/lib/conflicts $(FIRMWARE_ROMS) -DEBIAN_SRC := $(call ls-files, debian/) IMAGE_RECIPE_SRC := $(call ls-files, image-recipe/) STARTD_SRC := core/startos/startd.service $(BUILD_SRC) CORE_SRC := $(call ls-files, core) $(shell git ls-files --recurse-submodules patch-db) $(GIT_HASH_FILE) @@ -21,20 +23,23 @@ WEB_SHARED_SRC := $(call ls-files, web/projects/shared) $(call ls-files, web/pro WEB_UI_SRC := $(call ls-files, web/projects/ui) WEB_SETUP_WIZARD_SRC := $(call ls-files, web/projects/setup-wizard) WEB_INSTALL_WIZARD_SRC := $(call ls-files, web/projects/install-wizard) +WEB_START_TUNNEL_SRC := $(call ls-files, web/projects/start-tunnel) PATCH_DB_CLIENT_SRC := $(shell git ls-files --recurse-submodules patch-db/client) GZIP_BIN := $(shell which pigz || which gzip) TAR_BIN := $(shell which gtar || which tar) -COMPILED_TARGETS := core/target/$(ARCH)-unknown-linux-musl/$(PROFILE)/startbox core/target/$(ARCH)-unknown-linux-musl/release/containerbox container-runtime/rootfs.$(ARCH).squashfs -ALL_TARGETS := $(STARTD_SRC) $(ENVIRONMENT_FILE) $(GIT_HASH_FILE) $(VERSION_FILE) $(COMPILED_TARGETS) cargo-deps/$(ARCH)-unknown-linux-musl/release/startos-backup-fs $(PLATFORM_FILE) \ +COMPILED_TARGETS := core/target/$(RUST_ARCH)-unknown-linux-musl/$(PROFILE)/startbox core/target/$(RUST_ARCH)-unknown-linux-musl/release/containerbox container-runtime/rootfs.$(ARCH).squashfs +STARTOS_TARGETS := $(STARTD_SRC) $(ENVIRONMENT_FILE) $(GIT_HASH_FILE) $(VERSION_FILE) $(COMPILED_TARGETS) cargo-deps/$(RUST_ARCH)-unknown-linux-musl/release/startos-backup-fs $(PLATFORM_FILE) \ $(shell if [ "$(PLATFORM)" = "raspberrypi" ]; then \ echo cargo-deps/aarch64-unknown-linux-musl/release/pi-beep; \ fi) \ $(shell /bin/bash -c 'if [[ "${ENVIRONMENT}" =~ (^|-)unstable($$|-) ]]; then \ - echo cargo-deps/$(ARCH)-unknown-linux-musl/release/flamegraph; \ + echo cargo-deps/$(RUST_ARCH)-unknown-linux-musl/release/flamegraph; \ fi') \ $(shell /bin/bash -c 'if [[ "${ENVIRONMENT}" =~ (^|-)console($$|-) ]]; then \ - echo cargo-deps/$(ARCH)-unknown-linux-musl/release/tokio-console; \ + echo cargo-deps/$(RUST_ARCH)-unknown-linux-musl/release/tokio-console; \ fi') +REGISTRY_TARGETS := core/target/$(RUST_ARCH)-unknown-linux-musl/$(PROFILE)/registrybox core/startos/start-registryd.service +TUNNEL_TARGETS := core/target/$(RUST_ARCH)-unknown-linux-musl/$(PROFILE)/tunnelbox core/startos/start-tunneld.service REBUILD_TYPES = 1 ifeq ($(REMOTE),) @@ -58,12 +63,12 @@ endif .DELETE_ON_ERROR: -.PHONY: all metadata install clean format cli uis ui reflash deb $(IMAGE_TYPE) squashfs wormhole wormhole-deb test test-core test-sdk test-container-runtime registry +.PHONY: all metadata install clean format cli uis ui reflash deb $(IMAGE_TYPE) squashfs wormhole wormhole-deb test test-core test-sdk test-container-runtime registry install-registry tunnel install-tunnel -all: $(ALL_TARGETS) +all: $(STARTOS_TARGETS) touch: - touch $(ALL_TARGETS) + touch $(STARTOS_TARGETS) metadata: $(VERSION_FILE) $(PLATFORM_FILE) $(ENVIRONMENT_FILE) $(GIT_HASH_FILE) @@ -111,42 +116,74 @@ test-container-runtime: container-runtime/node_modules/.package-lock.json $(call cli: ./core/install-cli.sh -registry: - ./core/build-registrybox.sh +registry: core/target/$(RUST_ARCH)-unknown-linux-musl/$(PROFILE)/registrybox -tunnel: - ./core/build-tunnelbox.sh +install-registry: $(REGISTRY_TARGETS) + $(call mkdir,$(DESTDIR)/usr/bin) + $(call cp,core/target/$(RUST_ARCH)-unknown-linux-musl/$(PROFILE)/registrybox,$(DESTDIR)/usr/bin/start-registrybox) + $(call ln,/usr/bin/start-registrybox,$(DESTDIR)/usr/bin/start-registryd) + $(call ln,/usr/bin/start-registrybox,$(DESTDIR)/usr/bin/start-registry) + + $(call mkdir,$(DESTDIR)/lib/systemd/system) + $(call cp,core/startos/start-registryd.service,$(DESTDIR)/lib/systemd/system/start-registryd.service) + +core/target/$(RUST_ARCH)-unknown-linux-musl/$(PROFILE)/registrybox: $(CORE_SRC) $(ENVIRONMENT_FILE) + ARCH=$(ARCH) PROFILE=$(PROFILE) ./core/build-registrybox.sh + +tunnel: core/target/$(RUST_ARCH)-unknown-linux-musl/$(PROFILE)/tunnelbox + +install-tunnel: core/target/$(RUST_ARCH)-unknown-linux-musl/$(PROFILE)/tunnelbox core/startos/start-tunneld.service + $(call mkdir,$(DESTDIR)/usr/bin) + $(call cp,core/target/$(RUST_ARCH)-unknown-linux-musl/$(PROFILE)/tunnelbox,$(DESTDIR)/usr/bin/start-tunnelbox) + $(call ln,/usr/bin/start-tunnelbox,$(DESTDIR)/usr/bin/start-tunneld) + $(call ln,/usr/bin/start-tunnelbox,$(DESTDIR)/usr/bin/start-tunnel) + + $(call mkdir,$(DESTDIR)/lib/systemd/system) + $(call cp,core/startos/start-tunneld.service,$(DESTDIR)/lib/systemd/system/start-tunneld.service) + + $(call mkdir,$(DESTDIR)/usr/lib/startos/scripts) + $(call cp,build/lib/scripts/forward-port,$(DESTDIR)/usr/lib/startos/scripts/forward-port) + +core/target/$(RUST_ARCH)-unknown-linux-musl/$(PROFILE)/tunnelbox: $(CORE_SRC) $(ENVIRONMENT_FILE) $(GIT_HASH_FILE) web/dist/static/start-tunnel/index.html + ARCH=$(ARCH) PROFILE=$(PROFILE) ./core/build-tunnelbox.sh deb: results/$(BASENAME).deb -debian/control: build/lib/depends build/lib/conflicts - ./debuild/control.sh - -results/$(BASENAME).deb: dpkg-build.sh $(DEBIAN_SRC) $(ALL_TARGETS) +results/$(BASENAME).deb: dpkg-build.sh $(call ls-files,debian/startos) $(STARTOS_TARGETS) PLATFORM=$(PLATFORM) REQUIRES=debian ./build/os-compat/run-compat.sh ./dpkg-build.sh +registry-deb: results/$(REGISTRY_BASENAME).deb + +results/$(REGISTRY_BASENAME).deb: dpkg-build.sh $(call ls-files,debian/start-registry) $(REGISTRY_TARGETS) + PROJECT=start-registry PLATFORM=$(ARCH) REQUIRES=debian ./build/os-compat/run-compat.sh ./dpkg-build.sh + +tunnel-deb: results/$(TUNNEL_BASENAME).deb + +results/$(TUNNEL_BASENAME).deb: dpkg-build.sh $(call ls-files,debian/start-tunnel) $(TUNNEL_TARGETS) + PROJECT=start-tunnel PLATFORM=$(ARCH) REQUIRES=debian DEPENDS=wireguard-tools,iptables ./build/os-compat/run-compat.sh ./dpkg-build.sh + $(IMAGE_TYPE): results/$(BASENAME).$(IMAGE_TYPE) squashfs: results/$(BASENAME).squashfs results/$(BASENAME).$(IMAGE_TYPE) results/$(BASENAME).squashfs: $(IMAGE_RECIPE_SRC) results/$(BASENAME).deb - REQUIRES=debian ./build/os-compat/run-compat.sh ./image-recipe/run-local-build.sh "results/$(BASENAME).deb" + ./image-recipe/run-local-build.sh "results/$(BASENAME).deb" # For creating os images. DO NOT USE -install: $(ALL_TARGETS) +install: $(STARTOS_TARGETS) $(call mkdir,$(DESTDIR)/usr/bin) $(call mkdir,$(DESTDIR)/usr/sbin) - $(call cp,core/target/$(ARCH)-unknown-linux-musl/$(PROFILE)/startbox,$(DESTDIR)/usr/bin/startbox) + $(call cp,core/target/$(RUST_ARCH)-unknown-linux-musl/$(PROFILE)/startbox,$(DESTDIR)/usr/bin/startbox) $(call ln,/usr/bin/startbox,$(DESTDIR)/usr/bin/startd) $(call ln,/usr/bin/startbox,$(DESTDIR)/usr/bin/start-cli) if [ "$(PLATFORM)" = "raspberrypi" ]; then $(call cp,cargo-deps/aarch64-unknown-linux-musl/release/pi-beep,$(DESTDIR)/usr/bin/pi-beep); fi if /bin/bash -c '[[ "${ENVIRONMENT}" =~ (^|-)unstable($$|-) ]]'; then \ - $(call cp,cargo-deps/$(ARCH)-unknown-linux-musl/release/flamegraph,$(DESTDIR)/usr/bin/flamegraph); \ + $(call cp,cargo-deps/$(RUST_ARCH)-unknown-linux-musl/release/flamegraph,$(DESTDIR)/usr/bin/flamegraph); \ fi if /bin/bash -c '[[ "${ENVIRONMENT}" =~ (^|-)console($$|-) ]]'; then \ - $(call cp,cargo-deps/$(ARCH)-unknown-linux-musl/release/tokio-console,$(DESTDIR)/usr/bin/tokio-console); \ + $(call cp,cargo-deps/$(RUST_ARCH)-unknown-linux-musl/release/tokio-console,$(DESTDIR)/usr/bin/tokio-console); \ fi - $(call cp,cargo-deps/$(ARCH)-unknown-linux-musl/release/startos-backup-fs,$(DESTDIR)/usr/bin/startos-backup-fs) + $(call cp,cargo-deps/$(RUST_ARCH)-unknown-linux-musl/release/startos-backup-fs,$(DESTDIR)/usr/bin/startos-backup-fs) $(call ln,/usr/bin/startos-backup-fs,$(DESTDIR)/usr/sbin/mount.backup-fs) $(call mkdir,$(DESTDIR)/lib/systemd/system) @@ -165,7 +202,7 @@ install: $(ALL_TARGETS) $(call cp,firmware/$(PLATFORM),$(DESTDIR)/usr/lib/startos/firmware) -update-overlay: $(ALL_TARGETS) +update-overlay: $(STARTOS_TARGETS) @echo "\033[33m!!! THIS WILL ONLY REFLASH YOUR DEVICE IN MEMORY !!!\033[0m" @echo "\033[33mALL CHANGES WILL BE REVERTED IF YOU RESTART THE DEVICE\033[0m" @if [ -z "$(REMOTE)" ]; then >&2 echo "Must specify REMOTE" && false; fi @@ -174,10 +211,10 @@ update-overlay: $(ALL_TARGETS) $(MAKE) install REMOTE=$(REMOTE) SSHPASS=$(SSHPASS) PLATFORM=$(PLATFORM) $(call ssh,"sudo systemctl start startd") -wormhole: core/target/$(ARCH)-unknown-linux-musl/$(PROFILE)/startbox +wormhole: core/target/$(RUST_ARCH)-unknown-linux-musl/$(PROFILE)/startbox @echo "Paste the following command into the shell of your StartOS server:" @echo - @wormhole send core/target/$(ARCH)-unknown-linux-musl/$(PROFILE)/startbox 2>&1 | awk -Winteractive '/wormhole receive/ { printf "sudo /usr/lib/startos/scripts/chroot-and-upgrade \"cd /usr/bin && rm startbox && wormhole receive --accept-file %s && chmod +x startbox\"\n", $$3 }' + @wormhole send core/target/$(RUST_ARCH)-unknown-linux-musl/$(PROFILE)/startbox 2>&1 | awk -Winteractive '/wormhole receive/ { printf "sudo /usr/lib/startos/scripts/chroot-and-upgrade \"cd /usr/bin && rm startbox && wormhole receive --accept-file %s && chmod +x startbox\"\n", $$3 }' wormhole-deb: results/$(BASENAME).deb @echo "Paste the following command into the shell of your StartOS server:" @@ -191,16 +228,16 @@ wormhole-squashfs: results/$(BASENAME).squashfs @echo @wormhole send results/$(BASENAME).squashfs 2>&1 | awk -Winteractive '/wormhole receive/ { printf "sudo sh -c '"'"'/usr/lib/startos/scripts/prune-images $(SQFS_SIZE) && /usr/lib/startos/scripts/prune-boot && cd /media/startos/images && wormhole receive --accept-file %s && CHECKSUM=$(SQFS_SUM) /usr/lib/startos/scripts/use-img ./$(BASENAME).squashfs'"'"'\n", $$3 }' -update: $(ALL_TARGETS) +update: $(STARTOS_TARGETS) @if [ -z "$(REMOTE)" ]; then >&2 echo "Must specify REMOTE" && false; fi $(call ssh,'sudo /usr/lib/startos/scripts/chroot-and-upgrade --create') $(MAKE) install REMOTE=$(REMOTE) SSHPASS=$(SSHPASS) DESTDIR=/media/startos/next PLATFORM=$(PLATFORM) $(call ssh,'sudo /media/startos/next/usr/lib/startos/scripts/chroot-and-upgrade --no-sync "apt-get install -y $(shell cat ./build/lib/depends)"') -update-startbox: core/target/$(ARCH)-unknown-linux-musl/$(PROFILE)/startbox # only update binary (faster than full update) +update-startbox: core/target/$(RUST_ARCH)-unknown-linux-musl/$(PROFILE)/startbox # only update binary (faster than full update) @if [ -z "$(REMOTE)" ]; then >&2 echo "Must specify REMOTE" && false; fi $(call ssh,'sudo /usr/lib/startos/scripts/chroot-and-upgrade --create') - $(call cp,core/target/$(ARCH)-unknown-linux-musl/$(PROFILE)/startbox,/media/startos/next/usr/bin/startbox) + $(call cp,core/target/$(RUST_ARCH)-unknown-linux-musl/$(PROFILE)/startbox,/media/startos/next/usr/bin/startbox) $(call ssh,'sudo /media/startos/next/usr/lib/startos/scripts/chroot-and-upgrade --no-sync true') update-deb: results/$(BASENAME).deb # better than update, but only available from debian @@ -219,7 +256,7 @@ update-squashfs: results/$(BASENAME).squashfs $(call cp,results/$(BASENAME).squashfs,/media/startos/images/next.rootfs) $(call ssh,'sudo CHECKSUM=$(SQFS_SUM) /usr/lib/startos/scripts/use-img /media/startos/images/next.rootfs') -emulate-reflash: $(ALL_TARGETS) +emulate-reflash: $(STARTOS_TARGETS) @if [ -z "$(REMOTE)" ]; then >&2 echo "Must specify REMOTE" && false; fi $(call ssh,'sudo /usr/lib/startos/scripts/chroot-and-upgrade --create') $(MAKE) install REMOTE=$(REMOTE) SSHPASS=$(SSHPASS) DESTDIR=/media/startos/next PLATFORM=$(PLATFORM) @@ -265,22 +302,22 @@ container-runtime/dist/node_modules/.package-lock.json container-runtime/dist/pa ./container-runtime/install-dist-deps.sh touch container-runtime/dist/node_modules/.package-lock.json -container-runtime/rootfs.$(ARCH).squashfs: container-runtime/debian.$(ARCH).squashfs container-runtime/container-runtime.service container-runtime/update-image.sh container-runtime/deb-install.sh container-runtime/dist/index.js container-runtime/dist/node_modules/.package-lock.json core/target/$(ARCH)-unknown-linux-musl/release/containerbox +container-runtime/rootfs.$(ARCH).squashfs: container-runtime/debian.$(ARCH).squashfs container-runtime/container-runtime.service container-runtime/update-image.sh container-runtime/deb-install.sh container-runtime/dist/index.js container-runtime/dist/node_modules/.package-lock.json core/target/$(RUST_ARCH)-unknown-linux-musl/release/containerbox ARCH=$(ARCH) REQUIRES=linux ./build/os-compat/run-compat.sh ./container-runtime/update-image.sh -build/lib/depends build/lib/conflicts: $(ENVIRONMENT_FILE) build/dpkg-deps/* - build/dpkg-deps/generate.sh +build/lib/depends build/lib/conflicts: $(ENVIRONMENT_FILE) $(PLATFORM_FILE) $(shell ls build/dpkg-deps/*) + PLATFORM=$(PLATFORM) ARCH=$(ARCH) build/dpkg-deps/generate.sh $(FIRMWARE_ROMS): build/lib/firmware.json download-firmware.sh $(PLATFORM_FILE) ./download-firmware.sh $(PLATFORM) -core/target/$(ARCH)-unknown-linux-musl/$(PROFILE)/startbox: $(CORE_SRC) $(COMPRESSED_WEB_UIS) web/patchdb-ui-seed.json $(ENVIRONMENT_FILE) +core/target/$(RUST_ARCH)-unknown-linux-musl/$(PROFILE)/startbox: $(CORE_SRC) $(COMPRESSED_WEB_UIS) web/patchdb-ui-seed.json $(ENVIRONMENT_FILE) ARCH=$(ARCH) PROFILE=$(PROFILE) ./core/build-startbox.sh - touch core/target/$(ARCH)-unknown-linux-musl/$(PROFILE)/startbox + touch core/target/$(RUST_ARCH)-unknown-linux-musl/$(PROFILE)/startbox -core/target/$(ARCH)-unknown-linux-musl/release/containerbox: $(CORE_SRC) $(ENVIRONMENT_FILE) +core/target/$(RUST_ARCH)-unknown-linux-musl/release/containerbox: $(CORE_SRC) $(ENVIRONMENT_FILE) ARCH=$(ARCH) ./core/build-containerbox.sh - touch core/target/$(ARCH)-unknown-linux-musl/release/containerbox + touch core/target/$(RUST_ARCH)-unknown-linux-musl/release/containerbox web/package-lock.json: web/package.json sdk/baseDist/package.json npm --prefix web i @@ -307,8 +344,12 @@ web/dist/raw/install-wizard/index.html: $(WEB_INSTALL_WIZARD_SRC) $(WEB_SHARED_S npm --prefix web run build:install touch web/dist/raw/install-wizard/index.html -$(COMPRESSED_WEB_UIS): $(WEB_UIS) $(ENVIRONMENT_FILE) - ./compress-uis.sh +web/dist/raw/start-tunnel/index.html: $(WEB_START_TUNNEL_SRC) $(WEB_SHARED_SRC) web/.angular/.updated + npm --prefix web run build:tunnel + touch web/dist/raw/start-tunnel/index.html + +web/dist/static/%/index.html: web/dist/raw/%/index.html + ./compress-uis.sh $* web/config.json: $(GIT_HASH_FILE) web/config-sample.json jq '.useMocks = false' web/config-sample.json | jq '.gitHash = "$(shell cat GIT_HASH.txt)"' > web/config.json @@ -335,11 +376,11 @@ ui: web/dist/raw/ui cargo-deps/aarch64-unknown-linux-musl/release/pi-beep: ARCH=aarch64 ./build-cargo-dep.sh pi-beep -cargo-deps/$(ARCH)-unknown-linux-musl/release/tokio-console: +cargo-deps/$(RUST_ARCH)-unknown-linux-musl/release/tokio-console: ARCH=$(ARCH) PREINSTALL="apk add musl-dev pkgconfig" ./build-cargo-dep.sh tokio-console -cargo-deps/$(ARCH)-unknown-linux-musl/release/startos-backup-fs: +cargo-deps/$(RUST_ARCH)-unknown-linux-musl/release/startos-backup-fs: ARCH=$(ARCH) PREINSTALL="apk add fuse3 fuse3-dev fuse3-static musl-dev pkgconfig" ./build-cargo-dep.sh --git https://github.com/Start9Labs/start-fs.git startos-backup-fs -cargo-deps/$(ARCH)-unknown-linux-musl/release/flamegraph: +cargo-deps/$(RUST_ARCH)-unknown-linux-musl/release/flamegraph: ARCH=$(ARCH) PREINSTALL="apk add musl-dev pkgconfig" ./build-cargo-dep.sh flamegraph \ No newline at end of file diff --git a/START-TUNNEL.md b/START-TUNNEL.md new file mode 100644 index 000000000..1fea658bb --- /dev/null +++ b/START-TUNNEL.md @@ -0,0 +1,59 @@ +# StartTunnel + +A self-hosted Wiregaurd VPN optimized for creating VLANs and reverse tunneling to personal servers. + +You can think of StartTunnel as "virtual router in the cloud" + +Use it for private, remote access, to self-hosted services running on a personal server, or to expose self-hosted services to the public Internet without revealing the host server's IP address. + +## Installation + +1. Rent a low cost VPS. For most use cases, the cheapest option should be enough. + + - It must have a dedicated public IP address. + - For (CPU), memory (RAM), and storage (disk), choose the minimum spec. + - For transfer (bandwidth), it depends on (1) your use case and (2) your home Internet's _upload_ speed. Even if you intend to serve large files or stream content from your server, there is no reason to pay for speeds that exceed your home Internet's upload speed. + +1. Provision the VPS with the latest version of Debian. + +1. Access the VPS via SSH. + +1. Install StartTunnel: + + @TODO + +## Features + +- **Create Subnets**: Each subnet creates a private, virtual local area network (VLAN), similar to the LAN created by a home router. + +- **Add Devices**: When you add a device (server, phone, laptop) to a subnet, it receives a LAN IP address on that subnet as well as a unique Wireguard config that must be copied, downloaded, or scanned into the device. + +- **Forward Ports**: Forwarding a port creates a "reverse tunnel", exposing a specific port on a specific device to the public Internet. + +## CLI + +By default, StartTunnel is managed via the `start-tunnel` command line interface, which is self-documented. + +``` +start-tunnel --help +``` + +## Web Interface + +If you choose to enable the web interface (recommended in most cases), StartTunnel can be accessed as a website from the browser, or programmatically via API. + +1. Initialize the web interface. + + start-tunnel web init + +1. When prompted, select the IP address at which to host the web interface. In many cases, there will be only one IP address. + +1. When prompted, enter the port at which to host the web interface. The default is 8443, and we recommend using it. If you change the default, choose an uncommon port to avoid conflicts. + +1. Select whether to autogenerate a self-signed certificate or provide your own certificate and key. If you choose to autogenerate, you will be asked to list all IP addresses and domains for which to sign the certificate. For example, if you intend to access your StartTunnel web UI at a domain, include the domain in the list. + +1. You will receive a success message that the webserver is running at the chosen IP:port, as well as your SSL certificate and an autogenerated UI password. + +1. If not already, trust the certificate in your system keychain and/or browser. + +1. If you lose/forget your password, you can reset it using the CLI. diff --git a/basename.sh b/basename.sh index 679faa5bc..fd5bd759d 100755 --- a/basename.sh +++ b/basename.sh @@ -1,5 +1,7 @@ #!/bin/bash +PROJECT=${PROJECT:-"startos"} + cd "$(dirname "${BASH_SOURCE[0]}")" PLATFORM="$(if [ -f ./PLATFORM.txt ]; then cat ./PLATFORM.txt; else echo unknown; fi)" @@ -16,4 +18,4 @@ if [ -n "$STARTOS_ENV" ]; then VERSION_FULL="$VERSION_FULL~${STARTOS_ENV}" fi -echo -n "startos-${VERSION_FULL}_${PLATFORM}" \ No newline at end of file +echo -n "${PROJECT}-${VERSION_FULL}_${PLATFORM}" \ No newline at end of file diff --git a/build/dpkg-deps/depends b/build/dpkg-deps/depends index 8593bc733..9703cc99e 100644 --- a/build/dpkg-deps/depends +++ b/build/dpkg-deps/depends @@ -9,7 +9,6 @@ ca-certificates cifs-utils cryptsetup curl -dnsutils dmidecode dnsutils dosfstools @@ -19,6 +18,8 @@ exfatprogs flashrom fuse3 grub-common +grub-efi +grub2-common htop httpdirfs iotop @@ -41,7 +42,6 @@ nvme-cli nyx openssh-server podman -postgresql psmisc qemu-guest-agent rfkill diff --git a/build/dpkg-deps/generate.sh b/build/dpkg-deps/generate.sh index 6aafeefc3..7f1c2dcae 100755 --- a/build/dpkg-deps/generate.sh +++ b/build/dpkg-deps/generate.sh @@ -5,11 +5,15 @@ set -e cd "$(dirname "${BASH_SOURCE[0]}")" IFS="-" read -ra FEATURES <<< "$ENVIRONMENT" +FEATURES+=("${ARCH}") +if [ "$ARCH" != "$PLATFORM" ]; then + FEATURES+=("${PLATFORM}") +fi feature_file_checker=' /^#/ { next } -/^\+ [a-z0-9-]+$/ { next } -/^- [a-z0-9-]+$/ { next } +/^\+ [a-z0-9.-]+$/ { next } +/^- [a-z0-9.-]+$/ { next } { exit 1 } ' @@ -30,8 +34,8 @@ for type in conflicts depends; do for feature in ${FEATURES[@]}; do file="$feature.$type" if [ -f $file ]; then - if grep "^- $pkg$" $file; then - SKIP=1 + if grep "^- $pkg$" $file > /dev/null; then + SKIP=yes fi fi done diff --git a/build/dpkg-deps/raspberrypi.depends b/build/dpkg-deps/raspberrypi.depends new file mode 100644 index 000000000..95673daea --- /dev/null +++ b/build/dpkg-deps/raspberrypi.depends @@ -0,0 +1,12 @@ +- grub-common +- grub-efi +- grub2-common ++ parted ++ raspberrypi-net-mods ++ raspberrypi-sys-mods ++ raspi-config ++ raspi-firmware ++ raspi-utils ++ rpi-eeprom ++ rpi-update ++ rpi.gpio-common \ No newline at end of file diff --git a/build/dpkg-deps/x86_64.depends b/build/dpkg-deps/x86_64.depends new file mode 100644 index 000000000..f6773627f --- /dev/null +++ b/build/dpkg-deps/x86_64.depends @@ -0,0 +1 @@ ++ grub-pc-bin \ No newline at end of file diff --git a/build/lib/scripts/enable-kiosk b/build/lib/scripts/enable-kiosk index 769a139e0..56baebd50 100755 --- a/build/lib/scripts/enable-kiosk +++ b/build/lib/scripts/enable-kiosk @@ -64,9 +64,11 @@ user_pref("messaging-system.rsexperimentloader.enabled", false); user_pref("network.allow-experiments", false); user_pref("network.captive-portal-service.enabled", false); user_pref("network.connectivity-service.enabled", false); -user_pref("network.proxy.autoconfig_url", "file:///usr/lib/startos/proxy.pac"); +user_pref("network.proxy.socks", "10.0.3.1"); +user_pref("network.proxy.socks_port", 9050); +user_pref("network.proxy.socks_version", 5); user_pref("network.proxy.socks_remote_dns", true); -user_pref("network.proxy.type", 2); +user_pref("network.proxy.type", 1); user_pref("privacy.resistFingerprinting", true); //Enable letterboxing if we want the window size sent to the server to snap to common resolutions: //user_pref("privacy.resistFingerprinting.letterboxing", true); diff --git a/build/lib/scripts/forward-port b/build/lib/scripts/forward-port index 7b8aedac9..8152c6b7a 100755 --- a/build/lib/scripts/forward-port +++ b/build/lib/scripts/forward-port @@ -1,26 +1,38 @@ #!/bin/bash -if [ -z "$iiface" ] || [ -z "$oiface" ] || [ -z "$sip" ] || [ -z "$dip" ] || [ -z "$sport" ] || [ -z "$dport" ]; then +if [ -z "$sip" ] || [ -z "$dip" ] || [ -z "$sport" ] || [ -z "$dport" ]; then >&2 echo 'missing required env var' exit 1 fi -kind="-A" +# Helper function to check if a rule exists +nat_rule_exists() { + iptables -t nat -C "$@" 2>/dev/null +} + +# Helper function to add or delete a rule idempotently +# Usage: apply_rule [add|del] +apply_nat_rule() { + local action="$1" + shift + + if [ "$action" = "add" ]; then + # Only add if rule doesn't exist + if ! rule_exists "$@"; then + iptables -t nat -A "$@" + fi + elif [ "$action" = "del" ]; then + if rule_exists "$@"; then + iptables -t nat -D "$@" + fi + fi +} if [ "$UNDO" = 1 ]; then - kind="-D" + action="del" +else + action="add" fi -iptables -t nat "$kind" POSTROUTING -o $iiface -j MASQUERADE -iptables -t nat "$kind" PREROUTING -i $iiface -p tcp --dport $sport -j DNAT --to-destination $dip:$dport -iptables -t nat "$kind" PREROUTING -i $iiface -p udp --dport $sport -j DNAT --to-destination $dip:$dport -iptables -t nat "$kind" PREROUTING -i $oiface -s $dip/24 -d $sip -p tcp --dport $sport -j DNAT --to-destination $dip:$dport -iptables -t nat "$kind" PREROUTING -i $oiface -s $dip/24 -d $sip -p udp --dport $sport -j DNAT --to-destination $dip:$dport -iptables -t nat "$kind" POSTROUTING -o $oiface -s $dip/24 -d $dip/32 -p tcp --dport $dport -j SNAT --to-source $sip:$sport -iptables -t nat "$kind" POSTROUTING -o $oiface -s $dip/24 -d $dip/32 -p udp --dport $dport -j SNAT --to-source $sip:$sport - - -iptables -t nat "$kind" PREROUTING -i $iiface -s $sip/32 -d $sip -p tcp --dport $sport -j DNAT --to-destination $dip:$dport -iptables -t nat "$kind" PREROUTING -i $iiface -s $sip/32 -d $sip -p udp --dport $sport -j DNAT --to-destination $dip:$dport -iptables -t nat "$kind" POSTROUTING -o $oiface -s $sip/32 -d $dip/32 -p tcp --dport $dport -j SNAT --to-source $sip:$sport -iptables -t nat "$kind" POSTROUTING -o $oiface -s $sip/32 -d $dip/32 -p udp --dport $dport -j SNAT --to-source $sip:$sport \ No newline at end of file +apply_nat_rule "$action" PREROUTING -p tcp -d $sip --dport $sport -j DNAT --to-destination $dip:$dport +apply_nat_rule "$action" OUTPUT -p tcp -d $sip --dport $sport -j DNAT --to-destination $dip:$dport \ No newline at end of file diff --git a/build/lib/scripts/startos-initramfs-module b/build/lib/scripts/startos-initramfs-module index e13c887e2..f093328cc 100755 --- a/build/lib/scripts/startos-initramfs-module +++ b/build/lib/scripts/startos-initramfs-module @@ -83,6 +83,7 @@ local_mount_root() if [ -d "$image" ]; then mount -r --bind $image /lower elif [ -f "$image" ]; then + modprobe loop modprobe squashfs mount -r $image /lower else diff --git a/build/os-compat/run-compat.sh b/build/os-compat/run-compat.sh index ff04217ba..2151fd1b2 100755 --- a/build/os-compat/run-compat.sh +++ b/build/os-compat/run-compat.sh @@ -18,7 +18,7 @@ if [ "$FORCE_COMPAT" = 1 ] || ( [ "$REQUIRES" = "linux" ] && [ "$(uname -s)" != docker run -d --rm --name os-compat --privileged --security-opt apparmor=unconfined -v "${project_pwd}:/root/start-os" -v /lib/modules:/lib/modules:ro start9/build-env while ! docker exec os-compat systemctl is-active --quiet multi-user.target 2> /dev/null; do sleep .5; done - docker exec -eARCH -eENVIRONMENT -ePLATFORM -eGIT_BRANCH_AS_HASH $USE_TTY -w "/root/start-os${rel_pwd}" os-compat $@ + docker exec -eARCH -eENVIRONMENT -ePLATFORM -eGIT_BRANCH_AS_HASH -ePROJECT -eDEPENDS -eCONFLICTS $USE_TTY -w "/root/start-os${rel_pwd}" os-compat $@ code=$? docker stop os-compat exit $code diff --git a/compress-uis.sh b/compress-uis.sh index 3ca6cccf0..91048d19f 100755 --- a/compress-uis.sh +++ b/compress-uis.sh @@ -4,13 +4,17 @@ cd "$(dirname "${BASH_SOURCE[0]}")" set -e -rm -rf web/dist/static +STATIC_DIR=web/dist/static/$1 +RAW_DIR=web/dist/raw/$1 + +mkdir -p $STATIC_DIR +rm -rf $STATIC_DIR if ! [[ "$ENVIRONMENT" =~ (^|-)dev($|-) ]]; then - find web/dist/raw -type f -not -name '*.gz' -and -not -name '*.br' | xargs -n 1 -P 0 gzip -kf - find web/dist/raw -type f -not -name '*.gz' -and -not -name '*.br' | xargs -n 1 -P 0 brotli -kf + find $RAW_DIR -type f -not -name '*.gz' -and -not -name '*.br' | xargs -n 1 -P 0 gzip -kf + find $RAW_DIR -type f -not -name '*.gz' -and -not -name '*.br' | xargs -n 1 -P 0 brotli -kf - for file in $(find web/dist/raw -type f -not -name '*.gz' -and -not -name '*.br'); do + for file in $(find $RAW_DIR -type f -not -name '*.gz' -and -not -name '*.br'); do raw_size=$(du $file | awk '{print $1 * 512}') gz_size=$(du $file.gz | awk '{print $1 * 512}') br_size=$(du $file.br | awk '{print $1 * 512}') @@ -23,4 +27,5 @@ if ! [[ "$ENVIRONMENT" =~ (^|-)dev($|-) ]]; then done fi -cp -r web/dist/raw web/dist/static \ No newline at end of file + +cp -r $RAW_DIR $STATIC_DIR \ No newline at end of file diff --git a/container-runtime/deb-install.sh b/container-runtime/deb-install.sh index 688bd1003..0668b0c22 100644 --- a/container-runtime/deb-install.sh +++ b/container-runtime/deb-install.sh @@ -2,17 +2,11 @@ set -e - mkdir -p /run/systemd/resolve echo "nameserver 8.8.8.8" > /run/systemd/resolve/stub-resolv.conf apt-get update -apt-get install -y curl rsync qemu-user-static - -curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash -source ~/.bashrc -nvm install 22 -ln -s $(which node) /usr/bin/node +apt-get install -y curl rsync qemu-user-static nodejs sed -i '/\(^\|#\)DNSStubListener=/c\DNSStubListener=no' /etc/systemd/resolved.conf sed -i '/\(^\|#\)Storage=/c\Storage=persistent' /etc/systemd/journald.conf @@ -24,5 +18,5 @@ systemctl enable container-runtime.service rm -rf /run/systemd -rm /etc/resolv.conf +rm -f /etc/resolv.conf echo "nameserver 10.0.3.1" > /etc/resolv.conf \ No newline at end of file diff --git a/container-runtime/download-base-image.sh b/container-runtime/download-base-image.sh index c3ed51b64..dc02fac12 100755 --- a/container-runtime/download-base-image.sh +++ b/container-runtime/download-base-image.sh @@ -3,7 +3,7 @@ cd "$(dirname "${BASH_SOURCE[0]}")" set -e DISTRO=debian -VERSION=bookworm +VERSION=trixie ARCH=${ARCH:-$(uname -m)} FLAVOR=default diff --git a/container-runtime/package-lock.json b/container-runtime/package-lock.json index fa5ef919c..8f2bc713f 100644 --- a/container-runtime/package-lock.json +++ b/container-runtime/package-lock.json @@ -38,7 +38,7 @@ }, "../sdk/dist": { "name": "@start9labs/start-sdk", - "version": "0.4.0-beta.41", + "version": "0.4.0-beta.42", "license": "MIT", "dependencies": { "@iarna/toml": "^3.0.0", @@ -110,6 +110,7 @@ "integrity": "sha512-l+lkXCHS6tQEc5oUpK28xBOZ6+HwaH7YwoYQbLFiYb4nS2/l1tKnZEtEWkD0GuiYdvArf9qBS0XlQGXzPMsNqQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.26.2", @@ -1200,6 +1201,7 @@ "dev": true, "hasInstallScript": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "@swc/counter": "^0.1.3", "@swc/types": "^0.1.17" @@ -2143,6 +2145,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001688", "electron-to-chromium": "^1.5.73", @@ -3990,6 +3993,7 @@ "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@jest/core": "^29.7.0", "@jest/types": "^29.6.3", @@ -6556,6 +6560,7 @@ "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" diff --git a/container-runtime/update-image.sh b/container-runtime/update-image.sh index 0a8ca4ec9..287117f46 100755 --- a/container-runtime/update-image.sh +++ b/container-runtime/update-image.sh @@ -4,6 +4,11 @@ cd "$(dirname "${BASH_SOURCE[0]}")" set -e +RUST_ARCH="$ARCH" +if [ "$ARCH" = "riscv64" ]; then + RUST_ARCH="riscv64gc" +fi + if mountpoint -q tmp/combined; then sudo umount -R tmp/combined; fi if mountpoint -q tmp/lower; then sudo umount tmp/lower; fi sudo rm -rf tmp @@ -39,7 +44,7 @@ sudo cp container-runtime.service tmp/combined/lib/systemd/system/container-runt sudo chown 0:0 tmp/combined/lib/systemd/system/container-runtime.service sudo cp container-runtime-failure.service tmp/combined/lib/systemd/system/container-runtime-failure.service sudo chown 0:0 tmp/combined/lib/systemd/system/container-runtime-failure.service -sudo cp ../core/target/$ARCH-unknown-linux-musl/release/containerbox tmp/combined/usr/bin/start-container +sudo cp ../core/target/${RUST_ARCH}-unknown-linux-musl/release/containerbox tmp/combined/usr/bin/start-container echo -e '#!/bin/bash\nexec start-container "$@"' | sudo tee tmp/combined/usr/bin/start-cli # TODO: remove sudo chmod +x tmp/combined/usr/bin/start-cli sudo chown 0:0 tmp/combined/usr/bin/start-container diff --git a/core/Cargo.lock b/core/Cargo.lock index 69515d048..6475294c7 100644 --- a/core/Cargo.lock +++ b/core/Cargo.lock @@ -4,9 +4,9 @@ version = 4 [[package]] name = "addr2line" -version = "0.24.2" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" dependencies = [ "gimli", ] @@ -60,7 +60,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ "cfg-if", - "getrandom 0.3.3", "once_cell", "version_check", "zerocopy", @@ -68,9 +67,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] @@ -106,7 +105,7 @@ dependencies = [ "amplify_num", "ascii", "getrandom 0.2.16", - "getrandom 0.3.3", + "getrandom 0.3.4", "wasm-bindgen", ] @@ -142,12 +141,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - [[package]] name = "android_system_properties" version = "0.1.5" @@ -164,19 +157,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] -name = "ansi-width" +name = "ansi-regex" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "219e3ce6f2611d83b51ec2098a12702112c29e57203a6b0a0929b2cddb486608" +checksum = "74e74db1232b47053a58c3b009baf5d07cdb83354058af912eb6a30745c29081" dependencies = [ - "unicode-width 0.1.14", + "regex", ] [[package]] name = "anstream" -version = "0.6.20" +version = "0.6.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ae563653d1938f79b1ab1b5e668c87c76a9930414574a6583a7b7e11a8e6192" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" dependencies = [ "anstyle", "anstyle-parse", @@ -189,9 +182,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.11" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" [[package]] name = "anstyle-parse" @@ -224,9 +217,18 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.99" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" + +[[package]] +name = "ar_archive_writer" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0c269894b6fe5e9d7ada0cf69b5bf847ff35bc25fc271f08e1d080fce80339a" +dependencies = [ + "object 0.32.2", +] [[package]] name = "arbitrary" @@ -239,9 +241,9 @@ dependencies = [ [[package]] name = "archery" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae2ed21cd55021f05707a807a5fc85695dafb98832921f6cfa06db67ca5b869" +checksum = "70e0a5f99dfebb87bb342d0f53bb92c81842e100bbb915223e38349580e5441d" [[package]] name = "arrayref" @@ -270,7 +272,7 @@ dependencies = [ "cfg-if", "derive-deftly 1.2.0", "derive_builder_fork_arti", - "derive_more", + "derive_more 2.0.1", "educe", "fs-mistrust", "futures", @@ -283,7 +285,7 @@ dependencies = [ "rand 0.9.2", "safelog", "serde", - "thiserror 2.0.16", + "thiserror 2.0.17", "time", "tor-async-utils", "tor-basic-utils", @@ -354,7 +356,7 @@ dependencies = [ "nom 7.1.3", "num-traits", "rusticata-macros", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] @@ -365,7 +367,7 @@ checksum = "965c2d33e53cb6b267e148a4cb0760bc01f4904c1cd4bb4002a085bb016d1490" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", "synstructure", ] @@ -377,7 +379,7 @@ checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", "synstructure", ] @@ -389,7 +391,7 @@ checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -401,7 +403,7 @@ checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" [[package]] name = "async-acme" version = "0.6.0" -source = "git+https://github.com/dr-bonez/async-acme.git#0ddf25152237b5fc1726d977a7931e44513ce309" +source = "git+https://github.com/dr-bonez/async-acme.git#d22a20f9ac0a5dafb8fb383958b12bf6f4151833" dependencies = [ "async-trait", "base64 0.22.1", @@ -411,8 +413,8 @@ dependencies = [ "pem", "rcgen", "ring", - "rustls 0.23.31", - "rustls-pemfile 2.2.0", + "rustls 0.23.35", + "rustls-pemfile", "serde", "serde_json", "thiserror 1.0.69", @@ -457,27 +459,23 @@ dependencies = [ [[package]] name = "async-compression" -version = "0.4.19" +version = "0.4.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06575e6a9673580f52661c92107baabffbf41e2141373441cbcdc47cb733003c" +checksum = "5a89bce6054c720275ac2432fbba080a66a2106a44a1b804553930ca6909f4e0" dependencies = [ - "brotli", - "flate2", + "compression-codecs", + "compression-core", "futures-core", "futures-io", - "memchr", "pin-project-lite", "tokio", - "xz2", - "zstd", - "zstd-safe", ] [[package]] name = "async-executor" -version = "1.13.2" +version = "1.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb812ffb58524bdd10860d7d974e2f01cc0950c2438a74ee5ec2e2280c6c4ffa" +checksum = "497c00e0fd83a72a79a39fcbd8e3e2f055d6f6c7e025f3b3d91f4f8e76527fb8" dependencies = [ "async-task", "concurrent-queue 2.5.0", @@ -504,20 +502,20 @@ dependencies = [ [[package]] name = "async-io" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19634d6336019ef220f09fd31168ce5c184b295cbf80345437cc36094ef223ca" +checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc" dependencies = [ - "async-lock", + "autocfg", "cfg-if", "concurrent-queue 2.5.0", "futures-io", "futures-lite", "parking", "polling", - "rustix 1.0.8", + "rustix 1.1.2", "slab", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -545,9 +543,9 @@ dependencies = [ [[package]] name = "async-process" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65daa13722ad51e6ab1a1b9c01299142bc75135b337923cfa10e79bbbd669f00" +checksum = "fc50921ec0055cdd8a16de48773bfeec5c972598674347252c0399676be7da75" dependencies = [ "async-channel 2.5.0", "async-io", @@ -558,7 +556,7 @@ dependencies = [ "cfg-if", "event-listener 5.4.1", "futures-lite", - "rustix 1.0.8", + "rustix 1.1.2", ] [[package]] @@ -569,14 +567,14 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] name = "async-signal" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f567af260ef69e1d52c2b560ce0ea230763e6fbb9214a85d768760a920e3e3c1" +checksum = "43c070bbf59cd3570b6b2dd54cd772527c7c3620fce8be898406dd3ed6adc64c" dependencies = [ "async-io", "async-lock", @@ -584,10 +582,10 @@ dependencies = [ "cfg-if", "futures-core", "futures-io", - "rustix 1.0.8", + "rustix 1.1.2", "signal-hook-registry", "slab", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -636,7 +634,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -653,7 +651,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -723,9 +721,9 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "aws-lc-rs" -version = "1.13.3" +version = "1.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c953fe1ba023e6b7730c0d4b031d06f267f23a46167dcbd40316644b10a17ba" +checksum = "879b6c89592deb404ba4dc0ae6b58ffd1795c78991cbb5b8bc441c48a070440d" dependencies = [ "aws-lc-sys", "zeroize", @@ -733,9 +731,9 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.30.0" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbfd150b5dbdb988bcc8fb1fe787eb6b7ee6180ca24da683b61ea5405f3d43ff" +checksum = "107a4e9d9cab9963e04e84bb8dee0e25f2a987f9a8bad5ed054abd439caa8f8c" dependencies = [ "bindgen", "cc", @@ -773,11 +771,11 @@ dependencies = [ [[package]] name = "axum" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "021e862c184ae977658b36c4500f7feac3221ca5da43e3f25bd04ab6c79a29b5" +checksum = "8a18ed336352031311f4e0b4dd2ff392d4fbb370777c9d18d7fc9d7359f73871" dependencies = [ - "axum-core 0.5.2", + "axum-core 0.5.5", "base64 0.22.1", "bytes", "form_urlencoded", @@ -793,15 +791,14 @@ dependencies = [ "mime", "percent-encoding", "pin-project-lite", - "rustversion", - "serde", + "serde_core", "serde_json", "serde_path_to_error", "serde_urlencoded", "sha1", "sync_wrapper", "tokio", - "tokio-tungstenite", + "tokio-tungstenite 0.28.0", "tower 0.5.2", "tower-layer", "tower-service", @@ -830,9 +827,9 @@ dependencies = [ [[package]] name = "axum-core" -version = "0.5.2" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68464cd0412f486726fb3373129ef5d2993f90c34bc2bc1c1e9943b2f4fc7ca6" +checksum = "59446ce19cd142f8833f856eb31f3eb097812d1479ab224f54d72428ca21ea22" dependencies = [ "bytes", "futures-core", @@ -841,44 +838,34 @@ dependencies = [ "http-body-util", "mime", "pin-project-lite", - "rustversion", "sync_wrapper", "tower-layer", "tower-service", "tracing", ] -[[package]] -name = "backhand" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81e407ed987e67ac147f68f801e84a7628107acae7ac98439ee0c39d33c599dd" -dependencies = [ - "deku", - "flate2", - "lz4_flex", - "solana-nohash-hasher", - "thiserror 2.0.16", - "tracing", - "xxhash-rust", - "xz2", - "zstd", - "zstd-safe", -] - [[package]] name = "backtrace" -version = "0.3.75" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" +checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" dependencies = [ "addr2line", "cfg-if", "libc", "miniz_oxide", - "object", + "object 0.37.3", "rustc-demangle", - "windows-targets 0.52.6", + "windows-link 0.2.1", +] + +[[package]] +name = "backtrace-ext" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "537beee3be4a18fb023b570f80e3ae28003db9167a751266b259926e25539d50" +dependencies = [ + "backtrace", ] [[package]] @@ -909,12 +896,24 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" +[[package]] +name = "base32" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23ce669cd6c8588f79e15cf450314f9638f967fc5770ff1c7c1deb0925ea7cfa" + [[package]] name = "base32" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "022dfe9eb35f19ebbcb51e0b40a5ab759f46ad60cadf7297e0bd085afb50e076" +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + [[package]] name = "base64" version = "0.21.7" @@ -975,16 +974,14 @@ dependencies = [ [[package]] name = "bindgen" -version = "0.69.5" +version = "0.72.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" +checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.10.0", "cexpr", "clang-sys", - "itertools 0.12.1", - "lazy_static", - "lazycell", + "itertools 0.13.0", "log", "prettyplease", "proc-macro2", @@ -992,8 +989,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.106", - "which", + "syn 2.0.108", ] [[package]] @@ -1034,9 +1030,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.3" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34efbcccd345379ca2868b2b2c9d3782e9cc58ba87bc7d79d5b53d9c9ae6f25d" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" [[package]] name = "bitmaps" @@ -1099,7 +1095,7 @@ dependencies = [ "cc", "cfg-if", "constant_time_eq", - "memmap2", + "memmap2 0.9.9", "rayon-core", ] @@ -1111,15 +1107,22 @@ checksum = "e0b121a9fe0df916e362fb3271088d071159cdf11db0e4182d02152850756eff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + [[package]] name = "block-buffer" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ + "block-padding", "generic-array", ] @@ -1132,6 +1135,12 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-padding" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" + [[package]] name = "blocking" version = "1.6.2" @@ -1153,9 +1162,9 @@ checksum = "2225b558afc76c596898f5f1b3fc35cfce0eb1b13635cbd7d1b2a7177dc10ccd" [[package]] name = "brotli" -version = "7.0.0" +version = "8.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc97b8f16f944bba54f0433f07e30be199b6dc2bd25937444bbad560bcea29bd" +checksum = "4bd8b9603c7aa97359dbd97ecf258968c95f3adddd6db2f7e7a5bef101c84560" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -1164,9 +1173,9 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "4.0.3" +version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a334ef7c9e23abf0ce748e8cd309037da93e606ad52eb372e4ce327a0dcfbdfd" +checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -1174,12 +1183,12 @@ dependencies = [ [[package]] name = "bstr" -version = "1.12.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4" +checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" dependencies = [ "memchr", - "regex-automata 0.4.10", + "regex-automata", "serde", ] @@ -1197,9 +1206,9 @@ checksum = "64fa3c856b712db6612c019f14756e64e4bcea13337a6b33b696333a9eaa2d06" [[package]] name = "bytemuck" -version = "1.23.2" +version = "1.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3995eaeebcdf32f91f980d360f78732ddc061097ab4e39991ae7a6ace9194677" +checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" [[package]] name = "byteorder" @@ -1219,25 +1228,6 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" -[[package]] -name = "bzip2" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49ecfb22d906f800d4fe833b6282cf4dc1c298f5057ca0b5445e5c209735ca47" -dependencies = [ - "bzip2-sys", -] - -[[package]] -name = "bzip2-sys" -version = "0.1.13+1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225bff33b2141874fe80d71e07d6eec4f85c5c216453dd96388240f96e1acc14" -dependencies = [ - "cc", - "pkg-config", -] - [[package]] name = "cache-padded" version = "1.3.0" @@ -1257,15 +1247,22 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.34" +version = "1.2.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42bc4aea80032b7bf409b0bc7ccad88853858911b7713a8062fdc0623867bedc" +checksum = "37521ac7aabe3d13122dc382493e20c9416f299d2ccd5b3a5340a2570cdeb0f3" dependencies = [ + "find-msvc-tools", "jobserver", "libc", "shlex", ] +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + [[package]] name = "cexpr" version = "0.6.0" @@ -1277,9 +1274,15 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" [[package]] name = "cfg_aliases" @@ -1289,17 +1292,16 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chrono" -version = "0.4.41" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" +checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" dependencies = [ - "android-tzdata", "iana-time-zone", "js-sys", "num-traits", "serde", "wasm-bindgen", - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -1309,6 +1311,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8eebd66744a15ded14960ab4ccdbfb51ad3b81f51f3f04a80adac98c985396c9" dependencies = [ "hashbrown 0.14.5", + "stacker", ] [[package]] @@ -1335,7 +1338,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" dependencies = [ "ciborium-io", - "half 2.6.0", + "half 2.7.1", ] [[package]] @@ -1371,9 +1374,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.46" +version = "4.5.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c5e4fcf9c21d2e544ca1ee9d8552de13019a42aa7dbf32747fa7aaf1df76e57" +checksum = "4c26d721170e0295f191a69bd9a1f93efcdb0aff38684b61ab5750468972e5f5" dependencies = [ "clap_builder", "clap_derive", @@ -1381,33 +1384,44 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.46" +version = "4.5.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fecb53a0e6fcfb055f686001bc2e2592fa527efaf38dbe81a6a9563562e57d41" +checksum = "75835f0c7bf681bfd05abe44e965760fea999a5286c6eb2d59883634fd02011a" dependencies = [ "anstream", "anstyle", "clap_lex", "strsim 0.11.1", + "terminal_size", ] [[package]] name = "clap_derive" -version = "4.5.45" +version = "4.5.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14cb31bb0a7d536caef2639baa7fad459e15c3144efefa6dbd1c84562c4739f6" +checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] name = "clap_lex" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" +checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" + +[[package]] +name = "clipboard-win" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fdf5e01086b6be750428ba4a40619f847eb2e95756eee84b18e06e5f0b50342" +dependencies = [ + "lazy-bytes-cast", + "winapi", +] [[package]] name = "cmake" @@ -1462,6 +1476,46 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" +[[package]] +name = "colorgrad" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faedab4fd8670120c2be7f49225fbdb8b6db6d46f04ce4f864b1f1cdd55e6400" +dependencies = [ + "csscolorparser", +] + +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "compression-codecs" +version = "0.4.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef8a506ec4b81c460798f572caead636d57d3d7e940f998160f52bd254bf2d23" +dependencies = [ + "brotli", + "compression-core", + "flate2", + "liblzma", + "memchr", + "zstd", + "zstd-safe", +] + +[[package]] +name = "compression-core" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e47641d3deaf41fb1538ac1f54735925e275eaf3bf4d55c81b137fba797e5cbb" + [[package]] name = "concurrent-queue" version = "1.2.4" @@ -1489,7 +1543,7 @@ dependencies = [ "encode_unicode", "libc", "once_cell", - "unicode-width 0.2.1", + "unicode-width 0.2.2", "windows-sys 0.59.0", ] @@ -1540,9 +1594,9 @@ checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "const_format" -version = "0.2.34" +version = "0.2.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "126f97965c8ad46d6d9163268ff28432e8f6a1196a55578867832e3049df63dd" +checksum = "7faa7469a93a566e9ccc1c73fe783b4a65c274c5ace346038dca9c39fe0030ad" dependencies = [ "const_format_proc_macros", ] @@ -1564,6 +1618,12 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + [[package]] name = "convert_case" version = "0.6.0" @@ -1620,6 +1680,32 @@ dependencies = [ "url", ] +[[package]] +name = "copypasta" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "133fc8675ee3a4ec9aa513584deda9aa0faeda3586b87f7f0f2ba082c66fb172" +dependencies = [ + "clipboard-win", + "objc", + "objc-foundation", + "objc_id", + "smithay-clipboard", + "x11-clipboard", +] + +[[package]] +name = "copypasta-ext" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9455f470ea0c7d50c3fe3d22389c3a482f38a9f5fbab1c8ee368121356c56718" +dependencies = [ + "copypasta", + "libc", + "which", + "x11-clipboard", +] + [[package]] name = "core-foundation" version = "0.9.4" @@ -1630,6 +1716,16 @@ dependencies = [ "libc", ] +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -1770,14 +1866,14 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.10.0", "crossterm_winapi", - "derive_more", + "derive_more 2.0.1", "document-features", "futures-core", "mio", - "parking_lot", - "rustix 1.0.8", + "parking_lot 0.12.5", + "rustix 1.1.2", "signal-hook", "signal-hook-mio", "winapi", @@ -1821,22 +1917,41 @@ dependencies = [ ] [[package]] -name = "csv" -version = "1.3.1" +name = "crypto-mac" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acdc4883a9c96732e4733212c01447ebd805833b7275a73ca3ee080fd77afdaf" +checksum = "25fab6889090c8133f3deb8f73ba3c65a7f456f66436fc012a1b1e272b1e103e" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "csscolorparser" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fda6aace1fbef3aa217b27f4c8d7d071ef2a70a5ca51050b1f17d40299d3f16" +dependencies = [ + "phf 0.11.3", +] + +[[package]] +name = "csv" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52cd9d68cf7efc6ddfaaee42e7288d3a99d613d4b50f76ce9827ae0c6e14f938" dependencies = [ "csv-core", "itoa", "ryu", - "serde", + "serde_core", ] [[package]] name = "csv-core" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d02f3b0da4c6504f86e9cd789d8dbafab48c2321be74e9987593de5a894d93d" +checksum = "704a3c26996a80471189265814dbc2c257598b96b8a7feae2d31ace646bb9782" dependencies = [ "memchr", ] @@ -1896,7 +2011,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -1911,12 +2026,12 @@ dependencies = [ [[package]] name = "darling" -version = "0.20.11" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" dependencies = [ - "darling_core 0.20.11", - "darling_macro 0.20.11", + "darling_core 0.21.3", + "darling_macro 0.21.3", ] [[package]] @@ -1935,16 +2050,16 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.11" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -1960,13 +2075,13 @@ dependencies = [ [[package]] name = "darling_macro" -version = "0.20.11" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" dependencies = [ - "darling_core 0.20.11", + "darling_core 0.21.3", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -1975,37 +2090,6 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" -[[package]] -name = "deflate64" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da692b8d1080ea3045efaab14434d40468c3d8657e42abddfffca87b428f4c1b" - -[[package]] -name = "deku" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9711031e209dc1306d66985363b4397d4c7b911597580340b93c9729b55f6eb" -dependencies = [ - "bitvec 1.0.1", - "deku_derive", - "no_std_io2", - "rustversion", -] - -[[package]] -name = "deku_derive" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58cb0719583cbe4e81fb40434ace2f0d22ccc3e39a74bb3796c22b451b4f139d" -dependencies = [ - "darling 0.20.11", - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 2.0.106", -] - [[package]] name = "der" version = "0.7.10" @@ -2054,17 +2138,17 @@ checksum = "8034092389675178f570469e6c3b0465d3d30b4505c294a6550db47f3c17ad18" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] name = "deranged" -version = "0.4.0" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" +checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" dependencies = [ "powerfmt", - "serde", + "serde_core", ] [[package]] @@ -2094,14 +2178,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "357422a457ccb850dc8f1c1680e0670079560feaad6c2e247e3f345c4fab8a3f" dependencies = [ "heck 0.5.0", - "indexmap 2.11.0", + "indexmap 2.12.0", "itertools 0.14.0", "proc-macro-crate", "proc-macro2", "quote", - "sha3", + "sha3 0.10.8", "strum", - "syn 2.0.106", + "syn 2.0.108", "void", ] @@ -2112,14 +2196,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ea41269bd490d251b9eca50ccb43117e641cc68b129849757c15ece88fe0574" dependencies = [ "heck 0.5.0", - "indexmap 2.11.0", + "indexmap 2.12.0", "itertools 0.14.0", "proc-macro-crate", "proc-macro2", "quote", - "sha3", + "sha3 0.10.8", "strum", - "syn 2.0.106", + "syn 2.0.108", "void", ] @@ -2131,7 +2215,7 @@ checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -2165,6 +2249,19 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "derive_more" +version = "0.99.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" +dependencies = [ + "convert_case 0.4.0", + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.108", +] + [[package]] name = "derive_more" version = "2.0.1" @@ -2183,10 +2280,16 @@ dependencies = [ "convert_case 0.7.1", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", "unicode-xid", ] +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + [[package]] name = "digest" version = "0.9.0" @@ -2245,7 +2348,7 @@ dependencies = [ "libc", "option-ext", "redox_users 0.5.2", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -2267,7 +2370,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -2276,6 +2379,15 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69dde51e8fef5e12c1d65e0929b03d66e4c0c18282bc30ed2ca050ad6f44dd82" +[[package]] +name = "dlib" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" +dependencies = [ + "libloading", +] + [[package]] name = "dns-lookup" version = "2.1.1" @@ -2284,15 +2396,15 @@ checksum = "cf5597a4b7fe5275fc9dcf88ce26326bc8e4cb87d0130f33752d4c5f717793cf" dependencies = [ "cfg-if", "libc", - "socket2 0.6.0", + "socket2 0.6.1", "windows-sys 0.60.2", ] [[package]] name = "document-features" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d" +checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" dependencies = [ "litrs", ] @@ -2305,9 +2417,15 @@ checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" [[package]] name = "downcast-rs" -version = "2.0.1" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea8a8b81cacc08888170eef4d13b775126db426d0b348bee9d18c2c1eaf123cf" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" + +[[package]] +name = "downcast-rs" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "117240f60069e65410b3ae1bb213295bd828f707b5bec6596a1afc8793ce0cbc" [[package]] name = "dunce" @@ -2327,13 +2445,13 @@ version = "3.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f7d4c414c94bc830797115b8e5f434d58e7e80cb42ba88508c14bc6ea270625" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.10.0", "byteorder", "lazy_static", "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -2345,7 +2463,7 @@ dependencies = [ "byteorder", "dynasm", "fnv", - "memmap2", + "memmap2 0.9.9", ] [[package]] @@ -2454,6 +2572,22 @@ dependencies = [ "zeroize", ] +[[package]] +name = "email-encoding" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9298e6504d9b9e780ed3f7dfd43a61be8cd0e09eb07f7706a945b0072b6670b6" +dependencies = [ + "base64 0.22.1", + "memchr", +] + +[[package]] +name = "email_address" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e079f19b08ca6239f47f8ba8509c11cf3ea30095831f7fed61441475edd8c449" + [[package]] name = "emver" version = "0.1.6" @@ -2511,7 +2645,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -2524,7 +2658,7 @@ dependencies = [ "num-traits", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -2545,7 +2679,7 @@ checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -2562,7 +2696,7 @@ dependencies = [ "arrayvec 0.7.6", "hashx", "num-traits", - "thiserror 2.0.16", + "thiserror 2.0.17", "visibility", ] @@ -2579,12 +2713,12 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -2719,6 +2853,17 @@ dependencies = [ "version_check", ] +[[package]] +name = "filedescriptor" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e40758ed24c9b2eeb76c35fb0aebc66c626084edd827e07e1552279814c6682d" +dependencies = [ + "libc", + "thiserror 1.0.69", + "winapi", +] + [[package]] name = "filetime" version = "0.2.26" @@ -2731,6 +2876,12 @@ dependencies = [ "windows-sys 0.60.2", ] +[[package]] +name = "find-msvc-tools" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" + [[package]] name = "fixed-capacity-vec" version = "1.0.1" @@ -2745,12 +2896,11 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" -version = "1.1.2" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" +checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb" dependencies = [ "crc32fast", - "libz-rs-sys", "miniz_oxide", ] @@ -2772,6 +2922,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + [[package]] name = "foreign-types" version = "0.3.2" @@ -2815,10 +2971,20 @@ dependencies = [ "libc", "pwd-grp", "serde", - "thiserror 2.0.16", + "thiserror 2.0.17", "walkdir", ] +[[package]] +name = "fs2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "fs_extra" version = "1.3.0" @@ -2851,7 +3017,7 @@ version = "0.2.4" source = "git+https://github.com/Start9Labs/arti.git?branch=patch%2Fdisable-exit#24730694701a83432d791d80802db8bda0699700" dependencies = [ "fslock-arti-fork", - "thiserror 2.0.16", + "thiserror 2.0.17", "winapi", ] @@ -2917,7 +3083,7 @@ checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" dependencies = [ "futures-core", "lock_api", - "parking_lot", + "parking_lot 0.12.5", ] [[package]] @@ -2947,7 +3113,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -2968,7 +3134,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f2f12607f92c69b12ed746fabf9ca4f5c482cba46679c1a75b874ed7c26adb" dependencies = [ "futures-io", - "rustls 0.23.31", + "rustls 0.23.35", "rustls-pki-types", ] @@ -3003,10 +3169,19 @@ dependencies = [ ] [[package]] -name = "generic-array" -version = "0.14.7" +name = "fxhash" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "generic-array" +version = "0.14.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" dependencies = [ "typenum", "version_check", @@ -3034,12 +3209,12 @@ dependencies = [ [[package]] name = "gethostname" -version = "0.4.3" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818" +checksum = "c1ebd34e35c46e00bb73e81363248d627782724609fe1b6396f553f68fe3862e" dependencies = [ "libc", - "windows-targets 0.48.5", + "winapi", ] [[package]] @@ -3068,23 +3243,23 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "js-sys", "libc", "r-efi", - "wasi 0.14.2+wasi-0.2.4", + "wasip2", "wasm-bindgen", ] [[package]] name = "gimli" -version = "0.31.1" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" [[package]] name = "glob" @@ -3116,7 +3291,7 @@ version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3696fafb1ecdcc2ae3ce337de73e9202806068594b77d22fdf2f3573c5ec2219" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.10.0", "crc", "simple-bytes", "uuid", @@ -3157,7 +3332,7 @@ dependencies = [ "futures-core", "futures-sink", "http", - "indexmap 2.11.0", + "indexmap 2.12.0", "slab", "tokio", "tokio-util", @@ -3172,12 +3347,13 @@ checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403" [[package]] name = "half" -version = "2.6.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" dependencies = [ "cfg-if", "crunchy", + "zerocopy", ] [[package]] @@ -3213,7 +3389,16 @@ checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ "allocator-api2", "equivalent", - "foldhash", + "foldhash 0.1.5", +] + +[[package]] +name = "hashbrown" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" +dependencies = [ + "allocator-api2", ] [[package]] @@ -3236,7 +3421,7 @@ dependencies = [ "fixed-capacity-vec", "hex", "rand_core 0.9.3", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] @@ -3303,43 +3488,15 @@ dependencies = [ "data-encoding", "futures-channel", "futures-util", - "hickory-proto 0.25.2", + "hickory-proto", "once_cell", "radix_trie", "rand 0.9.2", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tracing", ] -[[package]] -name = "hickory-proto" -version = "0.24.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92652067c9ce6f66ce53cc38d1169daa36e6e7eb7dd3b63b5103bd9d97117248" -dependencies = [ - "async-trait", - "cfg-if", - "data-encoding", - "enum-as-inner", - "futures-channel", - "futures-io", - "futures-util", - "idna", - "ipnet", - "once_cell", - "rand 0.8.5", - "ring", - "rustls 0.21.12", - "rustls-pemfile 1.0.4", - "thiserror 1.0.69", - "tinyvec", - "tokio", - "tokio-rustls 0.24.1", - "tracing", - "url", -] - [[package]] name = "hickory-proto" version = "0.25.2" @@ -3359,36 +3516,13 @@ dependencies = [ "rand 0.9.2", "ring", "serde", - "thiserror 2.0.16", + "thiserror 2.0.17", "tinyvec", "tokio", "tracing", "url", ] -[[package]] -name = "hickory-resolver" -version = "0.24.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbb117a1ca520e111743ab2f6688eddee69db4e0ea242545a604dce8a66fd22e" -dependencies = [ - "cfg-if", - "futures-util", - "hickory-proto 0.24.4", - "ipconfig", - "lru-cache", - "once_cell", - "parking_lot", - "rand 0.8.5", - "resolv-conf", - "rustls 0.21.12", - "smallvec", - "thiserror 1.0.69", - "tokio", - "tokio-rustls 0.24.1", - "tracing", -] - [[package]] name = "hickory-server" version = "0.25.2" @@ -3401,11 +3535,11 @@ dependencies = [ "data-encoding", "enum-as-inner", "futures-util", - "hickory-proto 0.25.2", + "hickory-proto", "ipnet", "prefix-trie", "serde", - "thiserror 2.0.16", + "thiserror 2.0.17", "time", "tokio", "tokio-util", @@ -3424,7 +3558,17 @@ version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" dependencies = [ - "hmac", + "hmac 0.12.1", +] + +[[package]] +name = "hmac" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" +dependencies = [ + "crypto-mac", + "digest 0.9.0", ] [[package]] @@ -3438,11 +3582,22 @@ dependencies = [ [[package]] name = "home" -version = "0.5.11" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", +] + +[[package]] +name = "hostname" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a56f203cd1c76362b69e3863fd987520ac36cf70a8c92627449b2f64a8cf7d65" +dependencies = [ + "cfg-if", + "libc", + "windows-link 0.1.3", ] [[package]] @@ -3499,9 +3654,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "humantime" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b112acc8b3adf4b107a8ec20977da0273a8c386765a3ec0229bd500a1443f9f" +checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424" [[package]] name = "humantime-serde" @@ -3545,11 +3700,12 @@ dependencies = [ "http", "hyper", "hyper-util", - "rustls 0.23.31", + "rustls 0.23.35", "rustls-pki-types", "tokio", - "tokio-rustls 0.26.2", + "tokio-rustls 0.26.4", "tower-service", + "webpki-roots 1.0.4", ] [[package]] @@ -3583,9 +3739,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d9b05277c7e8da2c93a568989bb6207bef0112e8d17df7a6eda4a3cf143bc5e" +checksum = "3c6995591a8f1380fcb4ba966a252a4b29188d51d2b89e3a252f5305be65aea8" dependencies = [ "base64 0.22.1", "bytes", @@ -3599,7 +3755,7 @@ dependencies = [ "libc", "percent-encoding", "pin-project-lite", - "socket2 0.6.0", + "socket2 0.6.1", "system-configuration", "tokio", "tower-service", @@ -3609,9 +3765,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.63" +version = "0.1.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" +checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -3619,7 +3775,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core", + "windows-core 0.62.2", ] [[package]] @@ -3633,9 +3789,9 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" dependencies = [ "displaydoc", "potential_utf", @@ -3646,9 +3802,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" dependencies = [ "displaydoc", "litemap", @@ -3659,11 +3815,10 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" dependencies = [ - "displaydoc", "icu_collections", "icu_normalizer_data", "icu_properties", @@ -3674,42 +3829,38 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" [[package]] name = "icu_properties" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99" dependencies = [ - "displaydoc", "icu_collections", "icu_locale_core", "icu_properties_data", "icu_provider", - "potential_utf", "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" +checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899" [[package]] name = "icu_provider" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" dependencies = [ "displaydoc", "icu_locale_core", - "stable_deref_trait", - "tinystr", "writeable", "yoke", "zerofrom", @@ -3726,6 +3877,19 @@ dependencies = [ "serde", ] +[[package]] +name = "iddqd" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bac5efd33e0c5eb0ac45cbd210541a214dac576896ca97ba08e16e3b1079cdd8" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.2.0", + "hashbrown 0.16.0", + "rustc-hash", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -3755,20 +3919,21 @@ dependencies = [ [[package]] name = "image" -version = "0.25.6" +version = "0.25.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db35664ce6b9810857a38a906215e75a9c879f0696556a39f59c62829710251a" +checksum = "529feb3e6769d234375c4cf1ee2ce713682b8e76538cb13f9fc23e1400a591e7" dependencies = [ "bytemuck", "byteorder-lite", + "moxcms", "num-traits", ] [[package]] name = "imbl" -version = "6.0.0" +version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33afdc5d333c1a43f1f640bfc6ad3788729e5b2f18472e5d33a9187315257f8e" +checksum = "0fade8ae6828627ad1fa094a891eccfb25150b383047190a3648d66d06186501" dependencies = [ "archery", "bitmaps", @@ -3850,13 +4015,14 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.11.0" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2481980430f9f78649238835720ddccc57e52df14ffce1c6f37391d61b563e9" +checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" dependencies = [ "equivalent", - "hashbrown 0.15.5", + "hashbrown 0.16.0", "serde", + "serde_core", ] [[package]] @@ -3869,7 +4035,7 @@ dependencies = [ "number_prefix", "portable-atomic", "tokio", - "unicode-width 0.2.1", + "unicode-width 0.2.2", "web-time", ] @@ -3879,7 +4045,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f37dccff2791ab604f9babef0ba14fbe0be30bd368dc541e2b08d07c8aa908f3" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.10.0", "futures-core", "inotify-sys", "libc", @@ -3905,10 +4071,19 @@ dependencies = [ ] [[package]] -name = "integer-encoding" -version = "4.0.2" +name = "instant" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d762194228a2f1c11063e46e32e5acb96e66e906382b9eb5441f2e0504bbd5a" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "integer-encoding" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c00403deb17c3221a1fe4fb571b9ed0370b3dcd116553c77fa294a3d918699" dependencies = [ "async-trait", "tokio", @@ -3923,29 +4098,6 @@ dependencies = [ "rustversion", ] -[[package]] -name = "io-uring" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" -dependencies = [ - "bitflags 2.9.3", - "cfg-if", - "libc", -] - -[[package]] -name = "ipconfig" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" -dependencies = [ - "socket2 0.5.10", - "widestring", - "windows-sys 0.48.0", - "winreg", -] - [[package]] name = "ipnet" version = "2.11.0" @@ -3957,9 +4109,9 @@ dependencies = [ [[package]] name = "iri-string" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +checksum = "4f867b9d1d896b67beb18518eda36fdb77a32ea590de864f1325b294a6d14397" dependencies = [ "memchr", "serde", @@ -3967,20 +4119,26 @@ dependencies = [ [[package]] name = "is-terminal" -version = "0.4.16" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" +checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46" dependencies = [ "hermit-abi", "libc", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] -name = "is_terminal_polyfill" -version = "1.70.1" +name = "is_ci" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +checksum = "7655c9839580ee829dfacba1d1278c2b7883e50a277ff7541299489d6bdfdc45" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] name = "isocountry" @@ -4019,15 +4177,6 @@ dependencies = [ "either", ] -[[package]] -name = "itertools" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.13.0" @@ -4090,13 +4239,35 @@ dependencies = [ "jaq-parse", ] +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys", + "log", + "thiserror 1.0.69", + "walkdir", + "windows-sys 0.45.0", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + [[package]] name = "jobserver" version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", "libc", ] @@ -4113,15 +4284,15 @@ dependencies = [ "regex", "serde", "serde_json", - "thiserror 2.0.16", + "thiserror 2.0.17", "time", ] [[package]] name = "js-sys" -version = "0.3.77" +version = "0.3.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65" dependencies = [ "once_cell", "wasm-bindgen", @@ -4143,7 +4314,7 @@ dependencies = [ "imbl", "imbl-value 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "serde", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] @@ -4164,7 +4335,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4dc5fdb62af2f520116927304f15d25b3c2667b4817b90efdc045194c912c54" dependencies = [ "digest 0.10.7", - "sha3", + "sha3 0.10.8", ] [[package]] @@ -4196,6 +4367,21 @@ dependencies = [ "libc", ] +[[package]] +name = "kv" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "620727085ac39ee9650b373fe6d8073a0aee6f99e52a9c72b25f7671078039ab" +dependencies = [ + "bincode 1.3.3", + "pin-project-lite", + "serde", + "serde_json", + "sled", + "thiserror 1.0.69", + "toml 0.5.11", +] + [[package]] name = "kv-log-macro" version = "1.0.7" @@ -4219,7 +4405,7 @@ dependencies = [ "petgraph", "pico-args", "regex", - "regex-syntax 0.8.6", + "regex-syntax 0.8.8", "string_cache", "term", "tiny-keccak", @@ -4233,9 +4419,15 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "507460a910eb7b32ee961886ff48539633b788a36b65692b95f225b844c82553" dependencies = [ - "regex-automata 0.4.10", + "regex-automata", ] +[[package]] +name = "lazy-bytes-cast" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10257499f089cd156ad82d0a9cd57d9501fa2c989068992a97eb3c27836f206b" + [[package]] name = "lazy_async_pool" version = "0.3.3" @@ -4262,10 +4454,33 @@ dependencies = [ ] [[package]] -name = "lazycell" -version = "1.3.0" +name = "lettre" +version = "0.11.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" +checksum = "9e13e10e8818f8b2a60f52cb127041d388b89f3a96a62be9ceaffa22262fef7f" +dependencies = [ + "async-trait", + "base64 0.22.1", + "chumsky", + "email-encoding", + "email_address", + "fastrand", + "futures-io", + "futures-util", + "hostname", + "httpdate", + "idna", + "mime", + "nom 8.0.0", + "percent-encoding", + "quoted_printable", + "rustls 0.23.35", + "rustls-platform-verifier", + "socket2 0.6.1", + "tokio", + "tokio-rustls 0.26.4", + "url", +] [[package]] name = "lexical-core" @@ -4282,18 +4497,38 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.175" +version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" [[package]] name = "libloading" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" dependencies = [ "cfg-if", - "windows-targets 0.53.3", + "windows-link 0.2.1", +] + +[[package]] +name = "liblzma" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73c36d08cad03a3fbe2c4e7bb3a9e84c57e4ee4135ed0b065cade3d98480c648" +dependencies = [ + "liblzma-sys", +] + +[[package]] +name = "liblzma-sys" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01b9596486f6d60c3bbe644c0e1be1aa6ccc472ad630fe8927b456973d7cb736" +dependencies = [ + "cc", + "libc", + "pkg-config", ] [[package]] @@ -4303,14 +4538,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" [[package]] -name = "libredox" -version = "0.1.9" +name = "libmimalloc-sys" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "391290121bad3d37fbddad76d8f5d1c1c314cfc646d143d7e07a3086ddff0ce3" +checksum = "667f4fec20f29dfc6bc7357c582d91796c169ad7e2fce709468aefeb2c099870" dependencies = [ - "bitflags 2.9.3", + "cc", "libc", - "redox_syscall 0.5.17", +] + +[[package]] +name = "libredox" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" +dependencies = [ + "bitflags 2.10.0", + "libc", + "redox_syscall 0.5.18", ] [[package]] @@ -4334,15 +4579,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "libz-rs-sys" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "172a788537a2221661b480fee8dc5f96c580eb34fa88764d3205dc356c7e4221" -dependencies = [ - "zlib-rs", -] - [[package]] name = "linked-hash-map" version = "0.5.6" @@ -4357,142 +4593,62 @@ checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] name = "linux-raw-sys" -version = "0.9.4" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "litemap" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" [[package]] name = "litrs" -version = "0.4.2" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5e54036fe321fd421e10d732f155734c4e4afd610dd556d9a82833ab3ee0bed" +checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" [[package]] name = "lock_api" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ - "autocfg", "scopeguard", ] [[package]] name = "log" -version = "0.4.27" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" dependencies = [ "value-bag", ] [[package]] -name = "lru-cache" +name = "lru-slab" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" -dependencies = [ - "linked-hash-map", -] +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" [[package]] -name = "lz4_flex" -version = "0.11.5" +name = "malloc_buf" +version = "0.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08ab2867e3eeeca90e844d1940eab391c9dc5228783db2ed999acbc0a9ed375a" - -[[package]] -name = "lzma-rs" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "297e814c836ae64db86b36cf2a557ba54368d03f6afcd7d947c266692f71115e" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" dependencies = [ - "byteorder", - "crc", -] - -[[package]] -name = "lzma-sys" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fda04ab3764e6cde78b9974eec4f779acaba7c4e84b36eca3cf77c581b85d27" -dependencies = [ - "cc", "libc", - "pkg-config", -] - -[[package]] -name = "mail-auth" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bd9d657de66a3d5ac360c3eab8c9f5cac2565f2b97cc032d5de4c900ef470de" -dependencies = [ - "ahash 0.8.12", - "flate2", - "hickory-resolver", - "lru-cache", - "mail-builder", - "mail-parser", - "parking_lot", - "quick-xml", - "ring", - "rustls-pemfile 2.2.0", - "serde", - "serde_json", - "zip", -] - -[[package]] -name = "mail-builder" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25f5871d5270ed80f2ee750b95600c8d69b05f8653ad3be913b2ad2e924fefcb" -dependencies = [ - "gethostname", -] - -[[package]] -name = "mail-parser" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93c3b9e5d8b17faf573330bbc43b37d6e918c0a3bf8a88e7d0a220ebc84af9fc" -dependencies = [ - "encoding_rs", -] - -[[package]] -name = "mail-send" -version = "0.4.9" -source = "git+https://github.com/dr-bonez/mail-send.git?branch=main#57545dadab5808d59145d133de64f81b8ba01979" -dependencies = [ - "base64 0.22.1", - "gethostname", - "mail-auth", - "mail-builder", - "md5", - "rand 0.8.5", - "rustls 0.23.31", - "rustls-pki-types", - "smtp-proto", - "tokio", - "tokio-rustls 0.26.2", - "webpki-roots 0.26.11", ] [[package]] name = "matchers" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" dependencies = [ - "regex-automata 0.1.10", + "regex-automata", ] [[package]] @@ -4517,7 +4673,7 @@ dependencies = [ "bitvec 1.0.1", "serde", "serde-big-array", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] @@ -4530,23 +4686,26 @@ dependencies = [ "digest 0.10.7", ] -[[package]] -name = "md5" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" - [[package]] name = "memchr" -version = "2.7.5" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "memmap2" -version = "0.9.8" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843a98750cd611cc2965a8213b53b43e715f13c37a9e096c6408e69990961db7" +checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" +dependencies = [ + "libc", +] + +[[package]] +name = "memmap2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "744133e4a0e0a658e1374cf3bf8e415c4052a15a111acd372764c55b4177d490" dependencies = [ "libc", ] @@ -4581,6 +4740,45 @@ dependencies = [ "zeroize", ] +[[package]] +name = "miette" +version = "7.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f98efec8807c63c752b5bd61f862c165c115b0a35685bdcfd9238c7aeb592b7" +dependencies = [ + "backtrace", + "backtrace-ext", + "cfg-if", + "miette-derive", + "owo-colors", + "supports-color", + "supports-hyperlinks", + "supports-unicode", + "terminal_size", + "textwrap", + "unicode-width 0.1.14", +] + +[[package]] +name = "miette-derive" +version = "7.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db5b29714e950dbb20d5e6f74f9dcec4edbcc1067bb7f8ed198c097b8c1a818b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.108", +] + +[[package]] +name = "mimalloc" +version = "0.1.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1ee66a4b64c74f4ef288bcbb9192ad9c3feaad75193129ac8509af543894fd8" +dependencies = [ + "libmimalloc-sys", +] + [[package]] name = "mime" version = "0.3.17" @@ -4600,18 +4798,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", + "simd-adler32", ] [[package]] name = "mio" -version = "1.0.4" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" +checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" dependencies = [ "libc", "log", "wasi 0.11.1+wasi-snapshot-preview1", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -4619,7 +4818,7 @@ name = "models" version = "0.1.0" dependencies = [ "arti-client", - "axum 0.8.4", + "axum 0.8.6", "base64 0.22.1", "color-eyre", "ed25519-dalek 2.2.0", @@ -4627,7 +4826,9 @@ dependencies = [ "gpt", "ipnet", "lazy_static", + "lettre", "mbrman", + "miette", "num_enum", "openssl", "patch-db", @@ -4635,12 +4836,13 @@ dependencies = [ "regex", "reqwest", "rpc-toolkit", - "rustls 0.23.31", + "rustls 0.23.35", "serde", "serde_json", "ssh-key", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", + "torut", "tracing", "ts-rs", "typeid", @@ -4648,6 +4850,16 @@ dependencies = [ "zbus", ] +[[package]] +name = "moxcms" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fbdd3d7436f8b5e892b8b7ea114271ff0fa00bc5acae845d53b07d498616ef6" +dependencies = [ + "num-traits", + "pxfm", +] + [[package]] name = "native-tls" version = "0.2.14" @@ -4660,7 +4872,7 @@ dependencies = [ "openssl-probe", "openssl-sys", "schannel", - "security-framework", + "security-framework 2.11.1", "security-framework-sys", "tempfile", ] @@ -4715,28 +4927,31 @@ dependencies = [ "memoffset 0.6.5", ] +[[package]] +name = "nix" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" +dependencies = [ + "bitflags 2.10.0", + "cfg-if", + "cfg_aliases 0.1.1", + "libc", +] + [[package]] name = "nix" version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.10.0", "cfg-if", - "cfg_aliases", + "cfg_aliases 0.2.1", "libc", "memoffset 0.9.1", ] -[[package]] -name = "no_std_io2" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a3564ce7035b1e4778d8cb6cacebb5d766b5e8fe5a75b9e441e33fb61a872c6" -dependencies = [ - "memchr", -] - [[package]] name = "nom" version = "6.1.2" @@ -4775,7 +4990,7 @@ version = "8.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d3d07927151ff8575b7087f245456e549fea62edf0ec4e565a5ee50c8402bc3" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.10.0", "inotify", "kqueue", "libc", @@ -4803,12 +5018,11 @@ dependencies = [ [[package]] name = "nu-ansi-term" -version = "0.46.0" +version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "overload", - "winapi", + "windows-sys 0.61.2", ] [[package]] @@ -4837,11 +5051,10 @@ dependencies = [ [[package]] name = "num-bigint-dig" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +checksum = "82c79c15c05d4bf82b6f5ef163104cc81a760d8e874d38ac50ab67c8877b647b" dependencies = [ - "byteorder", "lazy_static", "libm", "num-integer", @@ -4920,9 +5133,9 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a973b4e44ce6cad84ce69d797acf9a044532e4184c4f267913d1b546a0727b7a" +checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c" dependencies = [ "num_enum_derive", "rustversion", @@ -4930,14 +5143,14 @@ dependencies = [ [[package]] name = "num_enum_derive" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d" +checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -4953,29 +5166,67 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6aa2c4e539b869820a2b82e1aef6ff40aa85e65decdd5185e83fb4b1249cd00f" [[package]] -name = "objc2-core-foundation" -version = "0.3.1" +name = "objc" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" dependencies = [ - "bitflags 2.9.3", + "malloc_buf", +] + +[[package]] +name = "objc-foundation" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" +dependencies = [ + "block", + "objc", + "objc_id", +] + +[[package]] +name = "objc2-core-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" +dependencies = [ + "bitflags 2.10.0", ] [[package]] name = "objc2-io-kit" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71c1c64d6120e51cd86033f67176b1cb66780c2efe34dec55176f77befd93c0a" +checksum = "33fafba39597d6dc1fb709123dfa8289d39406734be322956a69f0931c73bb15" dependencies = [ "libc", "objc2-core-foundation", ] [[package]] -name = "object" -version = "0.36.7" +name = "objc_id" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" +dependencies = [ + "objc", +] + +[[package]] +name = "object" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "memchr", +] + +[[package]] +name = "object" +version = "0.37.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" dependencies = [ "memchr", ] @@ -5001,9 +5252,9 @@ dependencies = [ [[package]] name = "once_cell_polyfill" -version = "1.70.1" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] name = "oneshot-fused-workaround" @@ -5013,6 +5264,28 @@ dependencies = [ "futures", ] +[[package]] +name = "onig" +version = "6.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "336b9c63443aceef14bea841b899035ae3abe89b7c486aaf4c5bd8aafedac3f0" +dependencies = [ + "bitflags 2.10.0", + "libc", + "once_cell", + "onig_sys", +] + +[[package]] +name = "onig_sys" +version = "69.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f86c6eef3d6df15f23bcfb6af487cbd2fed4e5581d58d5bf1f5f8b7f6727dc" +dependencies = [ + "cc", + "pkg-config", +] + [[package]] name = "oorandom" version = "11.1.5" @@ -5027,9 +5300,9 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "openssh-keys" -version = "0.6.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb830a82898b2ac17c9620ddce839ac3b34b9cb8a1a037cbdbfb9841c756c3e" +checksum = "351339c4d45e6bdf2defef3ef1ce0b153810bd59b171b92b6a42e7bb0f32a4ad" dependencies = [ "base64 0.21.7", "byteorder", @@ -5040,11 +5313,11 @@ dependencies = [ [[package]] name = "openssl" -version = "0.10.73" +version = "0.10.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" +checksum = "24ad14dd45412269e1a30f52ad8f0664f0f4f4a89ee8fe28c3b3527021ebb654" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.10.0", "cfg-if", "foreign-types", "libc", @@ -5061,7 +5334,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -5072,18 +5345,18 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-src" -version = "300.5.2+3.5.2" +version = "300.5.4+3.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d270b79e2926f5150189d475bc7e9d2c69f9c4697b185fa917d5a32b792d21b4" +checksum = "a507b3792995dae9b0df8a1c1e3771e8418b7c2d9f0baeba32e6fe8b06c7cb72" dependencies = [ "cc", ] [[package]] name = "openssl-sys" -version = "0.9.109" +version = "0.9.110" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" +checksum = "0a9f0075ba3c21b09f8e8b2026584b1d18d49388648f2fbbf3c97ea8deced8e2" dependencies = [ "cc", "libc", @@ -5126,17 +5399,11 @@ dependencies = [ "memchr", ] -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" - [[package]] name = "owo-colors" -version = "4.2.2" +version = "4.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48dd4f4a2c8405440fd0462561f0e5806bd0f77e86f51c761481bdd4018b545e" +checksum = "9c6901729fa79e91a0913333229e9ca5dc725089d1c363b2f4b4760709dc4a52" [[package]] name = "p256" @@ -5184,25 +5451,50 @@ checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" -version = "0.12.4" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core 0.8.6", +] + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" dependencies = [ "lock_api", - "parking_lot_core", + "parking_lot_core 0.9.12", ] [[package]] name = "parking_lot_core" -version = "0.9.11" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall 0.2.16", + "smallvec", + "winapi", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.17", + "redox_syscall 0.5.18", "smallvec", - "windows-targets 0.52.6", + "windows-link 0.2.1", ] [[package]] @@ -5227,7 +5519,7 @@ dependencies = [ "patch-db-macro", "serde", "serde_cbor", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tracing", "tracing-error", @@ -5259,17 +5551,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" dependencies = [ "digest 0.10.7", - "hmac", + "hmac 0.12.1", ] [[package]] name = "pem" -version = "3.0.5" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38af38e8470ac9dee3ce1bae1af9c1671fffc44ddfd8bd1d0a3445bf349a8ef3" +checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be" dependencies = [ "base64 0.22.1", - "serde", + "serde_core", ] [[package]] @@ -5289,20 +5581,19 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pest" -version = "2.8.1" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1db05f56d34358a8b1066f67cbb203ee3e7ed2ba674a6263a1d5ec6db2204323" +checksum = "989e7521a040efde50c3ab6bbadafbe15ab6dc042686926be59ac35d74607df4" dependencies = [ "memchr", - "thiserror 2.0.16", "ucd-trie", ] [[package]] name = "pest_derive" -version = "2.8.1" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb056d9e8ea77922845ec74a1c4e8fb17e7c218cc4fc11a15c5d25e189aa40bc" +checksum = "187da9a3030dbafabbbfb20cb323b976dc7b7ce91fcd84f2f74d6e31d378e2de" dependencies = [ "pest", "pest_generator", @@ -5310,22 +5601,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.8.1" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87e404e638f781eb3202dc82db6760c8ae8a1eeef7fb3fa8264b2ef280504966" +checksum = "49b401d98f5757ebe97a26085998d6c0eecec4995cad6ab7fc30ffdf4b052843" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] name = "pest_meta" -version = "2.8.1" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edd1101f170f5903fde0914f899bb503d9ff5271d7ba76bbb70bea63690cc0d5" +checksum = "72f27a2cfee9f9039c4d86faa5af122a0ac3851441a34865b8a043b46be0065a" dependencies = [ "pest", "sha2 0.10.9", @@ -5338,7 +5629,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", - "indexmap 2.11.0", + "indexmap 2.12.0", +] + +[[package]] +name = "phf" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" +dependencies = [ + "phf_macros 0.11.3", + "phf_shared 0.11.3", ] [[package]] @@ -5347,11 +5648,21 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" dependencies = [ - "phf_macros", + "phf_macros 0.13.1", "phf_shared 0.13.1", "serde", ] +[[package]] +name = "phf_generator" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" +dependencies = [ + "phf_shared 0.11.3", + "rand 0.8.5", +] + [[package]] name = "phf_generator" version = "0.13.1" @@ -5362,17 +5673,30 @@ dependencies = [ "phf_shared 0.13.1", ] +[[package]] +name = "phf_macros" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" +dependencies = [ + "phf_generator 0.11.3", + "phf_shared 0.11.3", + "proc-macro2", + "quote", + "syn 2.0.108", +] + [[package]] name = "phf_macros" version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef" dependencies = [ - "phf_generator", + "phf_generator 0.13.1", "phf_shared 0.13.1", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -5416,7 +5740,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -5469,6 +5793,19 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +[[package]] +name = "plist" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "740ebea15c5d1428f910cd1a5f52cebf8d25006245ed8ade92702f4943d91e07" +dependencies = [ + "base64 0.22.1", + "indexmap 2.12.0", + "quick-xml", + "serde", + "time", +] + [[package]] name = "plotters" version = "0.3.7" @@ -5499,16 +5836,16 @@ dependencies = [ [[package]] name = "polling" -version = "3.10.0" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5bd19146350fe804f7cb2669c851c03d69da628803dab0d98018142aaa5d829" +checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" dependencies = [ "cfg-if", "concurrent-queue 2.5.0", "hermit-abi", "pin-project-lite", - "rustix 1.0.8", - "windows-sys 0.60.2", + "rustix 1.1.2", + "windows-sys 0.61.2", ] [[package]] @@ -5517,6 +5854,27 @@ version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" +[[package]] +name = "portable-pty" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4a596a2b3d2752d94f51fac2d4a96737b8705dddd311a32b9af47211f08671e" +dependencies = [ + "anyhow", + "bitflags 1.3.2", + "downcast-rs 1.2.1", + "filedescriptor", + "lazy_static", + "libc", + "log", + "nix 0.28.0", + "serial2", + "shared_library", + "shell-words", + "winapi", + "winreg", +] + [[package]] name = "postage" version = "0.5.0" @@ -5526,7 +5884,7 @@ dependencies = [ "atomic 0.5.3", "crossbeam-queue", "futures", - "parking_lot", + "parking_lot 0.12.5", "pin-project", "static_assertions", "thiserror 1.0.69", @@ -5534,9 +5892,9 @@ dependencies = [ [[package]] name = "potential_utf" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" dependencies = [ "zerovec", ] @@ -5572,6 +5930,16 @@ dependencies = [ "num-traits", ] +[[package]] +name = "pretty_assertions" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d" +dependencies = [ + "diff", + "yansi", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -5579,7 +5947,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -5607,22 +5975,22 @@ dependencies = [ [[package]] name = "priority-queue" -version = "2.5.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5676d703dda103cbb035b653a9f11448c0a7216c7926bd35fcb5865475d0c970" +checksum = "93980406f12d9f8140ed5abe7155acb10bb1e69ea55c88960b9c2f117445ef96" dependencies = [ - "autocfg", "equivalent", - "indexmap 2.11.0", + "indexmap 2.12.0", + "serde", ] [[package]] name = "proc-macro-crate" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" dependencies = [ - "toml_edit", + "toml_edit 0.23.7", ] [[package]] @@ -5644,14 +6012,14 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] name = "proc-macro2" -version = "1.0.101" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" dependencies = [ "unicode-ident", ] @@ -5662,7 +6030,7 @@ version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc5b72d8145275d844d4b5f6d4e1eef00c8cd889edb6035c21675d1bb1f45c9f" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.10.0", "chrono", "flate2", "hex", @@ -5676,26 +6044,25 @@ version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "239df02d8349b06fc07398a3a1697b06418223b1c7725085e801e7c0fc6a12ec" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.10.0", "chrono", "hex", ] [[package]] name = "proptest" -version = "1.7.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fcdab19deb5195a31cf7726a210015ff1496ba1464fd42cb4f537b8b01b471f" +checksum = "bee689443a2bd0a16ab0348b52ee43e3b2d1b1f931c8aa5c9f8de4c86fbe8c40" dependencies = [ "bit-set 0.8.0", "bit-vec 0.8.0", - "bitflags 2.9.3", - "lazy_static", + "bitflags 2.10.0", "num-traits", "rand 0.9.2", "rand_chacha 0.9.0", "rand_xorshift", - "regex-syntax 0.8.6", + "regex-syntax 0.8.8", "rusty-fork", "tempfile", "unarray", @@ -5709,7 +6076,7 @@ checksum = "4ee1c9ac207483d5e7db4940700de86a9aae46ef90c48b57f99fe7edb8345e49" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -5732,7 +6099,7 @@ dependencies = [ "itertools 0.14.0", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -5750,13 +6117,23 @@ version = "2.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33cb294fe86a74cbcf50d4445b37da762029549ebeea341421c7c70370f86cac" +[[package]] +name = "psm" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d11f2fedc3b7dafdc2851bc52f277377c5473d378859be234bc7ebb593144d01" +dependencies = [ + "ar_archive_writer", + "cc", +] + [[package]] name = "pty-process" version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71cec9e2670207c5ebb9e477763c74436af3b9091dd550b9fb3c1bec7f3ea266" dependencies = [ - "rustix 1.0.8", + "rustix 1.1.2", ] [[package]] @@ -5781,6 +6158,15 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "pxfm" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3cbdf373972bf78df4d3b518d07003938e2c7d1fb5891e55f9cb6df57009d84" +dependencies = [ + "num-traits", +] + [[package]] name = "qrcode" version = "0.14.1" @@ -5798,28 +6184,138 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quick-xml" -version = "0.32.0" +version = "0.38.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d3a6e5838b60e0e8fa7a43f22ade549a37d61f8bdbe636d0d7816191de969c2" +checksum = "42a232e7487fc2ef313d96dde7948e7a3c05101870d8985e4fd8d26aedd27b89" dependencies = [ "memchr", ] [[package]] -name = "quote" -version = "1.0.40" +name = "quinn" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" +dependencies = [ + "bytes", + "cfg_aliases 0.2.1", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls 0.23.35", + "socket2 0.6.1", + "thiserror 2.0.17", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" +dependencies = [ + "bytes", + "getrandom 0.3.4", + "lru-slab", + "rand 0.9.2", + "ring", + "rustc-hash", + "rustls 0.23.35", + "rustls-pki-types", + "slab", + "thiserror 2.0.17", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" +dependencies = [ + "cfg_aliases 0.2.1", + "libc", + "once_cell", + "socket2 0.6.1", + "tracing", + "windows-sys 0.60.2", +] + +[[package]] +name = "quote" +version = "1.0.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" dependencies = [ "proc-macro2", ] +[[package]] +name = "quoted_printable" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "640c9bd8497b02465aeef5375144c26062e0dcd5939dfcbb0f5db76cb8c17c73" + [[package]] name = "r-efi" version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +[[package]] +name = "r3bl_tui" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "105ab0982b9aa4e3e1d6896036e92beb06ab14f6fcba408b56bca7c928353673" +dependencies = [ + "async-stream", + "bincode 2.0.1", + "chrono", + "clap", + "colorgrad", + "const_format", + "copypasta-ext", + "crossterm", + "flate2", + "futures-core", + "futures-util", + "is_ci", + "kv", + "miette", + "mimalloc", + "nom 8.0.0", + "portable-pty", + "pretty_assertions", + "rand 0.9.2", + "reqwest", + "rustc-hash", + "serde", + "serde_json", + "sha2 0.10.9", + "smallstr", + "smallvec", + "strip-ansi", + "strip-ansi-escapes", + "strum", + "strum_macros", + "syntect", + "textwrap", + "thiserror 2.0.17", + "tokio", + "tracing", + "tracing-appender", + "tracing-core", + "tracing-subscriber", + "unicode-segmentation", + "unicode-width 0.2.2", + "uuid", +] + [[package]] name = "radium" version = "0.5.3" @@ -5930,7 +6426,7 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", ] [[package]] @@ -6029,11 +6525,11 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.17" +version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.10.0", ] [[package]] @@ -6061,59 +6557,50 @@ checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" dependencies = [ "getrandom 0.2.16", "libredox", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] name = "ref-cast" -version = "1.0.24" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf" +checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.24" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7" +checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] name = "regex" -version = "1.11.2" +version = "1.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.10", - "regex-syntax 0.8.6", + "regex-automata", + "regex-syntax 0.8.8", ] [[package]] name = "regex-automata" -version = "0.1.10" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" -dependencies = [ - "regex-syntax 0.6.29", -] - -[[package]] -name = "regex-automata" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.6", + "regex-syntax 0.8.8", ] [[package]] @@ -6124,15 +6611,15 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[package]] name = "reqwest" -version = "0.12.23" +version = "0.12.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d429f34c8092b2d42c7c93cec323bb4adeb7c67698f70839adec842ec10c7ceb" +checksum = "9d0946410b9f7b082a427e4ef5c8ff541a88b357bc6c637c40db3a68ac70a36f" dependencies = [ "base64 0.22.1", "bytes", @@ -6155,6 +6642,8 @@ dependencies = [ "native-tls", "percent-encoding", "pin-project-lite", + "quinn", + "rustls 0.23.35", "rustls-pki-types", "serde", "serde_json", @@ -6162,6 +6651,7 @@ dependencies = [ "sync_wrapper", "tokio", "tokio-native-tls", + "tokio-rustls 0.26.4", "tokio-util", "tower 0.5.2", "tower-http", @@ -6171,6 +6661,7 @@ dependencies = [ "wasm-bindgen-futures", "wasm-streams", "web-sys", + "webpki-roots 1.0.4", ] [[package]] @@ -6185,12 +6676,6 @@ dependencies = [ "url", ] -[[package]] -name = "resolv-conf" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95325155c684b1c89f7765e30bc1c42e4a6da51ca513615660cb8a62ef9a88e3" - [[package]] name = "retry-error" version = "0.6.5" @@ -6202,7 +6687,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" dependencies = [ - "hmac", + "hmac 0.12.1", "subtle", ] @@ -6234,11 +6719,11 @@ dependencies = [ [[package]] name = "rpc-toolkit" version = "0.3.2" -source = "git+https://github.com/Start9Labs/rpc-toolkit.git?branch=master#23ecbda1c6b549fd2778e2847a53ea75a4103577" +source = "git+https://github.com/Start9Labs/rpc-toolkit.git?branch=master#068db905ee38a7da97cc4a43b806409204e73723" dependencies = [ "async-stream", "async-trait", - "axum 0.8.4", + "axum 0.8.6", "clap", "futures", "http", @@ -6252,7 +6737,7 @@ dependencies = [ "reqwest", "serde", "serde_json", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tokio-stream", "url", @@ -6296,7 +6781,7 @@ version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "165ca6e57b20e1351573e3729b958bc62f0e48025386970b6e4d29e7a7e71f3f" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.10.0", "fallible-iterator", "fallible-streaming-iterator", "hashlink", @@ -6324,9 +6809,9 @@ checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" [[package]] name = "rustc-hash" -version = "1.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" [[package]] name = "rustc_version" @@ -6352,8 +6837,8 @@ version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.9.3", - "errno 0.3.13", + "bitflags 2.10.0", + "errno 0.3.14", "libc", "linux-raw-sys 0.4.15", "windows-sys 0.59.0", @@ -6361,27 +6846,15 @@ dependencies = [ [[package]] name = "rustix" -version = "1.0.8" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" dependencies = [ - "bitflags 2.9.3", - "errno 0.3.13", + "bitflags 2.10.0", + "errno 0.3.14", "libc", - "linux-raw-sys 0.9.4", - "windows-sys 0.60.2", -] - -[[package]] -name = "rustls" -version = "0.21.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" -dependencies = [ - "log", - "ring", - "rustls-webpki 0.101.7", - "sct", + "linux-raw-sys 0.11.0", + "windows-sys 0.61.2", ] [[package]] @@ -6400,27 +6873,30 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.31" +version = "0.23.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ebcbd2f03de0fc1122ad9bb24b127a5a6cd51d72604a3f3c50ac459762b6cc" +checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f" dependencies = [ "aws-lc-rs", "log", "once_cell", "ring", "rustls-pki-types", - "rustls-webpki 0.103.4", + "rustls-webpki 0.103.8", "subtle", "zeroize", ] [[package]] -name = "rustls-pemfile" -version = "1.0.4" +name = "rustls-native-certs" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +checksum = "9980d917ebb0c0536119ba501e90834767bffc3d60641457fd84a1f3fd337923" dependencies = [ - "base64 0.21.7", + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework 3.5.1", ] [[package]] @@ -6434,23 +6910,41 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" +checksum = "94182ad936a0c91c324cd46c6511b9510ed16af436d7b5bab34beab0afd55f7a" dependencies = [ + "web-time", "zeroize", ] [[package]] -name = "rustls-webpki" -version = "0.101.7" +name = "rustls-platform-verifier" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784" dependencies = [ - "ring", - "untrusted", + "core-foundation 0.10.1", + "core-foundation-sys", + "jni", + "log", + "once_cell", + "rustls 0.23.35", + "rustls-native-certs", + "rustls-platform-verifier-android", + "rustls-webpki 0.103.8", + "security-framework 3.5.1", + "security-framework-sys", + "webpki-root-certs", + "windows-sys 0.61.2", ] +[[package]] +name = "rustls-platform-verifier-android" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" + [[package]] name = "rustls-webpki" version = "0.102.8" @@ -6464,9 +6958,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.4" +version = "0.103.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc" +checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" dependencies = [ "aws-lc-rs", "ring", @@ -6482,9 +6976,9 @@ checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "rusty-fork" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" +checksum = "cc6bf79ff24e648f6da1f8d1f011e9cac26491b619e6b9280f2b47f1774e6ee2" dependencies = [ "fnv", "quick-error", @@ -6492,21 +6986,6 @@ dependencies = [ "wait-timeout", ] -[[package]] -name = "rustyline-async" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e07ddce8399c61495b405dc94d4f30d01fc1c5e1238f10b9c09940678bc81ab" -dependencies = [ - "ansi-width", - "crossterm", - "futures-util", - "pin-project", - "thingbuf", - "thiserror 2.0.16", - "unicode-segmentation", -] - [[package]] name = "ryu" version = "1.0.20" @@ -6518,11 +6997,11 @@ name = "safelog" version = "0.4.8" source = "git+https://github.com/Start9Labs/arti.git?branch=patch%2Fdisable-exit#24730694701a83432d791d80802db8bda0699700" dependencies = [ - "derive_more", + "derive_more 2.0.1", "educe", "either", "fluid-let", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] @@ -6545,11 +7024,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -6566,9 +7045,9 @@ dependencies = [ [[package]] name = "schemars" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82d20c4491bc164fa2f6c5d44565947a52ad80b9505d8e36f8d54c27c739fcd0" +checksum = "1317c3bf3e7df961da95b0a56a172a02abead31276215a0497241a7624b487ce" dependencies = [ "dyn-clone", "ref-cast", @@ -6576,22 +7055,18 @@ dependencies = [ "serde_json", ] +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "sct" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" -dependencies = [ - "ring", - "untrusted", -] - [[package]] name = "sec1" version = "0.7.3" @@ -6612,8 +7087,21 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.9.3", - "core-foundation", + "bitflags 2.10.0", + "core-foundation 0.9.4", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework" +version = "3.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" +dependencies = [ + "bitflags 2.10.0", + "core-foundation 0.10.1", "core-foundation-sys", "libc", "security-framework-sys", @@ -6621,9 +7109,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.14.0" +version = "2.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" dependencies = [ "core-foundation-sys", "libc", @@ -6631,19 +7119,21 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.26" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" dependencies = [ "serde", + "serde_core", ] [[package]] name = "serde" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ + "serde_core", "serde_derive", ] @@ -6668,11 +7158,12 @@ dependencies = [ [[package]] name = "serde_bytes" -version = "0.11.17" +version = "0.11.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8437fd221bde2d4ca316d61b90e337e9e702b3820b87d63caa9ba6c02bd06d96" +checksum = "a5d440709e79d88e51ac01c4b72fc6cb7314017bb7da9eeff678aa94c10e3ea8" dependencies = [ "serde", + "serde_core", ] [[package]] @@ -6684,46 +7175,58 @@ dependencies = [ ] [[package]] -name = "serde_derive" -version = "1.0.219" +name = "serde_core" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] name = "serde_ignored" -version = "0.1.12" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b516445dac1e3535b6d658a7b528d771153dfb272ed4180ca4617a20550365ff" +checksum = "115dffd5f3853e06e746965a20dcbae6ee747ae30b543d91b0e089668bb07798" dependencies = [ "serde", + "serde_core", ] [[package]] name = "serde_json" -version = "1.0.143" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ - "indexmap 2.11.0", + "indexmap 2.12.0", "itoa", "memchr", "ryu", "serde", + "serde_core", ] [[package]] name = "serde_path_to_error" -version = "0.1.17" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59fab13f937fa393d08645bf3a84bdfe86e296747b506ada67bb15f10f218b2a" +checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" dependencies = [ "itoa", "serde", + "serde_core", ] [[package]] @@ -6745,7 +7248,7 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -6759,11 +7262,11 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "1.0.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40734c41988f7306bb04f0ecf60ec0f3f1caa34290e4e8ea471dcd3346483b83" +checksum = "e24345aa0fe688594e73770a5f6d1b216508b4f93484c0026d521acd30134392" dependencies = [ - "serde", + "serde_core", ] [[package]] @@ -6780,19 +7283,18 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.14.0" +version = "3.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2c45cd61fefa9db6f254525d46e392b852e0e61d9a1fd36e5bd183450a556d5" +checksum = "aa66c845eee442168b2c8134fec70ac50dc20e760769c8ba0ad1319ca1959b04" dependencies = [ "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.11.0", + "indexmap 2.12.0", "schemars 0.9.0", - "schemars 1.0.4", - "serde", - "serde_derive", + "schemars 1.0.5", + "serde_core", "serde_json", "serde_with_macros", "time", @@ -6800,14 +7302,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.14.0" +version = "3.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de90945e6565ce0d9a25098082ed4ee4002e047cb59892c318d66821e14bb30f" +checksum = "b91a903660542fced4e99881aa481bdbaec1634568ee02e0b8bd57c64cb38955" dependencies = [ - "darling 0.20.11", + "darling 0.21.3", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -6816,7 +7318,7 @@ version = "0.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59e2dd588bf1597a252c3b920e0143eb99b0f76e4e082f4c92ce34fbc9e71ddd" dependencies = [ - "indexmap 2.11.0", + "indexmap 2.12.0", "itoa", "libyml", "memchr", @@ -6825,6 +7327,17 @@ dependencies = [ "version_check", ] +[[package]] +name = "serial2" +version = "0.2.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cc76fa68e25e771492ca1e3c53d447ef0be3093e05cd3b47f4b712ba10c6f3c" +dependencies = [ + "cfg-if", + "libc", + "winapi", +] + [[package]] name = "sha-crypt" version = "0.5.0" @@ -6872,6 +7385,18 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "sha3" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809" +dependencies = [ + "block-buffer 0.9.0", + "digest 0.9.0", + "keccak", + "opaque-debug", +] + [[package]] name = "sha3" version = "0.10.8" @@ -6891,6 +7416,16 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shared_library" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a9e7e0f2bfae24d8a5b5a66c5b257a83c7412304311512a0c054cd5e619da11" +dependencies = [ + "lazy_static", + "libc", +] + [[package]] name = "shell-words" version = "1.1.0" @@ -6926,9 +7461,9 @@ dependencies = [ [[package]] name = "signal-hook-mio" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd" +checksum = "b75a19a7a740b25bc7944bdee6172368f988763b744e3d4dfe753f6b4ece40cc" dependencies = [ "libc", "mio", @@ -6995,6 +7530,22 @@ version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" +[[package]] +name = "sled" +version = "0.34.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f96b4737c2ce5987354855aed3797279def4ebf734436c6aa4552cf8e169935" +dependencies = [ + "crc32fast", + "crossbeam-epoch", + "crossbeam-utils", + "fs2", + "fxhash", + "libc", + "log", + "parking_lot 0.11.2", +] + [[package]] name = "slotmap" version = "1.0.7" @@ -7013,10 +7564,20 @@ dependencies = [ "paste", "serde", "slotmap", - "thiserror 2.0.16", + "thiserror 2.0.17", "void", ] +[[package]] +name = "smallstr" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "862077b1e764f04c251fe82a2ef562fd78d7cadaeb072ca7c2bcaf7217b1ff3b" +dependencies = [ + "serde", + "smallvec", +] + [[package]] name = "smallvec" version = "1.15.1" @@ -7033,10 +7594,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" [[package]] -name = "smtp-proto" -version = "0.1.6" +name = "smithay-client-toolkit" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7d3950ab75b03c52f2f13fd52aab91c9d62698b231b67240e85c3ef5301e63e" +checksum = "870427e30b8f2cbe64bf43ec4b86e88fe39b0a84b3f15efd9c9c2d020bc86eb9" +dependencies = [ + "bitflags 1.3.2", + "dlib", + "lazy_static", + "log", + "memmap2 0.5.10", + "nix 0.24.3", + "pkg-config", + "wayland-client", + "wayland-cursor", + "wayland-protocols", +] + +[[package]] +name = "smithay-clipboard" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a345c870a1fae0b1b779085e81b51e614767c239e93503588e54c5b17f4b0e8" +dependencies = [ + "smithay-client-toolkit", + "wayland-client", +] [[package]] name = "socket2" @@ -7050,12 +7633,12 @@ dependencies = [ [[package]] name = "socket2" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" +checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -7067,16 +7650,10 @@ dependencies = [ "async-trait", "bytes", "percent-encoding", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", ] -[[package]] -name = "solana-nohash-hasher" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b8a731ed60e89177c8a7ab05fe0f1511cedd3e70e773f288f9de33a9cfdc21e" - [[package]] name = "spin" version = "0.9.8" @@ -7122,17 +7699,17 @@ dependencies = [ "futures-util", "hashbrown 0.15.5", "hashlink", - "indexmap 2.11.0", + "indexmap 2.12.0", "log", "memchr", "once_cell", "percent-encoding", - "rustls 0.23.31", + "rustls 0.23.35", "serde", "serde_json", "sha2 0.10.9", "smallvec", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tokio-stream", "tracing", @@ -7150,7 +7727,7 @@ dependencies = [ "quote", "sqlx-core", "sqlx-macros-core", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -7171,7 +7748,7 @@ dependencies = [ "sha2 0.10.9", "sqlx-core", "sqlx-postgres", - "syn 2.0.106", + "syn 2.0.108", "tokio", "url", ] @@ -7184,7 +7761,7 @@ checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46" dependencies = [ "atoi", "base64 0.22.1", - "bitflags 2.9.3", + "bitflags 2.10.0", "byteorder", "crc", "dotenvy", @@ -7194,7 +7771,7 @@ dependencies = [ "futures-util", "hex", "hkdf", - "hmac", + "hmac 0.12.1", "home", "itoa", "log", @@ -7208,16 +7785,16 @@ dependencies = [ "smallvec", "sqlx-core", "stringprep", - "thiserror 2.0.16", + "thiserror 2.0.17", "tracing", "whoami", ] [[package]] name = "sscanf" -version = "0.4.1" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c713ebd15ce561dd4a13ed62bc2a0368e16806fc30dcaf66ecf1256b2a3fdde6" +checksum = "569fdd714955aad3acdde5d13129eaa6c4576b759c0585488c84ad395263138a" dependencies = [ "const_format", "lazy_static", @@ -7227,16 +7804,16 @@ dependencies = [ [[package]] name = "sscanf_macro" -version = "0.4.1" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84955aa74a157e5834d58a07be11af7f0ab923f0194a0bb2ea6b3db8b5d1611d" +checksum = "77faf04b02dc0dd55e6713fcae44aa6e8882570bae2bd873949924d6e57cca82" dependencies = [ "convert_case 0.6.0", "proc-macro2", "quote", "regex-syntax 0.6.29", - "strsim 0.10.0", - "syn 2.0.106", + "strsim 0.11.1", + "syn 2.0.108", "unicode-width 0.1.14", ] @@ -7284,13 +7861,26 @@ dependencies = [ [[package]] name = "stable_deref_trait" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "stacker" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1f8b29fb42aafcea4edeeb6b2f2d7ecd0d969c48b4cf0d2e64aafc471dd6e59" +dependencies = [ + "cc", + "cfg-if", + "libc", + "psm", + "windows-sys 0.59.0", +] [[package]] name = "start-os" -version = "0.4.0-alpha.11" +version = "0.4.0-alpha.12" dependencies = [ "aes 0.7.5", "arti-client", @@ -7298,11 +7888,11 @@ dependencies = [ "async-compression", "async-stream", "async-trait", - "axum 0.8.4", - "backhand", + "aws-lc-sys", + "axum 0.8.6", "backtrace-on-stack-overflow", "barrage", - "base32", + "base32 0.5.1", "base64 0.22.1", "base64ct", "basic-cookies", @@ -7317,6 +7907,7 @@ dependencies = [ "const_format", "cookie", "cookie_store", + "curve25519-dalek 4.1.3", "der", "digest 0.10.7", "divrem", @@ -7333,16 +7924,17 @@ dependencies = [ "hex", "hickory-client", "hickory-server", - "hmac", + "hmac 0.12.1", "http", "http-body-util", "hyper", "hyper-util", "id-pool", + "iddqd", "imbl", "imbl-value 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "include_dir", - "indexmap 2.11.0", + "indexmap 2.12.0", "indicatif", "inotify", "integer-encoding", @@ -7356,10 +7948,11 @@ dependencies = [ "lazy_async_pool", "lazy_format", "lazy_static", + "lettre", "libc", "log", - "mail-send", "mbrman", + "miette", "mio", "models", "new_mime_guess", @@ -7382,6 +7975,7 @@ dependencies = [ "proptest-derive", "pty-process", "qrcode", + "r3bl_tui", "rand 0.9.2", "regex", "reqwest", @@ -7389,9 +7983,6 @@ dependencies = [ "rpassword", "rpc-toolkit", "rust-argon2", - "rustls 0.23.31", - "rustls-pki-types", - "rustyline-async", "safelog", "semver", "serde", @@ -7404,7 +7995,7 @@ dependencies = [ "shell-words", "signal-hook", "simple-logging", - "socket2 0.6.0", + "socket2 0.6.1", "socks5-impl", "sqlx", "sscanf", @@ -7412,12 +8003,12 @@ dependencies = [ "tar", "termion", "textwrap", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", - "tokio-rustls 0.26.2", + "tokio-rustls 0.26.4", "tokio-stream", "tokio-tar", - "tokio-tungstenite", + "tokio-tungstenite 0.26.2", "tokio-util", "toml 0.8.23", "tor-cell", @@ -7427,6 +8018,7 @@ dependencies = [ "tor-llcrypto", "tor-proto", "tor-rtcompat", + "torut", "tower-service", "tracing", "tracing-error", @@ -7439,6 +8031,8 @@ dependencies = [ "url", "urlencoding", "uuid", + "visit-rs", + "x25519-dalek", "zbus", "zeroize", ] @@ -7456,7 +8050,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f" dependencies = [ "new_debug_unreachable", - "parking_lot", + "parking_lot 0.12.5", "phf_shared 0.11.3", "precomputed-hash", ] @@ -7472,6 +8066,24 @@ dependencies = [ "unicode-properties", ] +[[package]] +name = "strip-ansi" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e397af0b9266a4e521ed5a4891cc715902af8dd221cba1a187f552bd044d970" +dependencies = [ + "ansi-regex", +] + +[[package]] +name = "strip-ansi-escapes" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a8f8038e7e7969abb3f1b7c2a811225e9296da208539e0f79c5251d6cac0025" +dependencies = [ + "vte", +] + [[package]] name = "strsim" version = "0.10.0" @@ -7502,7 +8114,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -7511,6 +8123,27 @@ version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" +[[package]] +name = "supports-color" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c64fc7232dd8d2e4ac5ce4ef302b1d81e0b80d055b9d77c7c4f51f6aa4c867d6" +dependencies = [ + "is_ci", +] + +[[package]] +name = "supports-hyperlinks" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "804f44ed3c63152de6a9f90acbea1a110441de43006ea51bcce8f436196a288b" + +[[package]] +name = "supports-unicode" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7401a30af6cb5818bb64852270bb722533397edcfc7344954a38f420819ece2" + [[package]] name = "syn" version = "1.0.109" @@ -7524,9 +8157,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.106" +version = "2.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917" dependencies = [ "proc-macro2", "quote", @@ -7550,7 +8183,28 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", +] + +[[package]] +name = "syntect" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "656b45c05d95a5704399aeef6bd0ddec7b2b3531b7c9e900abbf7c4d2190c925" +dependencies = [ + "bincode 1.3.3", + "flate2", + "fnv", + "once_cell", + "onig", + "plist", + "regex-syntax 0.8.8", + "serde", + "serde_derive", + "serde_json", + "thiserror 2.0.17", + "walkdir", + "yaml-rust", ] [[package]] @@ -7573,8 +8227,8 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ - "bitflags 2.9.3", - "core-foundation", + "bitflags 2.10.0", + "core-foundation 0.9.4", "system-configuration-sys", ] @@ -7602,20 +8256,20 @@ checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a" dependencies = [ "filetime", "libc", - "xattr 1.5.1", + "xattr 1.6.1", ] [[package]] name = "tempfile" -version = "3.21.0" +version = "3.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15b61f8f20e3a6f7e0649d825294eaf317edce30f82cf6026e7e4cb9222a7d1e" +checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" dependencies = [ "fastrand", - "getrandom 0.3.3", + "getrandom 0.3.4", "once_cell", - "rustix 1.0.8", - "windows-sys 0.60.2", + "rustix 1.1.2", + "windows-sys 0.61.2", ] [[package]] @@ -7638,6 +8292,16 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "terminal_size" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b8cb979cb11c32ce1603f8137b22262a9d131aaa5c37b5678025f22b8becd0" +dependencies = [ + "rustix 1.1.2", + "windows-sys 0.60.2", +] + [[package]] name = "termion" version = "4.0.5" @@ -7658,17 +8322,7 @@ checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057" dependencies = [ "smawk", "unicode-linebreak", - "unicode-width 0.2.1", -] - -[[package]] -name = "thingbuf" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "662b54ef6f7b4e71f683dadc787bbb2d8e8ef2f91b682ebed3164a5a7abca905" -dependencies = [ - "parking_lot", - "pin-project", + "unicode-width 0.2.2", ] [[package]] @@ -7682,11 +8336,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.16" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" dependencies = [ - "thiserror-impl 2.0.16", + "thiserror-impl 2.0.17", ] [[package]] @@ -7697,18 +8351,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] name = "thiserror-impl" -version = "2.0.16" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -7733,9 +8387,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.41" +version = "0.3.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" +checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" dependencies = [ "deranged", "itoa", @@ -7748,15 +8402,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.4" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" +checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" [[package]] name = "time-macros" -version = "0.2.22" +version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" +checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" dependencies = [ "num-conv", "time-core", @@ -7773,11 +8427,12 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" dependencies = [ "displaydoc", + "serde_core", "zerovec", ] @@ -7808,34 +8463,31 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.47.1" +version = "1.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" +checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" dependencies = [ - "backtrace", "bytes", - "io-uring", "libc", "mio", - "parking_lot", + "parking_lot 0.12.5", "pin-project-lite", "signal-hook-registry", - "slab", - "socket2 0.6.0", + "socket2 0.6.1", "tokio-macros", "tracing", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "tokio-macros" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -7848,16 +8500,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-rustls" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" -dependencies = [ - "rustls 0.21.12", - "tokio", -] - [[package]] name = "tokio-rustls" version = "0.25.0" @@ -7871,11 +8513,11 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.26.2" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ - "rustls 0.23.31", + "rustls 0.23.35", "tokio", ] @@ -7916,14 +8558,26 @@ dependencies = [ "native-tls", "tokio", "tokio-native-tls", - "tungstenite", + "tungstenite 0.26.2", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25a406cddcc431a75d3d9afc6a7c0f7428d4891dd973e4d54c56b46127bf857" +dependencies = [ + "futures-util", + "log", + "tokio", + "tungstenite 0.28.0", ] [[package]] name = "tokio-util" -version = "0.7.16" +version = "0.7.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5" +checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594" dependencies = [ "bytes", "futures-core", @@ -7933,6 +8587,15 @@ dependencies = [ "tokio", ] +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + [[package]] name = "toml" version = "0.8.23" @@ -7942,19 +8605,19 @@ dependencies = [ "serde", "serde_spanned 0.6.9", "toml_datetime 0.6.11", - "toml_edit", + "toml_edit 0.22.27", ] [[package]] name = "toml" -version = "0.9.5" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75129e1dc5000bfbaa9fee9d1b21f974f9fbad9daec557a521ee6e080825f6e8" +checksum = "f0dc8b1fb61449e27716ec0e1bdf0f6b8f3e8f6b05391e8497b8b6d7804ea6d8" dependencies = [ - "indexmap 2.11.0", - "serde", - "serde_spanned 1.0.0", - "toml_datetime 0.7.0", + "indexmap 2.12.0", + "serde_core", + "serde_spanned 1.0.3", + "toml_datetime 0.7.3", "toml_parser", "toml_writer", "winnow", @@ -7971,11 +8634,11 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.7.0" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bade1c3e902f58d73d3f294cd7f20391c1cb2fbcb643b73566bc773971df91e3" +checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533" dependencies = [ - "serde", + "serde_core", ] [[package]] @@ -7984,7 +8647,7 @@ version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ - "indexmap 2.11.0", + "indexmap 2.12.0", "serde", "serde_spanned 0.6.9", "toml_datetime 0.6.11", @@ -7993,10 +8656,22 @@ dependencies = [ ] [[package]] -name = "toml_parser" -version = "1.0.2" +name = "toml_edit" +version = "0.23.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b551886f449aa90d4fe2bdaa9f4a2577ad2dde302c61ecf262d80b116db95c10" +checksum = "6485ef6d0d9b5d0ec17244ff7eb05310113c3f316f2d14200d4de56b3cb98f8d" +dependencies = [ + "indexmap 2.12.0", + "toml_datetime 0.7.3", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" dependencies = [ "winnow", ] @@ -8009,9 +8684,9 @@ checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" [[package]] name = "toml_writer" -version = "1.0.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc842091f2def52017664b53082ecbbeb5c7731092bad69d2c63050401dfd64" +checksum = "df8b2b54733674ad286d16267dcfc7a71ed5c776e4ac7aa3c3e2561f7c637bf2" [[package]] name = "tonic" @@ -8054,7 +8729,7 @@ dependencies = [ "oneshot-fused-workaround", "pin-project", "postage", - "thiserror 2.0.16", + "thiserror 2.0.17", "void", ] @@ -8063,7 +8738,7 @@ name = "tor-basic-utils" version = "0.33.0" source = "git+https://github.com/Start9Labs/arti.git?branch=patch%2Fdisable-exit#24730694701a83432d791d80802db8bda0699700" dependencies = [ - "derive_more", + "derive_more 2.0.1", "hex", "itertools 0.14.0", "libc", @@ -8073,7 +8748,7 @@ dependencies = [ "serde", "slab", "smallvec", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] @@ -8085,9 +8760,9 @@ dependencies = [ "derive-deftly 1.2.0", "digest 0.10.7", "educe", - "getrandom 0.3.3", + "getrandom 0.3.4", "safelog", - "thiserror 2.0.16", + "thiserror 2.0.17", "tor-error", "tor-llcrypto", "zeroize", @@ -8099,17 +8774,17 @@ version = "0.33.0" source = "git+https://github.com/Start9Labs/arti.git?branch=patch%2Fdisable-exit#24730694701a83432d791d80802db8bda0699700" dependencies = [ "amplify", - "bitflags 2.9.3", + "bitflags 2.10.0", "bytes", "caret", "derive-deftly 1.2.0", - "derive_more", + "derive_more 2.0.1", "educe", "itertools 0.14.0", "paste", "rand 0.9.2", "smallvec", - "thiserror 2.0.16", + "thiserror 2.0.17", "tor-basic-utils", "tor-bytes", "tor-cert", @@ -8130,9 +8805,9 @@ source = "git+https://github.com/Start9Labs/arti.git?branch=patch%2Fdisable-exit dependencies = [ "caret", "derive_builder_fork_arti", - "derive_more", + "derive_more 2.0.1", "digest 0.10.7", - "thiserror 2.0.16", + "thiserror 2.0.17", "tor-bytes", "tor-checkable", "tor-llcrypto", @@ -8146,7 +8821,7 @@ dependencies = [ "async-trait", "caret", "derive_builder_fork_arti", - "derive_more", + "derive_more 2.0.1", "educe", "futures", "oneshot-fused-workaround", @@ -8154,7 +8829,7 @@ dependencies = [ "rand 0.9.2", "safelog", "serde", - "thiserror 2.0.16", + "thiserror 2.0.17", "tor-async-utils", "tor-basic-utils", "tor-cell", @@ -8180,7 +8855,7 @@ source = "git+https://github.com/Start9Labs/arti.git?branch=patch%2Fdisable-exit dependencies = [ "humantime", "signature 2.2.0", - "thiserror 2.0.16", + "thiserror 2.0.17", "tor-llcrypto", ] @@ -8195,8 +8870,8 @@ dependencies = [ "cfg-if", "derive-deftly 1.2.0", "derive_builder_fork_arti", - "derive_more", - "downcast-rs", + "derive_more 2.0.1", + "downcast-rs 2.0.2", "dyn-clone", "educe", "futures", @@ -8210,7 +8885,7 @@ dependencies = [ "safelog", "serde", "static_assertions", - "thiserror 2.0.16", + "thiserror 2.0.17", "tor-async-utils", "tor-basic-utils", "tor-cell", @@ -8256,8 +8931,8 @@ dependencies = [ "serde-value", "serde_ignored", "strum", - "thiserror 2.0.16", - "toml 0.9.5", + "thiserror 2.0.17", + "toml 0.9.8", "tor-basic-utils", "tor-error", "tor-rtcompat", @@ -8273,7 +8948,7 @@ dependencies = [ "directories", "serde", "shellexpand", - "thiserror 2.0.16", + "thiserror 2.0.17", "tor-error", "tor-general-addr", ] @@ -8285,7 +8960,7 @@ source = "git+https://github.com/Start9Labs/arti.git?branch=patch%2Fdisable-exit dependencies = [ "digest 0.10.7", "hex", - "thiserror 2.0.16", + "thiserror 2.0.17", "tor-llcrypto", ] @@ -8296,7 +8971,7 @@ source = "git+https://github.com/Start9Labs/arti.git?branch=patch%2Fdisable-exit dependencies = [ "async-compression", "base64ct", - "derive_more", + "derive_more 2.0.1", "futures", "hex", "http", @@ -8304,7 +8979,7 @@ dependencies = [ "httpdate", "itertools 0.14.0", "memchr", - "thiserror 2.0.16", + "thiserror 2.0.17", "tor-circmgr", "tor-error", "tor-hscrypto", @@ -8324,7 +8999,7 @@ dependencies = [ "async-trait", "base64ct", "derive_builder_fork_arti", - "derive_more", + "derive_more 2.0.1", "digest 0.10.7", "educe", "event-listener 5.4.1", @@ -8335,7 +9010,7 @@ dependencies = [ "humantime", "humantime-serde", "itertools 0.14.0", - "memmap2", + "memmap2 0.9.9", "oneshot-fused-workaround", "paste", "postage", @@ -8348,7 +9023,7 @@ dependencies = [ "signature 2.2.0", "static_assertions", "strum", - "thiserror 2.0.16", + "thiserror 2.0.17", "time", "tor-async-utils", "tor-basic-utils", @@ -8374,13 +9049,13 @@ name = "tor-error" version = "0.33.0" source = "git+https://github.com/Start9Labs/arti.git?branch=patch%2Fdisable-exit#24730694701a83432d791d80802db8bda0699700" dependencies = [ - "derive_more", + "derive_more 2.0.1", "futures", "paste", "retry-error", "static_assertions", "strum", - "thiserror 2.0.16", + "thiserror 2.0.17", "tracing", "void", ] @@ -8391,8 +9066,8 @@ version = "0.33.0" source = "git+https://github.com/Start9Labs/arti.git?branch=patch%2Fdisable-exit#24730694701a83432d791d80802db8bda0699700" dependencies = [ "arbitrary", - "derive_more", - "thiserror 2.0.16", + "derive_more 2.0.1", + "thiserror 2.0.17", "void", ] @@ -8405,7 +9080,7 @@ dependencies = [ "base64ct", "derive-deftly 1.2.0", "derive_builder_fork_arti", - "derive_more", + "derive_more 2.0.1", "dyn-clone", "educe", "futures", @@ -8420,7 +9095,7 @@ dependencies = [ "safelog", "serde", "strum", - "thiserror 2.0.16", + "thiserror 2.0.17", "tor-async-utils", "tor-basic-utils", "tor-config", @@ -8444,7 +9119,7 @@ source = "git+https://github.com/Start9Labs/arti.git?branch=patch%2Fdisable-exit dependencies = [ "async-trait", "derive-deftly 1.2.0", - "derive_more", + "derive_more 2.0.1", "educe", "either", "futures", @@ -8456,7 +9131,7 @@ dependencies = [ "safelog", "slotmap-careful", "strum", - "thiserror 2.0.16", + "thiserror 2.0.17", "tor-async-utils", "tor-basic-utils", "tor-bytes", @@ -8488,7 +9163,7 @@ dependencies = [ "cipher 0.4.4", "data-encoding", "derive-deftly 1.2.0", - "derive_more", + "derive_more 2.0.1", "digest 0.10.7", "equix", "hex", @@ -8500,7 +9175,7 @@ dependencies = [ "serde", "signature 2.2.0", "subtle", - "thiserror 2.0.16", + "thiserror 2.0.17", "tor-basic-utils", "tor-bytes", "tor-error", @@ -8523,7 +9198,7 @@ dependencies = [ "cfg-if", "derive-deftly 1.2.0", "derive_builder_fork_arti", - "derive_more", + "derive_more 2.0.1", "digest 0.10.7", "educe", "fs-mistrust", @@ -8543,7 +9218,7 @@ dependencies = [ "serde", "serde_with", "strum", - "thiserror 2.0.16", + "thiserror 2.0.17", "tor-async-utils", "tor-basic-utils", "tor-bytes", @@ -8575,13 +9250,13 @@ version = "0.33.0" source = "git+https://github.com/Start9Labs/arti.git?branch=patch%2Fdisable-exit#24730694701a83432d791d80802db8bda0699700" dependencies = [ "derive-deftly 1.2.0", - "derive_more", - "downcast-rs", + "derive_more 2.0.1", + "downcast-rs 2.0.2", "paste", "rand 0.9.2", "signature 2.2.0", "ssh-key", - "thiserror 2.0.16", + "thiserror 2.0.17", "tor-bytes", "tor-cert", "tor-checkable", @@ -8599,8 +9274,8 @@ dependencies = [ "cfg-if", "derive-deftly 1.2.0", "derive_builder_fork_arti", - "derive_more", - "downcast-rs", + "derive_more 2.0.1", + "downcast-rs 2.0.2", "dyn-clone", "fs-mistrust", "glob-match", @@ -8612,7 +9287,7 @@ dependencies = [ "serde", "signature 2.2.0", "ssh-key", - "thiserror 2.0.16", + "thiserror 2.0.17", "tor-basic-utils", "tor-bytes", "tor-config", @@ -8638,14 +9313,14 @@ dependencies = [ "caret", "derive-deftly 1.2.0", "derive_builder_fork_arti", - "derive_more", + "derive_more 2.0.1", "hex", "itertools 0.14.0", "safelog", "serde", "serde_with", "strum", - "thiserror 2.0.16", + "thiserror 2.0.17", "tor-basic-utils", "tor-bytes", "tor-config", @@ -8665,11 +9340,11 @@ dependencies = [ "curve25519-dalek 4.1.3", "der-parser 10.0.0", "derive-deftly 1.2.0", - "derive_more", + "derive_more 2.0.1", "digest 0.10.7", "ed25519-dalek 2.2.0", "educe", - "getrandom 0.3.3", + "getrandom 0.3.4", "hex", "rand 0.9.2", "rand_chacha 0.9.0", @@ -8682,10 +9357,10 @@ dependencies = [ "serde", "sha1", "sha2 0.10.9", - "sha3", + "sha3 0.10.8", "signature 2.2.0", "subtle", - "thiserror 2.0.16", + "thiserror 2.0.17", "tor-memquota", "visibility", "x25519-dalek", @@ -8699,7 +9374,7 @@ source = "git+https://github.com/Start9Labs/arti.git?branch=patch%2Fdisable-exit dependencies = [ "futures", "humantime", - "thiserror 2.0.16", + "thiserror 2.0.17", "tor-error", "tor-rtcompat", "tracing", @@ -8713,7 +9388,7 @@ source = "git+https://github.com/Start9Labs/arti.git?branch=patch%2Fdisable-exit dependencies = [ "cfg-if", "derive-deftly 1.2.0", - "derive_more", + "derive_more 2.0.1", "dyn-clone", "educe", "futures", @@ -8724,7 +9399,7 @@ dependencies = [ "slotmap-careful", "static_assertions", "sysinfo", - "thiserror 2.0.16", + "thiserror 2.0.17", "tor-async-utils", "tor-basic-utils", "tor-config", @@ -8741,8 +9416,8 @@ version = "0.33.0" source = "git+https://github.com/Start9Labs/arti.git?branch=patch%2Fdisable-exit#24730694701a83432d791d80802db8bda0699700" dependencies = [ "async-trait", - "bitflags 2.9.3", - "derive_more", + "bitflags 2.10.0", + "derive_more 2.0.1", "digest 0.10.7", "futures", "hex", @@ -8753,7 +9428,7 @@ dependencies = [ "serde", "static_assertions", "strum", - "thiserror 2.0.16", + "thiserror 2.0.17", "time", "tor-basic-utils", "tor-error", @@ -8774,11 +9449,11 @@ source = "git+https://github.com/Start9Labs/arti.git?branch=patch%2Fdisable-exit dependencies = [ "amplify", "base64ct", - "bitflags 2.9.3", + "bitflags 2.10.0", "cipher 0.4.4", "derive-deftly 1.2.0", "derive_builder_fork_arti", - "derive_more", + "derive_more 2.0.1", "digest 0.10.7", "educe", "hex", @@ -8786,7 +9461,7 @@ dependencies = [ "itertools 0.14.0", "memchr", "paste", - "phf", + "phf 0.13.1", "rand 0.9.2", "serde", "serde_with", @@ -8794,7 +9469,7 @@ dependencies = [ "smallvec", "strum", "subtle", - "thiserror 2.0.16", + "thiserror 2.0.17", "time", "tinystr", "tor-basic-utils", @@ -8820,7 +9495,7 @@ source = "git+https://github.com/Start9Labs/arti.git?branch=patch%2Fdisable-exit dependencies = [ "amplify", "derive-deftly 1.2.0", - "derive_more", + "derive_more 2.0.1", "filetime", "fs-mistrust", "fslock", @@ -8832,7 +9507,7 @@ dependencies = [ "sanitize-filename", "serde", "serde_json", - "thiserror 2.0.16", + "thiserror 2.0.17", "time", "tor-async-utils", "tor-basic-utils", @@ -8857,13 +9532,13 @@ dependencies = [ "criterion-cycles-per-byte", "derive-deftly 1.2.0", "derive_builder_fork_arti", - "derive_more", + "derive_more 2.0.1", "digest 0.10.7", "educe", "futures", "futures-util", "hkdf", - "hmac", + "hmac 0.12.1", "itertools 0.14.0", "oneshot-fused-workaround", "pin-project", @@ -8876,7 +9551,7 @@ dependencies = [ "static_assertions", "subtle", "sync_wrapper", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tokio-util", "tor-async-utils", @@ -8911,7 +9586,7 @@ dependencies = [ "caret", "paste", "serde_with", - "thiserror 2.0.16", + "thiserror 2.0.17", "tor-bytes", ] @@ -8941,7 +9616,7 @@ dependencies = [ "async_executors", "asynchronous-codec", "coarsetime", - "derive_more", + "derive_more 2.0.1", "dyn-clone", "educe", "futures", @@ -8952,8 +9627,8 @@ dependencies = [ "paste", "pin-project", "rustls-pki-types", - "rustls-webpki 0.103.4", - "thiserror 2.0.16", + "rustls-webpki 0.103.8", + "thiserror 2.0.17", "tokio", "tokio-util", "tor-error", @@ -8971,7 +9646,7 @@ dependencies = [ "assert_matches", "async-trait", "derive-deftly 1.2.0", - "derive_more", + "derive_more 2.0.1", "educe", "futures", "humantime", @@ -8981,7 +9656,7 @@ dependencies = [ "priority-queue", "slotmap-careful", "strum", - "thiserror 2.0.16", + "thiserror 2.0.17", "tor-error", "tor-general-addr", "tor-rtcompat", @@ -9001,7 +9676,7 @@ dependencies = [ "educe", "safelog", "subtle", - "thiserror 2.0.16", + "thiserror 2.0.17", "tor-bytes", "tor-error", ] @@ -9012,12 +9687,32 @@ version = "0.33.0" source = "git+https://github.com/Start9Labs/arti.git?branch=patch%2Fdisable-exit#24730694701a83432d791d80802db8bda0699700" dependencies = [ "derive-deftly 1.2.0", - "derive_more", + "derive_more 2.0.1", "serde", - "thiserror 2.0.16", + "thiserror 2.0.17", "tor-memquota", ] +[[package]] +name = "torut" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99febc413f26cf855b3a309c5872edff5c31e0ffe9c2fce5681868761df36f69" +dependencies = [ + "base32 0.4.0", + "base64 0.13.1", + "derive_more 0.99.20", + "ed25519-dalek 1.0.1", + "hex", + "hmac 0.11.0", + "rand 0.7.3", + "serde", + "serde_derive", + "sha2 0.9.9", + "sha3 0.9.1", + "tokio", +] + [[package]] name = "tower" version = "0.4.13" @@ -9060,7 +9755,7 @@ version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.10.0", "bytes", "futures-util", "http", @@ -9096,6 +9791,18 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-appender" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3566e8ce28cc0a3fe42519fc80e6b4c943cc4c8cef275620eb8dac2d3d4e06cf" +dependencies = [ + "crossbeam-channel", + "thiserror 1.0.69", + "time", + "tracing-subscriber", +] + [[package]] name = "tracing-attributes" version = "0.1.30" @@ -9104,7 +9811,7 @@ checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -9161,14 +9868,14 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.19" +version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" +checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" dependencies = [ "matchers", "nu-ansi-term", "once_cell", - "regex", + "regex-automata", "sharded-slab", "smallvec", "thread_local", @@ -9195,7 +9902,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04659ddb06c87d233c566112c1c9c5b9e98256d9af50ec3bc9c8327f873a7568" dependencies = [ "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -9222,7 +9929,7 @@ checksum = "c88cc88fd23b5a04528f3a8436024f20010a16ec18eb23c164b1242f65860130" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", "termcolor", ] @@ -9240,11 +9947,28 @@ dependencies = [ "native-tls", "rand 0.9.2", "sha1", - "thiserror 2.0.16", + "thiserror 2.0.17", "url", "utf-8", ] +[[package]] +name = "tungstenite" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8628dcc84e5a09eb3d8423d6cb682965dea9133204e8fb3efee74c2a0c259442" +dependencies = [ + "bytes", + "data-encoding", + "http", + "httparse", + "log", + "rand 0.9.2", + "sha1", + "thiserror 2.0.17", + "utf-8", +] + [[package]] name = "typed-builder" version = "0.21.2" @@ -9262,7 +9986,7 @@ checksum = "1ecb9ecf7799210407c14a8cfdfe0173365780968dc57973ed082211958e0b18" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -9283,9 +10007,9 @@ checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" [[package]] name = "typenum" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "ucd-trie" @@ -9333,9 +10057,9 @@ checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" [[package]] name = "unicode-ident" -version = "1.0.18" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "unicode-linebreak" @@ -9345,18 +10069,18 @@ checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" [[package]] name = "unicode-normalization" -version = "0.1.24" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" +checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" dependencies = [ "tinyvec", ] [[package]] name = "unicode-properties" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" +checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" [[package]] name = "unicode-segmentation" @@ -9372,9 +10096,9 @@ checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "unicode-width" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" [[package]] name = "unicode-xid" @@ -9442,12 +10166,13 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.18.0" +version = "1.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f33196643e165781c20a5ead5582283a7dacbb87855d867fbc2df3f81eddc1be" +checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", "js-sys", + "serde", "wasm-bindgen", ] @@ -9489,7 +10214,30 @@ checksum = "d674d135b4a8c1d7e813e2f8d1c9a58308aee4a680323066025e53132218bd91" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", +] + +[[package]] +name = "visit-rs" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccaee8d068e8594cffeb617e934bd19607a71c0b0eaf40bdc548578d59abaae9" +dependencies = [ + "async-stream", + "futures", + "serde", + "visit-rs-derive", +] + +[[package]] +name = "visit-rs-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de41688745bbd6ed24e2f4923026911b523f0c057e10f86f44652a20e65555ce" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.108", ] [[package]] @@ -9498,6 +10246,15 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" +[[package]] +name = "vte" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "231fdcd7ef3037e8330d8e17e61011a2c244126acc0a982f4040ac3f9f0bc077" +dependencies = [ + "memchr", +] + [[package]] name = "wait-timeout" version = "0.2.1" @@ -9539,12 +10296,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] -name = "wasi" -version = "0.14.2+wasi-0.2.4" +name = "wasip2" +version = "1.0.1+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" dependencies = [ - "wit-bindgen-rt", + "wit-bindgen", ] [[package]] @@ -9564,35 +10321,22 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.100" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60" dependencies = [ "cfg-if", "once_cell", "rustversion", "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn 2.0.106", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.50" +version = "0.4.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +checksum = "551f88106c6d5e7ccc7cd9a16f312dd3b5d36ea8b4954304657d5dfba115d4a0" dependencies = [ "cfg-if", "js-sys", @@ -9603,9 +10347,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.100" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -9613,22 +10357,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.100" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc" dependencies = [ + "bumpalo", "proc-macro2", "quote", - "syn 2.0.106", - "wasm-bindgen-backend", + "syn 2.0.108", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.100" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76" dependencies = [ "unicode-ident", ] @@ -9646,6 +10390,79 @@ dependencies = [ "web-sys", ] +[[package]] +name = "wayland-client" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f3b068c05a039c9f755f881dc50f01732214f5685e379829759088967c46715" +dependencies = [ + "bitflags 1.3.2", + "downcast-rs 1.2.1", + "libc", + "nix 0.24.3", + "scoped-tls", + "wayland-commons", + "wayland-scanner", + "wayland-sys", +] + +[[package]] +name = "wayland-commons" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8691f134d584a33a6606d9d717b95c4fa20065605f798a3f350d78dced02a902" +dependencies = [ + "nix 0.24.3", + "once_cell", + "smallvec", + "wayland-sys", +] + +[[package]] +name = "wayland-cursor" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6865c6b66f13d6257bef1cd40cbfe8ef2f150fb8ebbdb1e8e873455931377661" +dependencies = [ + "nix 0.24.3", + "wayland-client", + "xcursor", +] + +[[package]] +name = "wayland-protocols" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b950621f9354b322ee817a23474e479b34be96c2e909c14f7bc0100e9a970bc6" +dependencies = [ + "bitflags 1.3.2", + "wayland-client", + "wayland-commons", + "wayland-scanner", +] + +[[package]] +name = "wayland-scanner" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f4303d8fa22ab852f789e75a967f0a2cdc430a607751c0499bada3e451cbd53" +dependencies = [ + "proc-macro2", + "quote", + "xml-rs", +] + +[[package]] +name = "wayland-sys" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be12ce1a3c39ec7dba25594b97b42cb3195d54953ddb9d3d95a7c3902bc6e9d4" +dependencies = [ + "dlib", + "lazy_static", + "pkg-config", +] + [[package]] name = "weak-table" version = "0.3.2" @@ -9654,9 +10471,9 @@ checksum = "323f4da9523e9a669e1eaf9c6e763892769b1d38c623913647bfdc1532fe4549" [[package]] name = "web-sys" -version = "0.3.77" +version = "0.3.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1" dependencies = [ "js-sys", "wasm-bindgen", @@ -9672,20 +10489,29 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki-root-certs" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee3e3b5f5e80bc89f30ce8d0343bf4e5f12341c51f3e26cbeecbc7c85443e85b" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "webpki-roots" version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" dependencies = [ - "webpki-roots 1.0.2", + "webpki-roots 1.0.4", ] [[package]] name = "webpki-roots" -version = "1.0.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8983c3ab33d6fb807cfcdad2491c4ea8cbc8ed839181c7dfd9c67c83e261b2" +checksum = "b2878ef029c47c6e8cf779119f20fcf52bde7ad42a731b2a304bc221df17571e" dependencies = [ "rustls-pki-types", ] @@ -9712,12 +10538,6 @@ dependencies = [ "wasite", ] -[[package]] -name = "widestring" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd7cf3379ca1aac9eea11fba24fd7e315d621f8dfe35c8d7d2be8b793726e07d" - [[package]] name = "winapi" version = "0.3.9" @@ -9736,11 +10556,20 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0978bf7171b3d90bac376700cb56d606feb40f251a475a5d6634613564460b22" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.61.2", +] + +[[package]] +name = "winapi-wsapoll" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1eafc5f679c576995526e81635d0cf9695841736712b4e892f87abbe6fed3f28" +dependencies = [ + "winapi", ] [[package]] @@ -9756,9 +10585,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" dependencies = [ "windows-collections", - "windows-core", + "windows-core 0.61.2", "windows-future", - "windows-link", + "windows-link 0.1.3", "windows-numerics", ] @@ -9768,7 +10597,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" dependencies = [ - "windows-core", + "windows-core 0.61.2", ] [[package]] @@ -9779,9 +10608,22 @@ checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" dependencies = [ "windows-implement", "windows-interface", - "windows-link", - "windows-result", - "windows-strings", + "windows-link 0.1.3", + "windows-result 0.3.4", + "windows-strings 0.4.2", +] + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link 0.2.1", + "windows-result 0.4.1", + "windows-strings 0.5.1", ] [[package]] @@ -9790,31 +10632,31 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" dependencies = [ - "windows-core", - "windows-link", + "windows-core 0.61.2", + "windows-link 0.1.3", "windows-threading", ] [[package]] name = "windows-implement" -version = "0.60.0" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] name = "windows-interface" -version = "0.59.1" +version = "0.59.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -9823,14 +10665,20 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + [[package]] name = "windows-numerics" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" dependencies = [ - "windows-core", - "windows-link", + "windows-core 0.61.2", + "windows-link 0.1.3", ] [[package]] @@ -9839,9 +10687,9 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b8a9ed28765efc97bbc954883f4e6796c33a06546ebafacbabee9696967499e" dependencies = [ - "windows-link", - "windows-result", - "windows-strings", + "windows-link 0.1.3", + "windows-result 0.3.4", + "windows-strings 0.4.2", ] [[package]] @@ -9850,7 +10698,16 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" dependencies = [ - "windows-link", + "windows-link 0.1.3", +] + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link 0.2.1", ] [[package]] @@ -9859,7 +10716,25 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" dependencies = [ - "windows-link", + "windows-link 0.1.3", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link 0.2.1", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", ] [[package]] @@ -9895,7 +10770,31 @@ version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets 0.53.3", + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link 0.2.1", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", ] [[package]] @@ -9931,19 +10830,19 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.3" +version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ - "windows-link", - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", + "windows-link 0.2.1", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", ] [[package]] @@ -9952,9 +10851,15 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" dependencies = [ - "windows-link", + "windows-link 0.1.3", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -9969,9 +10874,15 @@ checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" [[package]] name = "windows_aarch64_msvc" @@ -9987,9 +10898,15 @@ checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_aarch64_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" [[package]] name = "windows_i686_gnu" @@ -10005,9 +10922,9 @@ checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnu" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" [[package]] name = "windows_i686_gnullvm" @@ -10017,9 +10934,15 @@ checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" [[package]] name = "windows_i686_msvc" @@ -10035,9 +10958,15 @@ checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_i686_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" [[package]] name = "windows_x86_64_gnu" @@ -10053,9 +10982,15 @@ checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnu" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" [[package]] name = "windows_x86_64_gnullvm" @@ -10071,9 +11006,15 @@ checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" [[package]] name = "windows_x86_64_msvc" @@ -10089,9 +11030,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "windows_x86_64_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "winnow" @@ -10104,28 +11045,24 @@ dependencies = [ [[package]] name = "winreg" -version = "0.50.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" dependencies = [ - "cfg-if", - "windows-sys 0.48.0", + "winapi", ] [[package]] -name = "wit-bindgen-rt" -version = "0.39.0" +name = "wit-bindgen" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" -dependencies = [ - "bitflags 2.9.3", -] +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "writeable" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" [[package]] name = "wyz" @@ -10142,6 +11079,37 @@ dependencies = [ "tap", ] +[[package]] +name = "x11-clipboard" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "980b9aa9226c3b7de8e2adb11bf20124327c054e0e5812d2aac0b5b5a87e7464" +dependencies = [ + "x11rb", +] + +[[package]] +name = "x11rb" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "592b4883219f345e712b3209c62654ebda0bb50887f330cbd018d0f654bfd507" +dependencies = [ + "gethostname", + "nix 0.24.3", + "winapi", + "winapi-wsapoll", + "x11rb-protocol", +] + +[[package]] +name = "x11rb-protocol" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56b245751c0ac9db0e006dc812031482784e434630205a93c73cfefcaabeac67" +dependencies = [ + "nix 0.24.3", +] + [[package]] name = "x25519-dalek" version = "2.0.1" @@ -10182,29 +11150,32 @@ dependencies = [ [[package]] name = "xattr" -version = "1.5.1" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af3a19837351dc82ba89f8a125e22a3c475f05aba604acc023d62b2739ae2909" +checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" dependencies = [ "libc", - "rustix 1.0.8", + "rustix 1.1.2", ] +[[package]] +name = "xcursor" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec9e4a500ca8864c5b47b8b482a73d62e4237670e5b5f1d6b9e3cae50f28f2b" + +[[package]] +name = "xml-rs" +version = "0.8.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ae8337f8a065cfc972643663ea4279e04e7256de865aa66fe25cec5fb912d3f" + [[package]] name = "xxhash-rust" version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3" -[[package]] -name = "xz2" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388c44dc09d76f1536602ead6d325eb532f5c122f17782bd57fb47baeeb767e2" -dependencies = [ - "lzma-sys", -] - [[package]] name = "yajrc" version = "0.1.3" @@ -10218,17 +11189,32 @@ dependencies = [ ] [[package]] -name = "yasi" -version = "0.1.9" +name = "yaml-rust" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91d8075d6829add5913054d2de87aec55a786599427d93ef3504a0b7f515a418" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] + +[[package]] +name = "yansi" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" + +[[package]] +name = "yasi" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4752072f7740cdfce9c61da81760fbda4182cfe4fff6f7a21fb6470b3f20a0" dependencies = [ - "ahash 0.8.12", "hashbrown 0.13.2", "lazy_static", "serde", "tinyvec", "ts-rs", + "xxhash-rust", ] [[package]] @@ -10242,11 +11228,10 @@ dependencies = [ [[package]] name = "yoke" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" dependencies = [ - "serde", "stable_deref_trait", "yoke-derive", "zerofrom", @@ -10254,21 +11239,21 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", "synstructure", ] [[package]] name = "zbus" -version = "5.10.0" +version = "5.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67a073be99ace1adc48af593701c8015cd9817df372e14a1a6b0ee8f8bf043be" +checksum = "b622b18155f7a93d1cd2dc8c01d2d6a44e08fb9ebb7b3f9e6ed101488bad6c91" dependencies = [ "async-broadcast", "async-executor", @@ -10290,7 +11275,8 @@ dependencies = [ "serde_repr", "tracing", "uds_windows", - "windows-sys 0.60.2", + "uuid", + "windows-sys 0.61.2", "winnow", "zbus_macros", "zbus_names", @@ -10299,14 +11285,14 @@ dependencies = [ [[package]] name = "zbus_macros" -version = "5.10.0" +version = "5.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e80cd713a45a49859dcb648053f63265f4f2851b6420d47a958e5697c68b131" +checksum = "1cdb94821ca8a87ca9c298b5d1cbd80e2a8b67115d99f6e4551ac49e42b6a314" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", "zbus_names", "zvariant", "zvariant_utils", @@ -10326,22 +11312,22 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.26" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" +checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.26" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" +checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] @@ -10361,15 +11347,15 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", "synstructure", ] [[package]] name = "zeroize" -version = "1.8.1" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" dependencies = [ "zeroize_derive", ] @@ -10382,14 +11368,14 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", ] [[package]] name = "zerotrie" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" dependencies = [ "displaydoc", "yoke", @@ -10398,10 +11384,11 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.4" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" dependencies = [ + "serde", "yoke", "zerofrom", "zerovec-derive", @@ -10409,61 +11396,13 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", -] - -[[package]] -name = "zip" -version = "2.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fabe6324e908f85a1c52063ce7aa26b68dcb7eb6dbc83a2d148403c9bc3eba50" -dependencies = [ - "aes 0.8.4", - "arbitrary", - "bzip2", - "constant_time_eq", - "crc32fast", - "crossbeam-utils", - "deflate64", - "displaydoc", - "flate2", - "getrandom 0.3.3", - "hmac", - "indexmap 2.11.0", - "lzma-rs", - "memchr", - "pbkdf2", - "sha1", - "thiserror 2.0.16", - "time", - "xz2", - "zeroize", - "zopfli", - "zstd", -] - -[[package]] -name = "zlib-rs" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "626bd9fa9734751fc50d6060752170984d7053f5a39061f524cda68023d4db8a" - -[[package]] -name = "zopfli" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edfc5ee405f504cd4984ecc6f14d02d55cfda60fa4b689434ef4102aae150cd7" -dependencies = [ - "bumpalo", - "crc32fast", - "log", - "simd-adler32", + "syn 2.0.108", ] [[package]] @@ -10486,9 +11425,9 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "2.0.15+zstd.1.5.7" +version = "2.0.16+zstd.1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb81183ddd97d0c74cedf1d50d85c8d08c1b8b68ee863bdee9e706eedba1a237" +checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748" dependencies = [ "cc", "pkg-config", @@ -10496,9 +11435,9 @@ dependencies = [ [[package]] name = "zvariant" -version = "5.7.0" +version = "5.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "999dd3be73c52b1fccd109a4a81e4fcd20fab1d3599c8121b38d04e1419498db" +checksum = "2be61892e4f2b1772727be11630a62664a1826b62efa43a6fe7449521cb8744c" dependencies = [ "endi", "enumflags2", @@ -10510,14 +11449,14 @@ dependencies = [ [[package]] name = "zvariant_derive" -version = "5.7.0" +version = "5.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6643fd0b26a46d226bd90d3f07c1b5321fe9bb7f04673cb37ac6d6883885b68e" +checksum = "da58575a1b2b20766513b1ec59d8e2e68db2745379f961f86650655e862d2006" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.108", "zvariant_utils", ] @@ -10530,6 +11469,6 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.106", + "syn 2.0.108", "winnow", ] diff --git a/core/Cross.toml b/core/Cross.toml new file mode 100644 index 000000000..744c12471 --- /dev/null +++ b/core/Cross.toml @@ -0,0 +1,2 @@ +[build] +pre-build = ["apt-get update && apt-get install -y rsync"] diff --git a/core/build-cli.sh b/core/build-cli.sh index bc70c2983..e575b8be7 100755 --- a/core/build-cli.sh +++ b/core/build-cli.sh @@ -5,9 +5,15 @@ cd "$(dirname "${BASH_SOURCE[0]}")" set -ea shopt -s expand_aliases +PROFILE=${PROFILE:-release} +if [ "${PROFILE}" = "release" ]; then + BUILD_FLAGS="--release" +fi + if [ -z "${ARCH:-}" ]; then ARCH=$(uname -m) fi + if [ "$ARCH" = "arm64" ]; then ARCH="aarch64" fi @@ -27,11 +33,6 @@ if [ -z "${TARGET:-}" ]; then fi fi -USE_TTY= -if tty -s; then - USE_TTY="-it" -fi - cd .. # Ensure GIT_HASH.txt exists if not created by higher-level build steps @@ -50,15 +51,6 @@ if [[ "${ENVIRONMENT:-}" =~ (^|-)console($|-) ]]; then RUSTFLAGS="--cfg tokio_unstable" fi -if command -v zig >/dev/null 2>&1 && [ "${ENFORCE_USE_DOCKER:-0}" != "1" ]; then - echo "FEATURES=\"$FEATURES\"" - echo "RUSTFLAGS=\"$RUSTFLAGS\"" - RUSTFLAGS=$RUSTFLAGS sh -c "cd core && cargo zigbuild --release --no-default-features --features $FEATURE_ARGS --locked --bin start-cli --target=$TARGET" -else - alias 'rust-zig-builder'='docker run '"$USE_TTY"' --rm -e "RUSTFLAGS=$RUSTFLAGS" -v "$HOME/.cargo/registry":/root/.cargo/registry -v "$HOME/.cargo/git":/root/.cargo/git -v "$(pwd)":/home/rust/src -w /home/rust/src -P messense/cargo-zigbuild' - RUSTFLAGS=$RUSTFLAGS rust-zig-builder sh -c "cd core && cargo zigbuild --release --no-default-features --features $FEATURE_ARGS --locked --bin start-cli --target=$TARGET" - - if [ "$(ls -nd "core/target/$TARGET/release/start-cli" | awk '{ print $3 }')" != "$UID" ]; then - rust-zig-builder sh -c "cd core && chown -R $UID:$UID target && chown -R $UID:$UID /root/.cargo" - fi -fi \ No newline at end of file +echo "FEATURES=\"$FEATURES\"" +echo "RUSTFLAGS=\"$RUSTFLAGS\"" +cross build --manifest-path=./core/Cargo.toml $BUILD_FLAGS --no-default-features --features $FEATURE_ARGS --locked --bin start-cli --target=$TARGET \ No newline at end of file diff --git a/core/build-containerbox.sh b/core/build-containerbox.sh index b3899097f..efa0f6fce 100755 --- a/core/build-containerbox.sh +++ b/core/build-containerbox.sh @@ -5,6 +5,11 @@ cd "$(dirname "${BASH_SOURCE[0]}")" set -ea shopt -s expand_aliases +PROFILE=${PROFILE:-release} +if [ "${PROFILE}" = "release" ]; then + BUILD_FLAGS="--release" +fi + if [ -z "$ARCH" ]; then ARCH=$(uname -m) fi @@ -13,9 +18,9 @@ if [ "$ARCH" = "arm64" ]; then ARCH="aarch64" fi -USE_TTY= -if tty -s; then - USE_TTY="-it" +RUST_ARCH="$ARCH" +if [ "$ARCH" = "riscv64" ]; then + RUST_ARCH="riscv64gc" fi cd .. @@ -26,11 +31,6 @@ if [[ "${ENVIRONMENT}" =~ (^|-)console($|-) ]]; then RUSTFLAGS="--cfg tokio_unstable" fi -source ./core/builder-alias.sh - echo "FEATURES=\"$FEATURES\"" echo "RUSTFLAGS=\"$RUSTFLAGS\"" -rust-musl-builder sh -c "cd core && cargo build --release --no-default-features --features cli-container,$FEATURES --locked --bin containerbox --target=$ARCH-unknown-linux-musl" -if [ "$(ls -nd core/target/$ARCH-unknown-linux-musl/release/containerbox | awk '{ print $3 }')" != "$UID" ]; then - rust-musl-builder sh -c "cd core && chown -R $UID:$UID target && chown -R $UID:$UID /root/.cargo" -fi \ No newline at end of file +cross build --manifest-path=./core/Cargo.toml $BUILD_FLAGS --no-default-features --features cli-container,$FEATURES --locked --bin containerbox --target=$RUST_ARCH-unknown-linux-musl \ No newline at end of file diff --git a/core/build-registrybox.sh b/core/build-registrybox.sh index 4550a5043..ec6630d0f 100755 --- a/core/build-registrybox.sh +++ b/core/build-registrybox.sh @@ -5,6 +5,11 @@ cd "$(dirname "${BASH_SOURCE[0]}")" set -ea shopt -s expand_aliases +PROFILE=${PROFILE:-release} +if [ "${PROFILE}" = "release" ]; then + BUILD_FLAGS="--release" +fi + if [ -z "$ARCH" ]; then ARCH=$(uname -m) fi @@ -13,9 +18,9 @@ if [ "$ARCH" = "arm64" ]; then ARCH="aarch64" fi -USE_TTY= -if tty -s; then - USE_TTY="-it" +RUST_ARCH="$ARCH" +if [ "$ARCH" = "riscv64" ]; then + RUST_ARCH="riscv64gc" fi cd .. @@ -26,11 +31,6 @@ if [[ "${ENVIRONMENT}" =~ (^|-)console($|-) ]]; then RUSTFLAGS="--cfg tokio_unstable" fi -source ./core/builder-alias.sh - echo "FEATURES=\"$FEATURES\"" echo "RUSTFLAGS=\"$RUSTFLAGS\"" -rust-musl-builder sh -c "cd core && cargo build --release --no-default-features --features cli-registry,registry,$FEATURES --locked --bin registrybox --target=$ARCH-unknown-linux-musl" -if [ "$(ls -nd core/target/$ARCH-unknown-linux-musl/release/registrybox | awk '{ print $3 }')" != "$UID" ]; then - rust-musl-builder sh -c "cd core && chown -R $UID:$UID target && chown -R $UID:$UID /root/.cargo" -fi +cross build --manifest-path=./core/Cargo.toml $BUILD_FLAGS --no-default-features --features cli-registry,registry,$FEATURES --locked --bin registrybox --target=$RUST_ARCH-unknown-linux-musl diff --git a/core/build-startbox.sh b/core/build-startbox.sh index 2782d2c80..655566879 100755 --- a/core/build-startbox.sh +++ b/core/build-startbox.sh @@ -1,15 +1,15 @@ #!/bin/bash -PROFILE=${PROFILE:-release} -if [ "${PROFILE}" = "release" ]; then - BUILD_FLAGS="--release" -fi - cd "$(dirname "${BASH_SOURCE[0]}")" set -ea shopt -s expand_aliases +PROFILE=${PROFILE:-release} +if [ "${PROFILE}" = "release" ]; then + BUILD_FLAGS="--release" +fi + if [ -z "$ARCH" ]; then ARCH=$(uname -m) fi @@ -18,9 +18,9 @@ if [ "$ARCH" = "arm64" ]; then ARCH="aarch64" fi -USE_TTY= -if tty -s; then - USE_TTY="-it" +RUST_ARCH="$ARCH" +if [ "$ARCH" = "riscv64" ]; then + RUST_ARCH="riscv64gc" fi cd .. @@ -31,11 +31,6 @@ if [[ "${ENVIRONMENT}" =~ (^|-)console($|-) ]]; then RUSTFLAGS="--cfg tokio_unstable" fi -source ./core/builder-alias.sh - echo "FEATURES=\"$FEATURES\"" echo "RUSTFLAGS=\"$RUSTFLAGS\"" -rust-musl-builder sh -c "cd core && cargo build $BUILD_FLAGS --no-default-features --features cli,startd,$FEATURES --locked --bin startbox --target=$ARCH-unknown-linux-musl" -if [ "$(ls -nd core/target/$ARCH-unknown-linux-musl/${PROFILE}/startbox | awk '{ print $3 }')" != "$UID" ]; then - rust-musl-builder sh -c "cd core && chown -R $UID:$UID target && chown -R $UID:$UID /root/.cargo" -fi \ No newline at end of file +cross build --manifest-path=./core/Cargo.toml $BUILD_FLAGS --no-default-features --features cli,startd,$FEATURES --locked --bin startbox --target=$RUST_ARCH-unknown-linux-musl diff --git a/core/build-ts.sh b/core/build-ts.sh index f564026a9..e29a43a66 100755 --- a/core/build-ts.sh +++ b/core/build-ts.sh @@ -5,32 +5,30 @@ cd "$(dirname "${BASH_SOURCE[0]}")" set -ea shopt -s expand_aliases +PROFILE=${PROFILE:-release} +if [ "${PROFILE}" = "release" ]; then + BUILD_FLAGS="--release" +fi + if [ -z "$ARCH" ]; then ARCH=$(uname -m) fi if [ "$ARCH" = "arm64" ]; then - ARCH="aarch64" + ARCH="aarch64" fi -USE_TTY= -if tty -s; then - USE_TTY="-it" +RUST_ARCH="$ARCH" +if [ "$ARCH" = "riscv64" ]; then + RUST_ARCH="riscv64gc" fi cd .. FEATURES="$(echo $ENVIRONMENT | sed 's/-/,/g')" RUSTFLAGS="" - if [[ "${ENVIRONMENT}" =~ (^|-)console($|-) ]]; then RUSTFLAGS="--cfg tokio_unstable" fi - -source ./core/builder-alias.sh - echo "FEATURES=\"$FEATURES\"" echo "RUSTFLAGS=\"$RUSTFLAGS\"" -rust-musl-builder sh -c "cd core && cargo test --release --features=test,$FEATURES 'export_bindings_' && chown \$UID:\$UID startos/bindings" -if [ "$(ls -nd core/startos/bindings | awk '{ print $3 }')" != "$UID" ]; then - rust-musl-builder sh -c "cd core && chown -R $UID:$UID startos/bindings && chown -R $UID:$UID target && chown -R $UID:$UID /root/.cargo" -fi \ No newline at end of file +cross test --manifest-path=./core/Cargo.toml $BUILD_FLAGS --no-default-features --features test,$FEATURES --locked 'export_bindings_' diff --git a/core/build-tunnelbox.sh b/core/build-tunnelbox.sh index b5a00304d..da662c9b7 100755 --- a/core/build-tunnelbox.sh +++ b/core/build-tunnelbox.sh @@ -5,6 +5,11 @@ cd "$(dirname "${BASH_SOURCE[0]}")" set -ea shopt -s expand_aliases +PROFILE=${PROFILE:-release} +if [ "${PROFILE}" = "release" ]; then + BUILD_FLAGS="--release" +fi + if [ -z "$ARCH" ]; then ARCH=$(uname -m) fi @@ -13,9 +18,9 @@ if [ "$ARCH" = "arm64" ]; then ARCH="aarch64" fi -USE_TTY= -if tty -s; then - USE_TTY="-it" +RUST_ARCH="$ARCH" +if [ "$ARCH" = "riscv64" ]; then + RUST_ARCH="riscv64gc" fi cd .. @@ -26,11 +31,6 @@ if [[ "${ENVIRONMENT}" =~ (^|-)console($|-) ]]; then RUSTFLAGS="--cfg tokio_unstable" fi -source ./core/builder-alias.sh - echo "FEATURES=\"$FEATURES\"" echo "RUSTFLAGS=\"$RUSTFLAGS\"" -rust-musl-builder sh -c "cd core && cargo build --release --no-default-features --features cli-tunnel,tunnel,$FEATURES --locked --bin tunnelbox --target=$ARCH-unknown-linux-musl" -if [ "$(ls -nd core/target/$ARCH-unknown-linux-musl/release/tunnelbox | awk '{ print $3 }')" != "$UID" ]; then - rust-musl-builder sh -c "cd core && chown -R $UID:$UID target && chown -R $UID:$UID /root/.cargo" -fi +cross build --manifest-path=./core/Cargo.toml $BUILD_FLAGS --no-default-features --features cli-tunnel,tunnel,$FEATURES --locked --bin tunnelbox --target=$RUST_ARCH-unknown-linux-musl diff --git a/core/models/Cargo.toml b/core/models/Cargo.toml index b9d9cf8d5..7abe1b302 100644 --- a/core/models/Cargo.toml +++ b/core/models/Cargo.toml @@ -1,23 +1,28 @@ [package] +edition = "2021" name = "models" version = "0.1.0" -edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[features] +arti = ["arti-client"] + [dependencies] -arti-client = { version = "0.33", default-features = false, git = "https://github.com/Start9Labs/arti.git", branch = "patch/disable-exit" } +arti-client = { version = "0.33", default-features = false, git = "https://github.com/Start9Labs/arti.git", branch = "patch/disable-exit", optional = true } axum = "0.8.4" base64 = "0.22.1" color-eyre = "0.6.2" ed25519-dalek = { version = "2.0.0", features = ["serde"] } -gpt = "4.1.0" -lazy_static = "1.4" -mbrman = "0.6.0" exver = { version = "0.2.0", git = "https://github.com/Start9Labs/exver-rs.git", features = [ "serde", ] } +gpt = "4.1.0" ipnet = "2.8.0" +lazy_static = "1.4" +lettre = { version = "0.11", default-features = false } +mbrman = "0.6.0" +miette = "7.6.0" num_enum = "0.7.1" openssl = { version = "0.10.57", features = ["vendored"] } patch-db = { version = "*", path = "../../patch-db/patch-db", features = [ @@ -31,10 +36,11 @@ rustls = "0.23" serde = { version = "1.0", features = ["derive", "rc"] } serde_json = "1.0" ssh-key = "0.6.2" -ts-rs = "9" thiserror = "2.0" tokio = { version = "1", features = ["full"] } +torut = "0.2.1" tracing = "0.1.39" +ts-rs = "9" typeid = "1" yasi = { version = "0.1.6", features = ["serde", "ts-rs"] } zbus = "5" diff --git a/core/models/src/errors.rs b/core/models/src/errors.rs index 30ee64514..929a9502c 100644 --- a/core/models/src/errors.rs +++ b/core/models/src/errors.rs @@ -94,6 +94,7 @@ pub enum ErrorKind { DBus = 75, InstallFailed = 76, UpdateFailed = 77, + Smtp = 78, } impl ErrorKind { pub fn as_str(&self) -> &'static str { @@ -176,6 +177,7 @@ impl ErrorKind { DBus => "DBus Error", InstallFailed => "Install Failed", UpdateFailed => "Update Failed", + Smtp => "SMTP Error", } } } @@ -185,7 +187,6 @@ impl Display for ErrorKind { } } -#[derive(Debug)] pub struct Error { pub source: color_eyre::eyre::Error, pub debug: Option, @@ -196,7 +197,17 @@ pub struct Error { impl Display for Error { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}: {}", self.kind.as_str(), self.source) + write!(f, "{}: {:#}", self.kind.as_str(), self.source) + } +} +impl Debug for Error { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}: {:?}", + self.kind.as_str(), + self.debug.as_ref().unwrap_or(&self.source) + ) } } impl Error { @@ -347,11 +358,17 @@ impl From for Error { Error::new(e, kind) } } +#[cfg(feature = "arti")] impl From for Error { fn from(e: arti_client::Error) -> Self { Error::new(e, ErrorKind::Tor) } } +impl From for Error { + fn from(e: torut::control::ConnError) -> Self { + Error::new(e, ErrorKind::Tor) + } +} impl From for Error { fn from(e: zbus::Error) -> Self { Error::new(e, ErrorKind::DBus) @@ -362,6 +379,21 @@ impl From for Error { Error::new(e, ErrorKind::OpenSsl) } } +impl From for Error { + fn from(e: lettre::error::Error) -> Self { + Error::new(e, ErrorKind::Smtp) + } +} +impl From for Error { + fn from(e: lettre::transport::smtp::Error) -> Self { + Error::new(e, ErrorKind::Smtp) + } +} +impl From for Error { + fn from(e: lettre::address::AddressError) -> Self { + Error::new(e, ErrorKind::Smtp) + } +} impl From for Error { fn from(value: patch_db::value::Error) -> Self { match value.kind { diff --git a/core/run-tests.sh b/core/run-tests.sh index 185eb5a3e..8798b29b8 100755 --- a/core/run-tests.sh +++ b/core/run-tests.sh @@ -5,6 +5,11 @@ cd "$(dirname "${BASH_SOURCE[0]}")" set -ea shopt -s expand_aliases +PROFILE=${PROFILE:-release} +if [ "${PROFILE}" = "release" ]; then + BUILD_FLAGS="--release" +fi + if [ -z "$ARCH" ]; then ARCH=$(uname -m) fi @@ -26,11 +31,8 @@ if [[ "${ENVIRONMENT}" =~ (^|-)console($|-) ]]; then RUSTFLAGS="--cfg tokio_unstable" fi -alias 'rust-musl-builder'='docker run $USE_TTY --rm -e "RUSTFLAGS=$RUSTFLAGS" -v "$HOME/.cargo/registry":/root/.cargo/registry -v "$HOME/.cargo/git":/root/.cargo/git -v "$(pwd)":/home/rust/src -w /home/rust/src -P messense/rust-musl-cross:$ARCH-musl' +source ./core/builder-alias.sh echo "FEATURES=\"$FEATURES\"" echo "RUSTFLAGS=\"$RUSTFLAGS\"" -rust-musl-builder sh -c "apt-get update && apt-get install -y rsync && cd core && cargo test --release --features=test,$FEATURES --workspace --locked --target=$ARCH-unknown-linux-musl -- --skip export_bindings_ && chown \$UID:\$UID target" -if [ "$(ls -nd core/target | awk '{ print $3 }')" != "$UID" ]; then - rust-musl-builder sh -c "cd core && chown -R $UID:$UID target && chown -R $UID:$UID /root/.cargo" -fi \ No newline at end of file +cross test --manifest-path=./core/Cargo.toml $BUILD_FLAGS --features=test,$FEATURES --workspace --locked --target=$ARCH-unknown-linux-musl -- --skip export_bindings_ \ No newline at end of file diff --git a/core/startos/Cargo.toml b/core/startos/Cargo.toml index b7ea7dcf2..c3ccdbb9d 100644 --- a/core/startos/Cargo.toml +++ b/core/startos/Cargo.toml @@ -4,18 +4,18 @@ description = "The core of StartOS" documentation = "https://docs.rs/start-os" edition = "2024" keywords = [ - "self-hosted", - "raspberry-pi", - "privacy", "bitcoin", "full-node", "lightning", + "privacy", + "raspberry-pi", + "self-hosted", ] +license = "MIT" name = "start-os" readme = "README.md" repository = "https://github.com/Start9Labs/start-os" -version = "0.4.0-alpha.11" # VERSION_BUMP -license = "MIT" +version = "0.4.0-alpha.12" # VERSION_BUMP [lib] name = "startos" @@ -42,48 +42,61 @@ name = "tunnelbox" path = "src/main.rs" [features] -cli = ["cli-startd", "cli-registry", "cli-tunnel"] +arti = [ + "arti-client", + "models/arti", + "safelog", + "tor-cell", + "tor-hscrypto", + "tor-hsservice", + "tor-keymgr", + "tor-llcrypto", + "tor-proto", + "tor-rtcompat", +] +cli = ["cli-registry", "cli-startd", "cli-tunnel"] cli-container = ["procfs", "pty-process"] cli-registry = [] cli-startd = [] cli-tunnel = [] -default = ["cli", "startd", "registry", "cli-container", "tunnel"] +console = ["console-subscriber", "tokio/tracing"] +default = ["cli", "cli-container", "registry", "startd", "tunnel"] dev = ["backtrace-on-stack-overflow"] docker = [] registry = [] -startd = ["mail-send"] +startd = [] test = [] tunnel = [] -console = ["console-subscriber", "tokio/tracing"] unstable = ["backtrace-on-stack-overflow"] [dependencies] +aes = { version = "0.7.5", features = ["ctr"] } arti-client = { version = "0.33", features = [ "compression", + "ephemeral-keystore", "experimental-api", + "onion-service-client", + "onion-service-service", "rustls", "static", "tokio", - "ephemeral-keystore", - "onion-service-client", - "onion-service-service", -], default-features = false, git = "https://github.com/Start9Labs/arti.git", branch = "patch/disable-exit" } -aes = { version = "0.7.5", features = ["ctr"] } +], default-features = false, git = "https://github.com/Start9Labs/arti.git", branch = "patch/disable-exit", optional = true } async-acme = { version = "0.6.0", git = "https://github.com/dr-bonez/async-acme.git", features = [ "use_rustls", "use_tokio", ] } -async-compression = { version = "0.4.4", features = [ - "gzip", +async-compression = { version = "0.4.32", features = [ "brotli", + "gzip", "tokio", + "zstd", ] } async-stream = "0.3.5" async-trait = "0.1.74" +aws-lc-sys = { version = "0.32", features = ["bindgen"] } axum = { version = "0.8.4", features = ["ws"] } -barrage = "0.2.3" -backhand = "0.21.0" backtrace-on-stack-overflow = { version = "0.3.0", optional = true } +barrage = "0.2.3" base32 = "0.5.0" base64 = "0.22.1" base64ct = "1.6.0" @@ -98,17 +111,19 @@ console-subscriber = { version = "0.4.1", optional = true } const_format = "0.2.34" cookie = "0.18.0" cookie_store = "0.21.0" +curve25519-dalek = "4.1.3" der = { version = "0.7.9", features = ["derive", "pem"] } digest = "0.10.7" divrem = "1.0.0" dns-lookup = "2.1.0" -ed25519 = { version = "2.2.3", features = ["pkcs8", "pem", "alloc"] } +ed25519 = { version = "2.2.3", features = ["alloc", "pem", "pkcs8"] } ed25519-dalek = { version = "2.2.0", features = [ + "digest", + "hazmat", + "pkcs8", + "rand_core", "serde", "zeroize", - "rand_core", - "digest", - "pkcs8", ] } ed25519-dalek-v1 = { package = "ed25519-dalek", version = "1" } exver = { version = "0.2.0", git = "https://github.com/Start9Labs/exver-rs.git", features = [ @@ -125,20 +140,21 @@ hickory-server = "0.25.2" hmac = "0.12.1" http = "1.0.0" http-body-util = "0.1" -hyper = { version = "1.5", features = ["server", "http1", "http2"] } +hyper = { version = "1.5", features = ["http1", "http2", "server"] } hyper-util = { version = "0.1.10", features = [ + "http1", + "http2", "server", "server-auto", "server-graceful", "service", - "http1", - "http2", "tokio", ] } id-pool = { version = "0.2.2", default-features = false, features = [ "serde", "u16", ] } +iddqd = "0.3.14" imbl = { version = "6", features = ["serde", "small-chunks"] } imbl-value = { version = "0.4.3", features = ["ts-rs"] } include_dir = { version = "0.7.3", features = ["metadata"] } @@ -156,10 +172,20 @@ jsonpath_lib = { git = "https://github.com/Start9Labs/jsonpath.git" } lazy_async_pool = "0.3.3" lazy_format = "2.0" lazy_static = "1.4.0" +lettre = { version = "0.11.18", default-features = false, features = [ + "aws-lc-rs", + "builder", + "hostname", + "pool", + "rustls-platform-verifier", + "smtp-transport", + "tokio1-rustls", +] } libc = "0.2.149" log = "0.4.20" -mio = "1" mbrman = "0.6.0" +miette = { version = "7.6.0", features = ["fancy"] } +mio = "1" models = { version = "*", path = "../models" } new_mime_guess = "4" nix = { version = "0.30.1", features = [ @@ -173,8 +199,8 @@ nix = { version = "0.30.1", features = [ ] } nom = "8.0.0" num = "0.4.1" -num_enum = "0.7.0" num_cpus = "1.16.0" +num_enum = "0.7.0" once_cell = "1.19.0" openssh-keys = "0.6.2" openssl = { version = "0.10.57", features = ["vendored"] } @@ -191,22 +217,22 @@ proptest = "1.3.1" proptest-derive = "0.5.0" pty-process = { version = "0.5.1", optional = true } qrcode = "0.14.1" +r3bl_tui = "0.7.6" rand = "0.9.2" regex = "1.10.2" -reqwest = { version = "0.12.4", features = ["stream", "json", "socks"] } +reqwest = { version = "0.12.4", features = ["json", "socks", "stream"] } reqwest_cookie_store = "0.8.0" rpassword = "7.2.0" rpc-toolkit = { git = "https://github.com/Start9Labs/rpc-toolkit.git", branch = "master" } rust-argon2 = "2.0.0" -rustyline-async = "0.4.1" -safelog = { version = "0.4.8", git = "https://github.com/Start9Labs/arti.git", branch = "patch/disable-exit" } +safelog = { version = "0.4.8", git = "https://github.com/Start9Labs/arti.git", branch = "patch/disable-exit", optional = true } semver = { version = "1.0.20", features = ["serde"] } serde = { version = "1.0", features = ["derive", "rc"] } serde_cbor = { package = "ciborium", version = "0.2.1" } serde_json = "1.0" serde_toml = { package = "toml", version = "0.8.2" } serde_urlencoded = "0.7" -serde_with = { version = "3.4.0", features = ["macros", "json"] } +serde_with = { version = "3.4.0", features = ["json", "macros"] } serde_yaml = { package = "serde_yml", version = "0.0.12" } sha-crypt = "0.5.0" sha2 = "0.10.2" @@ -214,39 +240,40 @@ shell-words = "1" signal-hook = "0.3.17" simple-logging = "2.0.2" socket2 = { version = "0.6.0", features = ["all"] } -socks5-impl = { version = "0.7.2", features = ["server"] } +socks5-impl = { version = "0.7.2", features = ["client", "server"] } sqlx = { version = "0.8.6", features = [ - "runtime-tokio-rustls", "postgres", + "runtime-tokio-rustls", ], default-features = false } sscanf = "0.4.1" ssh-key = { version = "0.6.2", features = ["ed25519"] } tar = "0.4.40" termion = "4.0.5" -thiserror = "2.0.12" textwrap = "0.16.1" +thiserror = "2.0.12" tokio = { version = "1.38.1", features = ["full"] } tokio-rustls = "0.26.0" -tokio-stream = { version = "0.1.14", features = ["io-util", "sync", "net"] } +tokio-stream = { version = "0.1.14", features = ["io-util", "net", "sync"] } tokio-tar = { git = "https://github.com/dr-bonez/tokio-tar.git" } tokio-tungstenite = { version = "0.26.2", features = ["native-tls", "url"] } tokio-util = { version = "0.7.9", features = ["io"] } -tor-cell = { version = "0.33", git = "https://github.com/Start9Labs/arti.git", branch = "patch/disable-exit" } +tor-cell = { version = "0.33", git = "https://github.com/Start9Labs/arti.git", branch = "patch/disable-exit", optional = true } tor-hscrypto = { version = "0.33", features = [ "full", -], git = "https://github.com/Start9Labs/arti.git", branch = "patch/disable-exit" } -tor-hsservice = { version = "0.33", git = "https://github.com/Start9Labs/arti.git", branch = "patch/disable-exit" } +], git = "https://github.com/Start9Labs/arti.git", branch = "patch/disable-exit", optional = true } +tor-hsservice = { version = "0.33", git = "https://github.com/Start9Labs/arti.git", branch = "patch/disable-exit", optional = true } tor-keymgr = { version = "0.33", features = [ "ephemeral-keystore", -], git = "https://github.com/Start9Labs/arti.git", branch = "patch/disable-exit" } +], git = "https://github.com/Start9Labs/arti.git", branch = "patch/disable-exit", optional = true } tor-llcrypto = { version = "0.33", features = [ "full", -], git = "https://github.com/Start9Labs/arti.git", branch = "patch/disable-exit" } -tor-proto = { version = "0.33", git = "https://github.com/Start9Labs/arti.git", branch = "patch/disable-exit" } +], git = "https://github.com/Start9Labs/arti.git", branch = "patch/disable-exit", optional = true } +tor-proto = { version = "0.33", git = "https://github.com/Start9Labs/arti.git", branch = "patch/disable-exit", optional = true } tor-rtcompat = { version = "0.33", features = [ - "tokio", "rustls", -], git = "https://github.com/Start9Labs/arti.git", branch = "patch/disable-exit" } + "tokio", +], git = "https://github.com/Start9Labs/arti.git", branch = "patch/disable-exit", optional = true } +torut = "0.2.1" tower-service = "0.3.3" tracing = "0.1.39" tracing-error = "0.2.0" @@ -259,11 +286,10 @@ unix-named-pipe = "0.2.0" url = { version = "2.4.1", features = ["serde"] } urlencoding = "2.1.3" uuid = { version = "1.4.1", features = ["v4"] } +visit-rs = "0.1.1" +x25519-dalek = { version = "2.0.1", features = ["static_secrets"] } zbus = "5.1.1" zeroize = "1.6.0" -mail-send = { git = "https://github.com/dr-bonez/mail-send.git", branch = "main", optional = true } -rustls = "0.23.20" -rustls-pki-types = { version = "1.10.1", features = ["alloc"] } [profile.test] opt-level = 3 diff --git a/core/startos/src/account.rs b/core/startos/src/account.rs index 58d4649e0..87e127d17 100644 --- a/core/startos/src/account.rs +++ b/core/startos/src/account.rs @@ -1,3 +1,4 @@ +use std::collections::BTreeMap; use std::time::SystemTime; use imbl_value::InternedString; @@ -107,6 +108,7 @@ impl AccountInfo { .map(|tor_key| tor_key.onion_address()) .collect(), )?; + server_info.as_password_hash_mut().ser(&self.password)?; db.as_private_mut().as_password_mut().ser(&self.password)?; db.as_private_mut() .as_ssh_privkey_mut() @@ -119,12 +121,20 @@ impl AccountInfo { key_store.as_onion_mut().insert_key(tor_key)?; } let cert_store = key_store.as_local_certs_mut(); - cert_store - .as_root_key_mut() - .ser(Pem::new_ref(&self.root_ca_key))?; - cert_store - .as_root_cert_mut() - .ser(Pem::new_ref(&self.root_ca_cert))?; + if cert_store.as_root_cert().de()?.0 != self.root_ca_cert { + cert_store + .as_root_key_mut() + .ser(Pem::new_ref(&self.root_ca_key))?; + cert_store + .as_root_cert_mut() + .ser(Pem::new_ref(&self.root_ca_cert))?; + let int_key = crate::net::ssl::generate_key()?; + let int_cert = + crate::net::ssl::make_int_cert((&self.root_ca_key, &self.root_ca_cert), &int_key)?; + cert_store.as_int_key_mut().ser(&Pem(int_key))?; + cert_store.as_int_cert_mut().ser(&Pem(int_cert))?; + cert_store.as_leaves_mut().ser(&BTreeMap::new())?; + } Ok(()) } diff --git a/core/startos/src/action.rs b/core/startos/src/action.rs index 4729a3fb9..aac044bb9 100644 --- a/core/startos/src/action.rs +++ b/core/startos/src/action.rs @@ -4,7 +4,7 @@ use clap::{CommandFactory, FromArgMatches, Parser}; pub use models::ActionId; use models::{PackageId, ReplayId}; use qrcode::QrCode; -use rpc_toolkit::{from_fn_async, Context, HandlerExt, ParentHandler}; +use rpc_toolkit::{Context, HandlerExt, ParentHandler, from_fn_async}; use serde::{Deserialize, Serialize}; use tracing::instrument; use ts_rs::TS; @@ -14,7 +14,7 @@ use crate::db::model::package::TaskSeverity; use crate::prelude::*; use crate::rpc_continuations::Guid; use crate::util::serde::{ - display_serializable, HandlerExtSerde, StdinDeserializable, WithIoFormat, + HandlerExtSerde, StdinDeserializable, WithIoFormat, display_serializable, }; pub fn action_api() -> ParentHandler { diff --git a/core/startos/src/auth.rs b/core/startos/src/auth.rs index a49c8f2ab..c4ef42475 100644 --- a/core/startos/src/auth.rs +++ b/core/startos/src/auth.rs @@ -220,7 +220,7 @@ pub fn check_password(hash: &str, password: &str) -> Result<(), Error> { pub struct LoginParams { password: String, #[ts(skip)] - #[serde(rename = "__auth_userAgent")] // from Auth middleware + #[serde(rename = "__Auth_userAgent")] // from Auth middleware user_agent: Option, #[serde(default)] ephemeral: bool, @@ -279,7 +279,7 @@ pub async fn login_impl( #[command(rename_all = "kebab-case")] pub struct LogoutParams { #[ts(skip)] - #[serde(rename = "__auth_session")] // from Auth middleware + #[serde(rename = "__Auth_session")] // from Auth middleware session: InternedString, } @@ -373,7 +373,7 @@ fn display_sessions(params: WithIoFormat, arg: SessionList) -> Resul pub struct ListParams { #[arg(skip)] #[ts(skip)] - #[serde(rename = "__auth_session")] // from Auth middleware + #[serde(rename = "__Auth_session")] // from Auth middleware session: Option, } @@ -474,30 +474,19 @@ pub async fn reset_password_impl( let old_password = old_password.unwrap_or_default().decrypt(&ctx)?; let new_password = new_password.unwrap_or_default().decrypt(&ctx)?; - let mut account = ctx.account.write().await; - if !argon2::verify_encoded(&account.password, old_password.as_bytes()) - .with_kind(crate::ErrorKind::IncorrectPassword)? - { - return Err(Error::new( - eyre!("Incorrect Password"), - crate::ErrorKind::IncorrectPassword, - )); - } - account.set_password(&new_password)?; - let account_password = &account.password; - let account = account.clone(); - ctx.db - .mutate(|d| { - d.as_public_mut() - .as_server_info_mut() - .as_password_hash_mut() - .ser(account_password)?; - account.save(d)?; - - Ok(()) - }) - .await - .result + let account = ctx.account.mutate(|account| { + if !argon2::verify_encoded(&account.password, old_password.as_bytes()) + .with_kind(crate::ErrorKind::IncorrectPassword)? + { + return Err(Error::new( + eyre!("Incorrect Password"), + crate::ErrorKind::IncorrectPassword, + )); + } + account.set_password(&new_password)?; + Ok(account.clone()) + })?; + ctx.db.mutate(|d| account.save(d)).await.result } #[instrument(skip_all)] diff --git a/core/startos/src/backup/backup_bulk.rs b/core/startos/src/backup/backup_bulk.rs index 28170eb9b..1a57319fd 100644 --- a/core/startos/src/backup/backup_bulk.rs +++ b/core/startos/src/backup/backup_bulk.rs @@ -317,7 +317,7 @@ async fn perform_backup( .with_kind(ErrorKind::Filesystem)?; os_backup_file .write_all(&IoFormat::Json.to_vec(&OsBackup { - account: ctx.account.read().await.clone(), + account: ctx.account.peek(|a| a.clone()), ui, })?) .await?; @@ -342,7 +342,7 @@ async fn perform_backup( let timestamp = Utc::now(); backup_guard.unencrypted_metadata.version = crate::version::Current::default().semver().into(); - backup_guard.unencrypted_metadata.hostname = ctx.account.read().await.hostname.clone(); + backup_guard.unencrypted_metadata.hostname = ctx.account.peek(|a| a.hostname.clone()); backup_guard.unencrypted_metadata.timestamp = timestamp.clone(); backup_guard.metadata.version = crate::version::Current::default().semver().into(); backup_guard.metadata.timestamp = Some(timestamp); diff --git a/core/startos/src/bins/registry.rs b/core/startos/src/bins/registry.rs index 2aacebd39..cee20adc8 100644 --- a/core/startos/src/bins/registry.rs +++ b/core/startos/src/bins/registry.rs @@ -11,14 +11,17 @@ use crate::context::config::ClientConfig; use crate::net::web_server::{Acceptor, WebServer}; use crate::prelude::*; use crate::registry::context::{RegistryConfig, RegistryContext}; +use crate::registry::registry_router; use crate::util::logger::LOGGER; #[instrument(skip_all)] async fn inner_main(config: &RegistryConfig) -> Result<(), Error> { let server = async { let ctx = RegistryContext::init(config).await?; - let mut server = WebServer::new(Acceptor::bind([ctx.listen]).await?); - server.serve_registry(ctx.clone()); + let server = WebServer::new( + Acceptor::bind([ctx.listen]).await?, + registry_router(ctx.clone()), + ); let mut shutdown_recv = ctx.shutdown.subscribe(); diff --git a/core/startos/src/bins/start_cli.rs b/core/startos/src/bins/start_cli.rs index b3b10cf71..647e509d4 100644 --- a/core/startos/src/bins/start_cli.rs +++ b/core/startos/src/bins/start_cli.rs @@ -17,7 +17,7 @@ pub fn main(args: impl IntoIterator) { if let Err(e) = CliApp::new( |cfg: ClientConfig| Ok(CliContext::init(cfg.load()?)?), - crate::expanded_api(), + crate::main_api(), ) .run(args) { diff --git a/core/startos/src/bins/start_init.rs b/core/startos/src/bins/start_init.rs index 70c32ed1a..fedc9f623 100644 --- a/core/startos/src/bins/start_init.rs +++ b/core/startos/src/bins/start_init.rs @@ -11,7 +11,8 @@ use crate::disk::fsck::RepairStrategy; use crate::disk::main::DEFAULT_PASSWORD; use crate::firmware::{check_for_firmware_update, update_firmware}; use crate::init::{InitPhases, STANDBY_MODE_PATH}; -use crate::net::web_server::{UpgradableListener, WebServer}; +use crate::net::gateway::UpgradableListener; +use crate::net::web_server::WebServer; use crate::prelude::*; use crate::progress::FullProgressTracker; use crate::shutdown::Shutdown; @@ -37,7 +38,7 @@ async fn setup_or_init( let mut update_phase = handle.add_phase("Updating Firmware".into(), Some(10)); let mut reboot_phase = handle.add_phase("Rebooting".into(), Some(1)); - server.serve_init(init_ctx); + server.serve_ui_for(init_ctx); update_phase.start(); if let Err(e) = update_firmware(firmware).await { @@ -93,7 +94,7 @@ async fn setup_or_init( let ctx = InstallContext::init().await?; - server.serve_install(ctx.clone()); + server.serve_ui_for(ctx.clone()); ctx.shutdown .subscribe() @@ -113,7 +114,7 @@ async fn setup_or_init( { let ctx = SetupContext::init(server, config)?; - server.serve_setup(ctx.clone()); + server.serve_ui_for(ctx.clone()); let mut shutdown = ctx.shutdown.subscribe(); if let Some(shutdown) = shutdown.recv().await.expect("context dropped") { @@ -149,7 +150,7 @@ async fn setup_or_init( let init_phases = InitPhases::new(&handle); let rpc_ctx_phases = InitRpcContextPhases::new(&handle); - server.serve_init(init_ctx); + server.serve_ui_for(init_ctx); async { disk_phase.start(); @@ -247,7 +248,7 @@ pub async fn main( e, )?; - server.serve_diagnostic(ctx.clone()); + server.serve_ui_for(ctx.clone()); let shutdown = ctx.shutdown.subscribe().recv().await.unwrap(); diff --git a/core/startos/src/bins/startd.rs b/core/startos/src/bins/startd.rs index 8c1e77afb..86c391508 100644 --- a/core/startos/src/bins/startd.rs +++ b/core/startos/src/bins/startd.rs @@ -12,8 +12,9 @@ use tracing::instrument; use crate::context::config::ServerConfig; use crate::context::rpc::InitRpcContextPhases; use crate::context::{DiagnosticContext, InitContext, RpcContext}; -use crate::net::gateway::SelfContainedNetworkInterfaceListener; -use crate::net::web_server::{Acceptor, UpgradableListener, WebServer}; +use crate::net::gateway::{BindTcp, SelfContainedNetworkInterfaceListener, UpgradableListener}; +use crate::net::static_server::refresher; +use crate::net::web_server::{Acceptor, WebServer}; use crate::shutdown::Shutdown; use crate::system::launch_metrics_task; use crate::util::io::append_file; @@ -38,7 +39,7 @@ async fn inner_main( }; tokio::fs::write("/run/startos/initialized", "").await?; - server.serve_main(ctx.clone()); + server.serve_ui_for(ctx.clone()); LOGGER.set_logfile(None); handle.complete(); @@ -47,7 +48,7 @@ async fn inner_main( let init_ctx = InitContext::init(config).await?; let handle = init_ctx.progress.clone(); let rpc_ctx_phases = InitRpcContextPhases::new(&handle); - server.serve_init(init_ctx); + server.serve_ui_for(init_ctx); let ctx = RpcContext::init( &server.acceptor_setter(), @@ -63,14 +64,14 @@ async fn inner_main( ) .await?; - server.serve_main(ctx.clone()); + server.serve_ui_for(ctx.clone()); handle.complete(); ctx }; let (rpc_ctx, shutdown) = async { - crate::hostname::sync_hostname(&rpc_ctx.account.read().await.hostname).await?; + crate::hostname::sync_hostname(&rpc_ctx.account.peek(|a| a.hostname.clone())).await?; let mut shutdown_recv = rpc_ctx.shutdown.subscribe(); @@ -147,9 +148,10 @@ pub fn main(args: impl IntoIterator) { .build() .expect("failed to initialize runtime"); let res = rt.block_on(async { - let mut server = WebServer::new(Acceptor::bind_upgradable( - SelfContainedNetworkInterfaceListener::bind(80), - )); + let mut server = WebServer::new( + Acceptor::bind_upgradable(SelfContainedNetworkInterfaceListener::bind(BindTcp, 80)), + refresher(), + ); match inner_main(&mut server, &config).await { Ok(a) => { server.shutdown().await; @@ -177,7 +179,7 @@ pub fn main(args: impl IntoIterator) { e, )?; - server.serve_diagnostic(ctx.clone()); + server.serve_ui_for(ctx.clone()); let mut shutdown = ctx.shutdown.subscribe(); diff --git a/core/startos/src/bins/tunnel.rs b/core/startos/src/bins/tunnel.rs index d1deede3f..3a2e2337a 100644 --- a/core/startos/src/bins/tunnel.rs +++ b/core/startos/src/bins/tunnel.rs @@ -1,29 +1,110 @@ use std::ffi::OsString; +use std::net::SocketAddr; +use std::sync::Arc; +use std::time::Duration; use clap::Parser; use futures::FutureExt; +use helpers::NonDetachingJoinHandle; use rpc_toolkit::CliApp; use tokio::signal::unix::signal; use tracing::instrument; +use visit_rs::Visit; use crate::context::CliContext; use crate::context::config::ClientConfig; -use crate::net::web_server::{Acceptor, WebServer}; +use crate::net::gateway::{Bind, BindTcp}; +use crate::net::tls::TlsListener; +use crate::net::web_server::{Accept, Acceptor, MetadataVisitor, WebServer}; use crate::prelude::*; use crate::tunnel::context::{TunnelConfig, TunnelContext}; +use crate::tunnel::tunnel_router; +use crate::tunnel::web::TunnelCertHandler; use crate::util::logger::LOGGER; +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +enum WebserverListener { + Http, + Https(SocketAddr), +} +impl Visit for WebserverListener { + fn visit(&self, visitor: &mut V) -> ::Result { + visitor.visit(self) + } +} + #[instrument(skip_all)] async fn inner_main(config: &TunnelConfig) -> Result<(), Error> { let server = async { let ctx = TunnelContext::init(config).await?; - let mut server = WebServer::new(Acceptor::bind([ctx.listen]).await?); - server.serve_tunnel(ctx.clone()); + let listen = ctx.listen; + let server = WebServer::new( + Acceptor::bind_map_dyn([(WebserverListener::Http, listen)]).await?, + tunnel_router(ctx.clone()), + ); + let acceptor_setter = server.acceptor_setter(); + let https_db = ctx.db.clone(); + let https_thread: NonDetachingJoinHandle<()> = tokio::spawn(async move { + let mut sub = https_db.subscribe("/webserver".parse().unwrap()).await; + while { + while let Err(e) = async { + let webserver = https_db.peek().await.into_webserver(); + if webserver.as_enabled().de()? { + let addr = webserver.as_listen().de()?.or_not_found("listen address")?; + acceptor_setter.send_if_modified(|a| { + let key = WebserverListener::Https(addr); + if !a.contains_key(&key) { + match (|| { + Ok::<_, Error>(TlsListener::new( + BindTcp.bind(addr)?, + TunnelCertHandler { + db: https_db.clone(), + crypto_provider: Arc::new(tokio_rustls::rustls::crypto::ring::default_provider()), + }, + )) + })() { + Ok(l) => { + a.retain(|k, _| *k == WebserverListener::Http); + a.insert(key, l.into_dyn()); + + true + } + Err(e) => { + tracing::error!("error adding ssl listener: {e}"); + tracing::debug!("{e:?}"); + + false + } + } + } else { + false + } + }); + } else { + acceptor_setter.send_if_modified(|a| { + let before = a.len(); + a.retain(|k, _| *k == WebserverListener::Http); + a.len() != before + }); + } + + Ok::<_, Error>(()) + } + .await + { + tracing::error!("error updating webserver bind: {e}"); + tracing::debug!("{e:?}"); + tokio::time::sleep(Duration::from_secs(5)).await; + } + sub.recv().await.is_some() + } {} + }) + .into(); let mut shutdown_recv = ctx.shutdown.subscribe(); let sig_handler_ctx = ctx; - let sig_handler = tokio::spawn(async move { + let sig_handler: NonDetachingJoinHandle<()> = tokio::spawn(async move { use tokio::signal::unix::SignalKind; futures::future::select_all( [ @@ -48,14 +129,16 @@ async fn inner_main(config: &TunnelConfig) -> Result<(), Error> { .send(()) .map_err(|_| ()) .expect("send shutdown signal"); - }); + }) + .into(); shutdown_recv .recv() .await .with_kind(crate::ErrorKind::Unknown)?; - sig_handler.abort(); + sig_handler.wait_for_abort().await.with_kind(ErrorKind::Unknown)?; + https_thread.wait_for_abort().await.with_kind(ErrorKind::Unknown)?; Ok::<_, Error>(server) } diff --git a/core/startos/src/context/cli.rs b/core/startos/src/context/cli.rs index e93963f56..4234f9944 100644 --- a/core/startos/src/context/cli.rs +++ b/core/startos/src/context/cli.rs @@ -6,6 +6,7 @@ use std::sync::Arc; use cookie::{Cookie, Expiration, SameSite}; use cookie_store::CookieStore; +use http::HeaderMap; use imbl_value::InternedString; use josekit::jwk::Jwk; use once_cell::sync::OnceCell; @@ -26,7 +27,7 @@ use crate::developer::{OS_DEVELOPER_KEY_PATH, default_developer_key_path}; use crate::middleware::auth::AuthContext; use crate::prelude::*; use crate::rpc_continuations::Guid; -use crate::tunnel::context::TunnelContext; +use crate::util::io::read_file_to_string; #[derive(Debug)] pub struct CliContextSeed { @@ -159,7 +160,7 @@ impl CliContext { continue; } let pair = ::from_pkcs8_pem( - &std::fs::read_to_string(&self.developer_key_path)?, + &std::fs::read_to_string(path)?, ) .with_kind(crate::ErrorKind::Pem)?; let secret = ed25519_dalek::SecretKey::try_from(&pair.secret_key[..]).map_err(|_| { @@ -171,7 +172,7 @@ impl CliContext { return Ok(secret.into()) } Err(Error::new( - eyre!("Developer Key does not exist! Please run `start-cli init` before running this command."), + eyre!("Developer Key does not exist! Please run `start-cli init-key` before running this command."), crate::ErrorKind::Uninitialized )) }) @@ -233,23 +234,28 @@ impl CliContext { &self, method: &str, params: Value, - ) -> Result + ) -> Result where Self: CallRemote, { >::call_remote(&self, method, params, Empty {}) .await + .map_err(Error::from) + .with_ctx(|e| (e.kind, method)) } pub async fn call_remote_with( &self, method: &str, params: Value, extra: T, - ) -> Result + ) -> Result where Self: CallRemote, { - >::call_remote(&self, method, params, extra).await + >::call_remote(&self, method, params, extra) + .await + .map_err(Error::from) + .with_ctx(|e| (e.kind, method)) } } impl AsRef for CliContext { @@ -279,9 +285,15 @@ impl Context for CliContext { ) } } +impl AsRef for CliContext { + fn as_ref(&self) -> &Client { + &self.client + } +} + impl CallRemote for CliContext { async fn call_remote(&self, method: &str, params: Value, _: Empty) -> Result { - if let Ok(local) = std::fs::read_to_string(RpcContext::LOCAL_AUTH_COOKIE_PATH) { + if let Ok(local) = read_file_to_string(RpcContext::LOCAL_AUTH_COOKIE_PATH).await { self.cookie_store .lock() .unwrap() @@ -298,7 +310,8 @@ impl CallRemote for CliContext { crate::middleware::signature::call_remote( self, self.rpc_url.clone(), - self.rpc_url.host_str().or_not_found("rpc url hostname")?, + HeaderMap::new(), + self.rpc_url.host_str(), method, params, ) @@ -307,24 +320,11 @@ impl CallRemote for CliContext { } impl CallRemote for CliContext { async fn call_remote(&self, method: &str, params: Value, _: Empty) -> Result { - if let Ok(local) = std::fs::read_to_string(TunnelContext::LOCAL_AUTH_COOKIE_PATH) { - self.cookie_store - .lock() - .unwrap() - .insert_raw( - &Cookie::build(("local", local)) - .domain("localhost") - .expires(Expiration::Session) - .same_site(SameSite::Strict) - .build(), - &"http://localhost".parse()?, - ) - .with_kind(crate::ErrorKind::Network)?; - } crate::middleware::signature::call_remote( self, self.rpc_url.clone(), - self.rpc_url.host_str().or_not_found("rpc url hostname")?, + HeaderMap::new(), + self.rpc_url.host_str(), method, params, ) @@ -336,7 +336,8 @@ impl CallRemote for CliContext { crate::middleware::signature::call_remote( self, self.rpc_url.clone(), - self.rpc_url.host_str().or_not_found("rpc url hostname")?, + HeaderMap::new(), + self.rpc_url.host_str(), method, params, ) @@ -348,7 +349,8 @@ impl CallRemote for CliContext { crate::middleware::signature::call_remote( self, self.rpc_url.clone(), - self.rpc_url.host_str().or_not_found("rpc url hostname")?, + HeaderMap::new(), + self.rpc_url.host_str(), method, params, ) @@ -360,22 +362,11 @@ impl CallRemote for CliContext { crate::middleware::signature::call_remote( self, self.rpc_url.clone(), - self.rpc_url.host_str().or_not_found("rpc url hostname")?, + HeaderMap::new(), + self.rpc_url.host_str(), method, params, ) .await } } - -#[test] -fn test() { - let ctx = CliContext::init(ClientConfig::default()).unwrap(); - ctx.runtime().unwrap().block_on(async { - reqwest::Client::new() - .get("http://example.com") - .send() - .await - .unwrap(); - }); -} diff --git a/core/startos/src/context/init.rs b/core/startos/src/context/init.rs index bceae8a86..b7d5eac6a 100644 --- a/core/startos/src/context/init.rs +++ b/core/startos/src/context/init.rs @@ -6,10 +6,10 @@ use tokio::sync::broadcast::Sender; use tokio::sync::watch; use tracing::instrument; +use crate::Error; use crate::context::config::ServerConfig; use crate::progress::FullProgressTracker; use crate::rpc_continuations::RpcContinuations; -use crate::Error; pub struct InitContextSeed { pub config: ServerConfig, diff --git a/core/startos/src/context/rpc.rs b/core/startos/src/context/rpc.rs index 0e05a1cf8..7ffd339d9 100644 --- a/core/startos/src/context/rpc.rs +++ b/core/startos/src/context/rpc.rs @@ -1,11 +1,10 @@ use std::collections::{BTreeMap, BTreeSet}; use std::ffi::OsStr; use std::future::Future; -use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4}; use std::ops::Deref; use std::path::{Path, PathBuf}; -use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; +use std::sync::atomic::{AtomicBool, Ordering}; use std::time::Duration; use chrono::{TimeDelta, Utc}; @@ -18,36 +17,37 @@ use models::{ActionId, PackageId}; use reqwest::{Client, Proxy}; use rpc_toolkit::yajrc::RpcError; use rpc_toolkit::{CallRemote, Context, Empty}; -use tokio::sync::{broadcast, oneshot, watch, RwLock}; +use tokio::sync::{RwLock, broadcast, oneshot, watch}; use tokio::time::Instant; use tracing::instrument; use super::setup::CURRENT_SECRET; +use crate::DATA_DIR; use crate::account::AccountInfo; use crate::auth::Sessions; use crate::context::config::ServerConfig; -use crate::db::model::package::TaskSeverity; use crate::db::model::Database; +use crate::db::model::package::TaskSeverity; use crate::disk::OsPartitionInfo; -use crate::init::{check_time_is_synchronized, InitResult}; +use crate::init::{InitResult, check_time_is_synchronized}; use crate::install::PKG_ARCHIVE_DIR; use crate::lxc::LxcManager; +use crate::net::gateway::UpgradableListener; use crate::net::net_controller::{NetController, NetService}; use crate::net::socks::DEFAULT_SOCKS_LISTEN; use crate::net::utils::{find_eth_iface, find_wifi_iface}; -use crate::net::web_server::{UpgradableListener, WebServerAcceptorSetter}; +use crate::net::web_server::WebServerAcceptorSetter; use crate::net::wifi::WpaCli; use crate::prelude::*; use crate::progress::{FullProgressTracker, PhaseProgressTrackerHandle}; use crate::rpc_continuations::{Guid, OpenAuthedContinuations, RpcContinuations}; +use crate::service::ServiceMap; use crate::service::action::update_tasks; use crate::service::effects::callbacks::ServiceCallbacks; -use crate::service::ServiceMap; use crate::shutdown::Shutdown; use crate::util::io::delete_file; use crate::util::lshw::LshwDevice; -use crate::util::sync::{SyncMutex, Watch}; -use crate::{DATA_DIR, HOST_IP}; +use crate::util::sync::{SyncMutex, SyncRwLock, Watch}; pub struct RpcContextSeed { is_closed: AtomicBool, @@ -58,7 +58,7 @@ pub struct RpcContextSeed { pub ephemeral_sessions: SyncMutex, pub db: TypedPatchDb, pub sync_db: watch::Sender, - pub account: RwLock, + pub account: SyncRwLock, pub net_controller: Arc, pub os_net_service: NetService, pub s9pk_arch: Option<&'static str>, @@ -225,7 +225,7 @@ impl RpcContext { ephemeral_sessions: SyncMutex::new(Sessions::new()), sync_db: watch::Sender::new(db.sequence().await), db, - account: RwLock::new(account), + account: SyncRwLock::new(account), callbacks: net_controller.callbacks.clone(), net_controller, os_net_service, @@ -483,6 +483,11 @@ impl RpcContext { >::call_remote(&self, method, params, extra).await } } +impl AsRef for RpcContext { + fn as_ref(&self) -> &Client { + &self.client + } +} impl AsRef for RpcContext { fn as_ref(&self) -> &Jwk { &CURRENT_SECRET diff --git a/core/startos/src/context/setup.rs b/core/startos/src/context/setup.rs index 94c81a9db..a00b092ed 100644 --- a/core/startos/src/context/setup.rs +++ b/core/startos/src/context/setup.rs @@ -10,24 +10,25 @@ use josekit::jwk::Jwk; use patch_db::PatchDb; use rpc_toolkit::Context; use serde::{Deserialize, Serialize}; -use tokio::sync::broadcast::Sender; use tokio::sync::OnceCell; +use tokio::sync::broadcast::Sender; use tracing::instrument; use ts_rs::TS; +use crate::MAIN_DATA; use crate::account::AccountInfo; -use crate::context::config::ServerConfig; use crate::context::RpcContext; +use crate::context::config::ServerConfig; use crate::disk::OsPartitionInfo; use crate::hostname::Hostname; -use crate::net::web_server::{UpgradableListener, WebServer, WebServerAcceptorSetter}; +use crate::net::gateway::UpgradableListener; +use crate::net::web_server::{WebServer, WebServerAcceptorSetter}; use crate::prelude::*; use crate::progress::FullProgressTracker; use crate::rpc_continuations::{Guid, RpcContinuation, RpcContinuations}; use crate::setup::SetupProgress; use crate::shutdown::Shutdown; use crate::util::net::WebSocketExt; -use crate::MAIN_DATA; lazy_static::lazy_static! { pub static ref CURRENT_SECRET: Jwk = Jwk::generate_ec_key(josekit::jwk::alg::ec::EcCurve::P256).unwrap_or_else(|e| { diff --git a/core/startos/src/db/mod.rs b/core/startos/src/db/mod.rs index f1a16ab2f..aad28d1eb 100644 --- a/core/startos/src/db/mod.rs +++ b/core/startos/src/db/mod.rs @@ -1,6 +1,7 @@ pub mod model; pub mod prelude; +use std::panic::UnwindSafe; use std::path::PathBuf; use std::sync::Arc; use std::time::Duration; @@ -29,6 +30,26 @@ lazy_static::lazy_static! { static ref PUBLIC: JsonPointer = "/public".parse().unwrap(); } +pub trait DbAccess: Sized { + fn access<'a>(db: &'a Model) -> &'a Model; +} + +pub trait DbAccessMut: DbAccess { + fn access_mut<'a>(db: &'a mut Model) -> &'a mut Model; +} + +pub trait DbAccessByKey: Sized { + type Key<'a>; + fn access_by_key<'a>(db: &'a Model, key: Self::Key<'_>) -> Option<&'a Model>; +} + +pub trait DbAccessMutByKey: DbAccessByKey { + fn access_mut_by_key<'a>( + db: &'a mut Model, + key: Self::Key<'_>, + ) -> Option<&'a mut Model>; +} + pub fn db() -> ParentHandler { ParentHandler::new() .subcommand( @@ -127,7 +148,7 @@ pub struct SubscribeParams { #[ts(type = "string | null")] pointer: Option, #[ts(skip)] - #[serde(rename = "__auth_session")] + #[serde(rename = "__Auth_session")] session: Option, } diff --git a/core/startos/src/db/model/public.rs b/core/startos/src/db/model/public.rs index d090b545b..f16125ae9 100644 --- a/core/startos/src/db/model/public.rs +++ b/core/startos/src/db/model/public.rs @@ -1,5 +1,6 @@ use std::collections::{BTreeMap, BTreeSet, VecDeque}; -use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}; +use std::net::{IpAddr, Ipv4Addr, SocketAddr}; +use std::sync::Arc; use chrono::{DateTime, Utc}; use exver::{Version, VersionRange}; @@ -8,7 +9,6 @@ use imbl_value::InternedString; use ipnet::IpNet; use isocountry::CountryCode; use itertools::Itertools; -use lazy_static::lazy_static; use models::{GatewayId, PackageId}; use openssl::hash::MessageDigest; use patch_db::{HasModel, Value}; @@ -16,11 +16,12 @@ use serde::{Deserialize, Serialize}; use ts_rs::TS; use crate::account::AccountInfo; +use crate::db::DbAccessByKey; +use crate::db::model::Database; use crate::db::model::package::AllPackageData; use crate::net::acme::AcmeProvider; -use crate::net::forward::START9_BRIDGE_IFACE; -use crate::net::host::binding::{AddSslOptions, BindInfo, BindOptions, NetInfo}; use crate::net::host::Host; +use crate::net::host::binding::{AddSslOptions, BindInfo, BindOptions, NetInfo}; use crate::net::utils::ipv6_is_local; use crate::net::vhost::AlpnInfo; use crate::prelude::*; @@ -30,7 +31,7 @@ use crate::util::cpupower::Governor; use crate::util::lshw::LshwDevice; use crate::util::serde::MaybeUtf8String; use crate::version::{Current, VersionT}; -use crate::{ARCH, HOST_IP, PLATFORM}; +use crate::{ARCH, PLATFORM}; #[derive(Debug, Deserialize, Serialize, HasModel, TS)] #[serde(rename_all = "camelCase")] @@ -122,11 +123,20 @@ impl Public { kiosk, }, package_data: AllPackageData::default(), - ui: serde_json::from_str(include_str!(concat!( - env!("CARGO_MANIFEST_DIR"), - "/../../web/patchdb-ui-seed.json" - ))) - .with_kind(ErrorKind::Deserialization)?, + ui: { + #[cfg(feature = "startd")] + { + serde_json::from_str(include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/../../web/patchdb-ui-seed.json" + ))) + .with_kind(ErrorKind::Deserialization)? + } + #[cfg(not(feature = "startd"))] + { + Value::Null + } + }, }) } } @@ -216,64 +226,9 @@ pub struct NetworkInterfaceInfo { pub name: Option, pub public: Option, pub secure: Option, - pub ip_info: Option, + pub ip_info: Option>, } impl NetworkInterfaceInfo { - pub fn loopback() -> (&'static GatewayId, &'static Self) { - lazy_static! { - static ref LO: GatewayId = GatewayId::from(InternedString::intern("lo")); - static ref LOOPBACK: NetworkInterfaceInfo = NetworkInterfaceInfo { - name: Some(InternedString::from_static("Loopback")), - public: Some(false), - secure: Some(true), - ip_info: Some(IpInfo { - name: "lo".into(), - scope_id: 1, - device_type: None, - subnets: [ - IpNet::new(Ipv4Addr::LOCALHOST.into(), 8).unwrap(), - IpNet::new(Ipv6Addr::LOCALHOST.into(), 128).unwrap(), - ] - .into_iter() - .collect(), - lan_ip: [ - IpAddr::from(Ipv4Addr::LOCALHOST), - IpAddr::from(Ipv6Addr::LOCALHOST) - ] - .into_iter() - .collect(), - wan_ip: None, - ntp_servers: Default::default(), - dns_servers: Default::default(), - }), - }; - } - (&*LO, &*LOOPBACK) - } - pub fn lxc_bridge() -> (&'static GatewayId, &'static Self) { - lazy_static! { - static ref LXCBR0: GatewayId = - GatewayId::from(InternedString::intern(START9_BRIDGE_IFACE)); - static ref LXC_BRIDGE: NetworkInterfaceInfo = NetworkInterfaceInfo { - name: Some(InternedString::from_static("LXC Bridge Interface")), - public: Some(false), - secure: Some(true), - ip_info: Some(IpInfo { - name: START9_BRIDGE_IFACE.into(), - scope_id: 0, - device_type: None, - subnets: [IpNet::new(HOST_IP.into(), 24).unwrap()] - .into_iter() - .collect(), - lan_ip: [IpAddr::from(HOST_IP)].into_iter().collect(), - wan_ip: None, - ntp_servers: Default::default(), - dns_servers: Default::default(), - }), - }; - } - (&*LXCBR0, &*LXC_BRIDGE) - } pub fn public(&self) -> bool { self.public.unwrap_or_else(|| { !self.ip_info.as_ref().map_or(true, |ip_info| { @@ -308,7 +263,7 @@ impl NetworkInterfaceInfo { self.secure.unwrap_or_else(|| { self.ip_info.as_ref().map_or(false, |ip_info| { ip_info.device_type == Some(NetworkInterfaceType::Wireguard) - }) + }) && !self.public() }) } } @@ -333,13 +288,15 @@ pub struct IpInfo { pub dns_servers: OrdSet, } -#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize, TS)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize, TS)] #[ts(export)] #[serde(rename_all = "kebab-case")] pub enum NetworkInterfaceType { Ethernet, Wireless, + Bridge, Wireguard, + Loopback, } #[derive(Debug, Deserialize, Serialize, HasModel, TS)] @@ -349,6 +306,19 @@ pub enum NetworkInterfaceType { pub struct AcmeSettings { pub contact: Vec, } +impl DbAccessByKey for Database { + type Key<'a> = &'a AcmeProvider; + fn access_by_key<'a>( + db: &'a Model, + key: Self::Key<'_>, + ) -> Option<&'a Model> { + db.as_public() + .as_server_info() + .as_network() + .as_acme() + .as_idx(key) + } +} #[derive(Debug, Deserialize, Serialize, HasModel, TS)] #[serde(rename_all = "camelCase")] diff --git a/core/startos/src/db/prelude.rs b/core/startos/src/db/prelude.rs index bb779a3c0..f45d051cc 100644 --- a/core/startos/src/db/prelude.rs +++ b/core/startos/src/db/prelude.rs @@ -1,6 +1,7 @@ use std::collections::{BTreeMap, BTreeSet}; use std::marker::PhantomData; use std::str::FromStr; +use std::sync::Arc; use chrono::{DateTime, Utc}; use imbl::OrdMap; @@ -167,6 +168,21 @@ impl Model> { } } +impl Model> { + pub fn deref(self) -> Model { + use patch_db::ModelExt; + self.transmute(|a| a) + } + pub fn as_deref(&self) -> &Model { + use patch_db::ModelExt; + self.transmute_ref(|a| a) + } + pub fn as_deref_mut(&mut self) -> &mut Model { + use patch_db::ModelExt; + self.transmute_mut(|a| a) + } +} + pub trait Map: DeserializeOwned + Serialize { type Key; type Value; @@ -193,10 +209,10 @@ where A: serde::Serialize + serde::de::DeserializeOwned + Ord, B: serde::Serialize + serde::de::DeserializeOwned, { - type Key = A; + type Key = JsonKey; type Value = B; fn key_str(key: &Self::Key) -> Result, Error> { - serde_json::to_string(key).with_kind(ErrorKind::Serialization) + serde_json::to_string(&key.0).with_kind(ErrorKind::Serialization) } } @@ -216,13 +232,18 @@ impl Model where T::Value: Serialize, { - pub fn insert(&mut self, key: &T::Key, value: &T::Value) -> Result<(), Error> { + pub fn insert_model( + &mut self, + key: &T::Key, + value: Model, + ) -> Result>, Error> { + use patch_db::ModelExt; use serde::ser::Error; - let v = patch_db::value::to_value(value)?; + let v = value.into_value(); match &mut self.value { Value::Object(o) => { - o.insert(T::key_string(key)?, v); - Ok(()) + let prev = o.insert(T::key_string(key)?, v); + Ok(prev.map(|v| Model::from_value(v))) } v => Err(patch_db::value::Error { source: patch_db::value::ErrorSource::custom(format!("expected object found {v}")), @@ -231,6 +252,13 @@ where .into()), } } + pub fn insert( + &mut self, + key: &T::Key, + value: &T::Value, + ) -> Result>, Error> { + self.insert_model(key, Model::new(value)?) + } pub fn upsert(&mut self, key: &T::Key, value: F) -> Result<&mut Model, Error> where F: FnOnce() -> Result, @@ -257,22 +285,6 @@ where .into()), } } - pub fn insert_model(&mut self, key: &T::Key, value: Model) -> Result<(), Error> { - use patch_db::ModelExt; - use serde::ser::Error; - let v = value.into_value(); - match &mut self.value { - Value::Object(o) => { - o.insert(T::key_string(key)?, v); - Ok(()) - } - v => Err(patch_db::value::Error { - source: patch_db::value::ErrorSource::custom(format!("expected object found {v}")), - kind: patch_db::value::ErrorKind::Serialization, - } - .into()), - } - } } impl Model @@ -437,6 +449,12 @@ impl std::ops::DerefMut for JsonKey { &mut self.0 } } +impl FromStr for JsonKey { + type Err = Error; + fn from_str(s: &str) -> Result { + serde_json::from_str(s).with_kind(ErrorKind::Deserialization) + } +} impl Serialize for JsonKey { fn serialize(&self, serializer: S) -> Result where @@ -449,7 +467,7 @@ impl Serialize for JsonKey { } } // { "foo": "bar" } -> "{ \"foo\": \"bar\" }" -impl<'de, T: Serialize + DeserializeOwned> Deserialize<'de> for JsonKey { +impl<'de, T: DeserializeOwned> Deserialize<'de> for JsonKey { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, diff --git a/core/startos/src/dependencies.rs b/core/startos/src/dependencies.rs index 43ed3bbc3..375b6c67d 100644 --- a/core/startos/src/dependencies.rs +++ b/core/startos/src/dependencies.rs @@ -6,9 +6,9 @@ use models::PackageId; use serde::{Deserialize, Serialize}; use ts_rs::TS; +use crate::Error; use crate::prelude::*; use crate::util::PathOrUrl; -use crate::Error; #[derive(Clone, Debug, Default, Deserialize, Serialize, HasModel, TS)] #[model = "Model"] diff --git a/core/startos/src/disk/mount/filesystem/idmapped.rs b/core/startos/src/disk/mount/filesystem/idmapped.rs index b7393a722..093575924 100644 --- a/core/startos/src/disk/mount/filesystem/idmapped.rs +++ b/core/startos/src/disk/mount/filesystem/idmapped.rs @@ -80,23 +80,6 @@ impl FileSystem for IdMapped { } Ok(()) } - async fn mount + Send>( - &self, - mountpoint: P, - mount_type: MountType, - ) -> Result<(), Error> { - self.pre_mount(mountpoint.as_ref()).await?; - Command::new("mount.next") - .args( - default_mount_command(self, mountpoint, mount_type) - .await? - .get_args(), - ) - .invoke(ErrorKind::Filesystem) - .await?; - - Ok(()) - } async fn source_hash( &self, ) -> Result::OutputSize>, Error> { diff --git a/core/startos/src/disk/mount/guard.rs b/core/startos/src/disk/mount/guard.rs index 761060f20..980e4daa5 100644 --- a/core/startos/src/disk/mount/guard.rs +++ b/core/startos/src/disk/mount/guard.rs @@ -10,8 +10,8 @@ use tracing::instrument; use super::filesystem::{FileSystem, MountType, ReadOnly, ReadWrite}; use super::util::unmount; -use crate::util::{Invoke, Never}; use crate::Error; +use crate::util::{Invoke, Never}; pub const TMP_MOUNTPOINT: &'static str = "/media/startos/tmp"; diff --git a/core/startos/src/init.rs b/core/startos/src/init.rs index ecba6fde9..001dca911 100644 --- a/core/startos/src/init.rs +++ b/core/startos/src/init.rs @@ -8,7 +8,7 @@ use const_format::formatcp; use futures::{StreamExt, TryStreamExt}; use itertools::Itertools; use models::ResultExt; -use rpc_toolkit::{from_fn_async, Context, Empty, HandlerArgs, HandlerExt, ParentHandler}; +use rpc_toolkit::{Context, Empty, HandlerArgs, HandlerExt, ParentHandler, from_fn_async}; use serde::{Deserialize, Serialize}; use tokio::process::Command; use tracing::instrument; @@ -17,15 +17,16 @@ use ts_rs::TS; use crate::account::AccountInfo; use crate::context::config::ServerConfig; use crate::context::{CliContext, InitContext, RpcContext}; -use crate::db::model::public::ServerStatus; use crate::db::model::Database; +use crate::db::model::public::ServerStatus; use crate::developer::OS_DEVELOPER_KEY_PATH; use crate::hostname::Hostname; use crate::middleware::auth::AuthContext; +use crate::net::gateway::UpgradableListener; use crate::net::net_controller::{NetController, NetService}; use crate::net::socks::DEFAULT_SOCKS_LISTEN; use crate::net::utils::find_wifi_iface; -use crate::net::web_server::{UpgradableListener, WebServerAcceptorSetter}; +use crate::net::web_server::WebServerAcceptorSetter; use crate::prelude::*; use crate::progress::{ FullProgress, FullProgressTracker, PhaseProgressTrackerHandle, PhasedProgressBar, ProgressUnits, @@ -34,10 +35,10 @@ use crate::rpc_continuations::{Guid, RpcContinuation}; use crate::s9pk::v2::pack::{CONTAINER_DATADIR, CONTAINER_TOOL}; use crate::ssh::SSH_DIR; use crate::system::{get_mem_info, sync_kiosk}; -use crate::util::io::{open_file, IOHook}; +use crate::util::io::{IOHook, open_file}; use crate::util::lshw::lshw; use crate::util::net::WebSocketExt; -use crate::util::{cpupower, Invoke}; +use crate::util::{Invoke, cpupower}; use crate::{Error, MAIN_DATA, PACKAGE_DATA}; pub const SYSTEM_REBUILD_PATH: &str = "/media/startos/config/system-rebuild"; diff --git a/core/startos/src/install/mod.rs b/core/startos/src/install/mod.rs index 3c4d54ebc..5a13204f5 100644 --- a/core/startos/src/install/mod.rs +++ b/core/startos/src/install/mod.rs @@ -7,7 +7,7 @@ use clap::builder::ValueParserFactory; use clap::{CommandFactory, FromArgMatches, Parser, value_parser}; use color_eyre::eyre::eyre; use exver::VersionRange; -use futures::{AsyncWriteExt, StreamExt}; +use futures::StreamExt; use imbl_value::{InternedString, json}; use itertools::Itertools; use models::{FromStrParser, VersionString}; @@ -15,7 +15,6 @@ use reqwest::Url; use reqwest::header::{CONTENT_LENGTH, HeaderMap}; use rpc_toolkit::HandlerArgs; use rpc_toolkit::yajrc::RpcError; -use rustyline_async::ReadlineEvent; use serde::{Deserialize, Serialize}; use tokio::sync::oneshot; use tokio_tungstenite::tungstenite::protocol::frame::coding::CloseCode; @@ -34,6 +33,7 @@ use crate::upload::upload; use crate::util::Never; use crate::util::io::open_file; use crate::util::net::WebSocketExt; +use crate::util::tui::choose; pub const PKG_ARCHIVE_DIR: &str = "package-data/archive"; pub const PKG_PUBLIC_DIR: &str = "package-data/public"; @@ -175,7 +175,7 @@ pub async fn install( #[serde(rename_all = "camelCase")] pub struct SideloadParams { #[ts(skip)] - #[serde(rename = "__auth_session")] + #[serde(rename = "__Auth_session")] session: Option, } @@ -483,47 +483,19 @@ pub async fn cli_install( let version = if packages.best.len() == 1 { packages.best.pop_first().map(|(k, _)| k).unwrap() } else { - println!( - "Multiple flavors of {id} found. Please select one of the following versions to install:" - ); - let version; - loop { - let (mut read, mut output) = rustyline_async::Readline::new("> ".into()) - .with_kind(ErrorKind::Filesystem)?; - for (idx, version) in packages.best.keys().enumerate() { - output - .write_all(format!(" {}) {}\n", idx + 1, version).as_bytes()) - .await?; - read.add_history_entry(version.to_string()); - } - if let ReadlineEvent::Line(line) = read.readline().await? { - let trimmed = line.trim(); - match trimmed.parse() { - Ok(v) => { - if let Some((k, _)) = packages.best.remove_entry(&v) { - version = k; - break; - } - } - Err(_) => match trimmed.parse::() { - Ok(i) if (1..=packages.best.len()).contains(&i) => { - version = packages.best.keys().nth(i - 1).unwrap().clone(); - break; - } - _ => (), - }, - } - eprintln!("invalid selection: {trimmed}"); - println!("Please select one of the following versions to install:"); - } else { - return Err(Error::new( - eyre!("Could not determine precise version to install"), - ErrorKind::InvalidRequest, - ) - .into()); - } - } - version + let versions = packages.best.keys().collect::>(); + let version = choose( + &format!( + concat!( + "Multiple flavors of {id} found. ", + "Please select one of the following versions to install:" + ), + id = id + ), + &versions, + ) + .await?; + (*version).clone() }; ctx.call_remote::( &method.join("."), diff --git a/core/startos/src/lib.rs b/core/startos/src/lib.rs index bcf3d3418..7b0d83e1f 100644 --- a/core/startos/src/lib.rs +++ b/core/startos/src/lib.rs @@ -80,17 +80,16 @@ use imbl_value::Value; use rpc_toolkit::yajrc::RpcError; use rpc_toolkit::{ CallRemoteHandler, Context, Empty, HandlerExt, ParentHandler, from_fn, from_fn_async, - from_fn_blocking, + from_fn_async_local, from_fn_blocking, }; use serde::{Deserialize, Serialize}; use ts_rs::TS; -use crate::context::{ - CliContext, DiagnosticContext, InitContext, InstallContext, RpcContext, SetupContext, -}; +use crate::context::{CliContext, DiagnosticContext, InitContext, RpcContext}; use crate::disk::fsck::RequiresReboot; use crate::registry::context::{RegistryContext, RegistryUrlParams}; use crate::system::kiosk; +use crate::tunnel::context::TunnelUrlParams; use crate::util::serde::{HandlerExtSerde, WithIoFormat, display_serializable}; #[derive(Deserialize, Serialize, Parser, TS)] @@ -139,6 +138,20 @@ pub fn main_api() -> ParentHandler { .with_about("Display the API that is currently serving") .with_call_remote::(), ) + .subcommand( + "state", + from_fn(|_: InitContext| Ok::<_, Error>(ApiState::Initializing)) + .with_metadata("authenticated", Value::Bool(false)) + .with_about("Display the API that is currently serving") + .with_call_remote::(), + ) + .subcommand( + "state", + from_fn(|_: DiagnosticContext| Ok::<_, Error>(ApiState::Error)) + .with_metadata("authenticated", Value::Bool(false)) + .with_about("Display the API that is currently serving") + .with_call_remote::(), + ) .subcommand( "server", server::() @@ -191,6 +204,19 @@ pub fn main_api() -> ParentHandler { ) .no_cli(), ) + .subcommand( + "registry", + registry::registry_api::().with_about("Commands related to the registry"), + ) + .subcommand( + "tunnel", + CallRemoteHandler::::new(tunnel::api::tunnel_api()) + .no_cli(), + ) + .subcommand( + "tunnel", + tunnel::api::tunnel_api::().with_about("Commands related to StartTunnel"), + ) .subcommand( "s9pk", s9pk::rpc::s9pk().with_about("Commands for interacting with s9pk files"), @@ -198,6 +224,29 @@ pub fn main_api() -> ParentHandler { .subcommand( "util", util::rpc::util::().with_about("Command for calculating the blake3 hash of a file"), + ) + .subcommand( + "init-key", + from_fn_async(developer::init) + .no_display() + .with_about("Create developer key if it doesn't exist"), + ) + .subcommand( + "pubkey", + from_fn_blocking(developer::pubkey) + .with_about("Get public key for developer private key"), + ) + .subcommand( + "diagnostic", + diagnostic::diagnostic::() + .with_about("Commands to display logs, restart the server, etc"), + ) + .subcommand("init", init::init_api::()) + .subcommand("setup", setup::setup::()) + .subcommand( + "install", + os_install::install::() + .with_about("Commands to list disk info, install StartOS, and reboot"), ); if &*PLATFORM != "raspberrypi" { api = api.subcommand("kiosk", kiosk::()); @@ -343,7 +392,7 @@ pub fn package() -> ParentHandler { ) .subcommand( "install", - from_fn_async(install::cli_install) + from_fn_async_local(install::cli_install) .no_display() .with_about("Install a package from a marketplace or via sideloading"), ) @@ -464,13 +513,6 @@ pub fn package() -> ParentHandler { backup::package_backup::() .with_about("Commands for restoring package(s) from backup"), ) - .subcommand("connect", from_fn_async(service::connect_rpc).no_cli()) - .subcommand( - "connect", - from_fn_async(service::connect_rpc_cli) - .no_display() - .with_about("Connect to a LXC container"), - ) .subcommand( "attach", from_fn_async(service::attach) @@ -484,127 +526,3 @@ pub fn package() -> ParentHandler { net::host::host_api::().with_about("Manage network hosts for a package"), ) } - -pub fn diagnostic_api() -> ParentHandler { - ParentHandler::new() - .subcommand( - "git-info", - from_fn(|_: DiagnosticContext| version::git_info()) - .with_metadata("authenticated", Value::Bool(false)) - .with_about("Display the githash of StartOS CLI"), - ) - .subcommand( - "echo", - from_fn(echo::) - .with_about("Echo a message") - .with_call_remote::(), - ) - .subcommand( - "state", - from_fn(|_: DiagnosticContext| Ok::<_, Error>(ApiState::Error)) - .with_metadata("authenticated", Value::Bool(false)) - .with_about("Display the API that is currently serving") - .with_call_remote::(), - ) - .subcommand( - "diagnostic", - diagnostic::diagnostic::() - .with_about("Diagnostic commands i.e. logs, restart, rebuild"), - ) -} - -pub fn init_api() -> ParentHandler { - ParentHandler::new() - .subcommand( - "git-info", - from_fn(|_: InitContext| version::git_info()) - .with_metadata("authenticated", Value::Bool(false)) - .with_about("Display the githash of StartOS CLI"), - ) - .subcommand( - "echo", - from_fn(echo::) - .with_about("Echo a message") - .with_call_remote::(), - ) - .subcommand( - "state", - from_fn(|_: InitContext| Ok::<_, Error>(ApiState::Initializing)) - .with_metadata("authenticated", Value::Bool(false)) - .with_about("Display the API that is currently serving") - .with_call_remote::(), - ) - .subcommand( - "init", - init::init_api::() - .with_about("Commands to get logs or initialization progress"), - ) -} - -pub fn setup_api() -> ParentHandler { - ParentHandler::new() - .subcommand( - "git-info", - from_fn(|_: SetupContext| version::git_info()) - .with_metadata("authenticated", Value::Bool(false)) - .with_about("Display the githash of StartOS CLI"), - ) - .subcommand( - "echo", - from_fn(echo::) - .with_about("Echo a message") - .with_call_remote::(), - ) - .subcommand("setup", setup::setup::()) -} - -pub fn install_api() -> ParentHandler { - ParentHandler::new() - .subcommand( - "git-info", - from_fn(|_: InstallContext| version::git_info()) - .with_metadata("authenticated", Value::Bool(false)) - .with_about("Display the githash of StartOS CLI"), - ) - .subcommand( - "echo", - from_fn(echo::) - .with_about("Echo a message") - .with_call_remote::(), - ) - .subcommand( - "install", - os_install::install::() - .with_about("Commands to list disk info, install StartOS, and reboot"), - ) -} - -pub fn expanded_api() -> ParentHandler { - main_api() - .subcommand( - "init", - from_fn_async(developer::init) - .no_display() - .with_about("Create developer key if it doesn't exist"), - ) - .subcommand( - "pubkey", - from_fn_blocking(developer::pubkey) - .with_about("Get public key for developer private key"), - ) - .subcommand( - "diagnostic", - diagnostic::diagnostic::() - .with_about("Commands to display logs, restart the server, etc"), - ) - .subcommand("setup", setup::setup::()) - .subcommand( - "install", - os_install::install::() - .with_about("Commands to list disk info, install StartOS, and reboot"), - ) - .subcommand( - "registry", - registry::registry_api::().with_about("Commands related to the registry"), - ) -} diff --git a/core/startos/src/logs.rs b/core/startos/src/logs.rs index 728c9cd71..15bf31ebe 100644 --- a/core/startos/src/logs.rs +++ b/core/startos/src/logs.rs @@ -15,7 +15,7 @@ use itertools::Itertools; use models::{FromStrParser, PackageId}; use rpc_toolkit::yajrc::RpcError; use rpc_toolkit::{ - from_fn_async, CallRemote, Context, Empty, HandlerArgs, HandlerExt, HandlerFor, ParentHandler, + CallRemote, Context, Empty, HandlerArgs, HandlerExt, HandlerFor, ParentHandler, from_fn_async, }; use serde::de::{self, DeserializeOwned}; use serde::{Deserialize, Serialize}; @@ -30,9 +30,9 @@ use crate::error::ResultExt; use crate::lxc::ContainerId; use crate::prelude::*; use crate::rpc_continuations::{Guid, RpcContinuation, RpcContinuations}; +use crate::util::Invoke; use crate::util::net::WebSocketExt; use crate::util::serde::Reversible; -use crate::util::Invoke; #[pin_project::pin_project] pub struct LogStream { diff --git a/core/startos/src/lxc/mod.rs b/core/startos/src/lxc/mod.rs index ff9f0fc24..869e58c09 100644 --- a/core/startos/src/lxc/mod.rs +++ b/core/startos/src/lxc/mod.rs @@ -10,7 +10,6 @@ use imbl_value::{InOMap, InternedString}; use models::{FromStrParser, InvalidId, PackageId}; use rpc_toolkit::yajrc::RpcError; use rpc_toolkit::{GenericRpcMethod, RpcRequest, RpcResponse}; -use rustyline_async::{ReadlineEvent, SharedWriter}; use serde::{Deserialize, Serialize}; use tokio::io::{AsyncBufReadExt, BufReader}; use tokio::process::Command; @@ -470,115 +469,6 @@ pub async fn connect(ctx: &RpcContext, container: &LxcContainer) -> Result Result<(), Error> { - use futures::SinkExt; - use tokio_tungstenite::tungstenite::Message; - - let mut ws = ctx.ws_continuation(guid).await?; - let (mut input, mut output) = - rustyline_async::Readline::new("> ".into()).with_kind(ErrorKind::Filesystem)?; - - async fn handle_message( - msg: Option>, - output: &mut SharedWriter, - ) -> Result { - match msg { - None => return Ok(true), - Some(Ok(Message::Text(txt))) => match serde_json::from_str::(&txt) { - Ok(RpcResponse { result: Ok(a), .. }) => { - output - .write_all( - (serde_json::to_string(&a).with_kind(ErrorKind::Serialization)? + "\n") - .as_bytes(), - ) - .await?; - } - Ok(RpcResponse { result: Err(e), .. }) => { - let e: Error = e.into(); - tracing::error!("{e}"); - tracing::debug!("{e:?}"); - } - Err(e) => { - tracing::error!("Error Parsing RPC response: {e}"); - tracing::debug!("{e:?}"); - } - }, - Some(Ok(_)) => (), - Some(Err(e)) => { - return Err(Error::new(e, ErrorKind::Network)); - } - }; - Ok(false) - } - - loop { - tokio::select! { - line = input.readline() => { - let line = line.with_kind(ErrorKind::Filesystem)?; - if let ReadlineEvent::Line(line) = line { - input.add_history_entry(line.clone()); - if serde_json::from_str::(&line).is_ok() { - ws.send(Message::Text(line.into())) - .await - .with_kind(ErrorKind::Network)?; - } else { - match shell_words::split(&line) { - Ok(command) => { - if let Some((method, rest)) = command.split_first() { - let mut params = InOMap::new(); - for arg in rest { - if let Some((name, value)) = arg.split_once('=') { - params.insert(InternedString::intern(name), if value.is_empty() { - Value::Null - } else if let Ok(v) = serde_json::from_str(value) { - v - } else { - Value::String(Arc::new(value.into())) - }); - } else { - tracing::error!("argument without a value: {arg}"); - tracing::debug!("help: set the value of {arg} with `{arg}=...`"); - continue; - } - } - ws.send(Message::Text(match serde_json::to_string(&RpcRequest { - id: None, - method: GenericRpcMethod::new(method.into()), - params: Value::Object(params), - }) { - Ok(a) => a.into(), - Err(e) => { - tracing::error!("Error Serializing Request: {e}"); - tracing::debug!("{e:?}"); - continue; - } - })).await.with_kind(ErrorKind::Network)?; - if handle_message(ws.next().await, &mut output).await? { - break - } - } - } - Err(e) => { - tracing::error!("{e}"); - tracing::debug!("{e:?}"); - } - } - } - } else { - ws.send(Message::Close(None)).await.with_kind(ErrorKind::Network)?; - } - } - msg = ws.next() => { - if handle_message(msg, &mut output).await? { - break; - } - } - } - } - - Ok(()) -} - pub async fn stats(ctx: RpcContext) -> Result>, Error> { let ids = ctx.db.peek().await.as_public().as_package_data().keys()?; diff --git a/core/startos/src/middleware/auth.rs b/core/startos/src/middleware/auth.rs index 4fed0fd12..3d2d7679e 100644 --- a/core/startos/src/middleware/auth.rs +++ b/core/startos/src/middleware/auth.rs @@ -27,14 +27,11 @@ use tokio::sync::Mutex; use crate::auth::{Sessions, check_password, write_shadow}; use crate::context::RpcContext; -use crate::db::model::Database; use crate::middleware::signature::{SignatureAuth, SignatureAuthContext}; use crate::prelude::*; use crate::rpc_continuations::OpenAuthedContinuations; -use crate::sign::AnyVerifyingKey; use crate::util::Invoke; use crate::util::io::{create_file_mod, read_file_to_string}; -use crate::util::iter::TransposeResultIterExt; use crate::util::serde::BASE64; use crate::util::sync::SyncMutex; @@ -66,65 +63,6 @@ pub trait AuthContext: SignatureAuthContext { } } -impl SignatureAuthContext for RpcContext { - type Database = Database; - type AdditionalMetadata = (); - type CheckPubkeyRes = (); - fn db(&self) -> &TypedPatchDb { - &self.db - } - async fn sig_context( - &self, - ) -> impl IntoIterator + Send, Error>> + Send { - let peek = self.db.peek().await; - self.account - .read() - .await - .hostnames() - .into_iter() - .map(Ok) - .chain( - peek.as_public() - .as_server_info() - .as_network() - .as_host() - .as_public_domains() - .keys() - .map(|k| k.into_iter()) - .transpose(), - ) - .chain( - peek.as_public() - .as_server_info() - .as_network() - .as_host() - .as_private_domains() - .de() - .map(|k| k.into_iter()) - .transpose(), - ) - .collect::>() - } - fn check_pubkey( - db: &Model, - pubkey: Option<&AnyVerifyingKey>, - _: Self::AdditionalMetadata, - ) -> Result { - if let Some(pubkey) = pubkey { - if db.as_private().as_auth_pubkeys().de()?.contains(pubkey) { - return Ok(()); - } - } - - Err(Error::new( - eyre!("Developer Key is not authorized"), - ErrorKind::IncorrectPassword, - )) - } - async fn post_auth_hook(&self, _: Self::CheckPubkeyRes, _: &RpcRequest) -> Result<(), Error> { - Ok(()) - } -} impl AuthContext for RpcContext { const LOCAL_AUTH_COOKIE_PATH: &str = "/run/startos/rpc.authcookie"; const LOCAL_AUTH_COOKIE_OWNERSHIP: &str = "root:startos"; @@ -439,7 +377,7 @@ impl Middleware for Auth { )); } if let Some(user_agent) = self.user_agent.as_ref().and_then(|h| h.to_str().ok()) { - request.params["__auth_userAgent"] = + request.params["__Auth_userAgent"] = Value::String(Arc::new(user_agent.to_owned())) // TODO: will this panic? } @@ -458,7 +396,7 @@ impl Middleware for Auth { { match HasValidSession::from_header(self.cookie.as_ref(), context).await? { HasValidSession(SessionType::Session(s)) if metadata.get_session => { - request.params["__auth_session"] = + request.params["__Auth_session"] = Value::String(Arc::new(s.hashed().deref().to_owned())); } _ => (), diff --git a/core/startos/src/middleware/connect_info.rs b/core/startos/src/middleware/connect_info.rs new file mode 100644 index 000000000..2f759a16d --- /dev/null +++ b/core/startos/src/middleware/connect_info.rs @@ -0,0 +1,55 @@ +use std::net::SocketAddr; + +use axum::extract::Request; +use axum::response::Response; +use imbl_value::json; +use rpc_toolkit::Middleware; +use serde::Deserialize; + +#[derive(Clone, Default)] +pub struct ConnectInfo { + peer_addr: Option, + local_addr: Option, +} +impl ConnectInfo { + pub fn new() -> Self { + Self::default() + } +} + +#[derive(Deserialize)] +pub struct Metadata { + get_connect_info: bool, +} + +impl Middleware for ConnectInfo { + type Metadata = Metadata; + async fn process_http_request( + &mut self, + _: &Context, + request: &mut Request, + ) -> Result<(), Response> { + if let Some(axum::extract::ConnectInfo((peer, local))) = request.extensions().get().cloned() + { + self.peer_addr = Some(peer); + self.local_addr = Some(local); + } + Ok(()) + } + async fn process_rpc_request( + &mut self, + _: &Context, + metadata: Self::Metadata, + request: &mut rpc_toolkit::RpcRequest, + ) -> Result<(), rpc_toolkit::RpcResponse> { + if metadata.get_connect_info { + if let Some(peer_addr) = self.peer_addr { + request.params["__ConnectInfo_peer_addr"] = json!(peer_addr); + } + if let Some(local_addr) = self.local_addr { + request.params["__ConnectInfo_local_addr"] = json!(local_addr); + } + } + Ok(()) + } +} diff --git a/core/startos/src/middleware/mod.rs b/core/startos/src/middleware/mod.rs index c1b8cb573..f71837a93 100644 --- a/core/startos/src/middleware/mod.rs +++ b/core/startos/src/middleware/mod.rs @@ -1,4 +1,5 @@ pub mod auth; +pub mod connect_info; pub mod cors; pub mod db; pub mod signature; diff --git a/core/startos/src/middleware/signature.rs b/core/startos/src/middleware/signature.rs index b07d79a20..1ad72197c 100644 --- a/core/startos/src/middleware/signature.rs +++ b/core/startos/src/middleware/signature.rs @@ -5,7 +5,8 @@ use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; use axum::body::Body; use axum::extract::Request; -use http::HeaderValue; +use http::{HeaderMap, HeaderValue}; +use reqwest::Client; use rpc_toolkit::yajrc::RpcError; use rpc_toolkit::{Context, Middleware, RpcRequest, RpcResponse}; use serde::Deserialize; @@ -13,13 +14,17 @@ use serde::de::DeserializeOwned; use tokio::sync::Mutex; use url::Url; -use crate::context::CliContext; +use crate::context::{CliContext, RpcContext}; +use crate::db::model::Database; use crate::prelude::*; use crate::sign::commitment::Commitment; use crate::sign::commitment::request::RequestCommitment; use crate::sign::{AnySignature, AnySigningKey, AnyVerifyingKey, SignatureScheme}; +use crate::util::iter::TransposeResultIterExt; use crate::util::serde::Base64; +pub const AUTH_SIG_HEADER: &str = "X-StartOS-Auth-Sig"; + pub trait SignatureAuthContext: Context { type Database: HasModel> + Send + Sync; type AdditionalMetadata: DeserializeOwned + Send; @@ -41,7 +46,82 @@ pub trait SignatureAuthContext: Context { ) -> impl Future> + Send; } -pub const AUTH_SIG_HEADER: &str = "X-StartOS-Auth-Sig"; +impl SignatureAuthContext for RpcContext { + type Database = Database; + type AdditionalMetadata = (); + type CheckPubkeyRes = (); + fn db(&self) -> &TypedPatchDb { + &self.db + } + async fn sig_context( + &self, + ) -> impl IntoIterator + Send, Error>> + Send { + let peek = self.db.peek().await; + self.account.peek(|a| { + a.hostnames() + .into_iter() + .map(Ok) + .chain( + peek.as_public() + .as_server_info() + .as_network() + .as_host() + .as_public_domains() + .keys() + .map(|k| k.into_iter()) + .transpose(), + ) + .chain( + peek.as_public() + .as_server_info() + .as_network() + .as_host() + .as_private_domains() + .de() + .map(|k| k.into_iter()) + .transpose(), + ) + .collect::>() + }) + } + fn check_pubkey( + db: &Model, + pubkey: Option<&AnyVerifyingKey>, + _: Self::AdditionalMetadata, + ) -> Result { + if let Some(pubkey) = pubkey { + if db.as_private().as_auth_pubkeys().de()?.contains(pubkey) { + return Ok(()); + } + } + + Err(Error::new( + eyre!("Developer Key is not authorized"), + ErrorKind::IncorrectPassword, + )) + } + async fn post_auth_hook(&self, _: Self::CheckPubkeyRes, _: &RpcRequest) -> Result<(), Error> { + Ok(()) + } +} + +pub trait SigningContext { + fn signing_key(&self) -> Result; +} + +impl SigningContext for CliContext { + fn signing_key(&self) -> Result { + Ok(AnySigningKey::Ed25519(self.developer_key()?.clone())) + } +} + +impl SigningContext for RpcContext { + fn signing_key(&self) -> Result { + Ok(AnySigningKey::Ed25519( + self.account.peek(|a| a.developer_key.clone()), + )) + } +} #[derive(Deserialize)] pub struct Metadata { @@ -203,7 +283,7 @@ impl Middleware for SignatureAuth { let signer = self.signer.take().transpose()?; if metadata.get_signer { if let Some(signer) = &signer { - request.params["__auth_signer"] = to_value(signer)?; + request.params["__Auth_signer"] = to_value(signer)?; } } let db = context.db().peek().await; @@ -216,10 +296,11 @@ impl Middleware for SignatureAuth { } } -pub async fn call_remote( - ctx: &CliContext, +pub async fn call_remote>( + ctx: &Ctx, url: Url, - sig_context: &str, + headers: HeaderMap, + sig_context: Option<&str>, method: &str, params: Value, ) -> Result { @@ -235,16 +316,16 @@ pub async fn call_remote( }; let body = serde_json::to_vec(&rpc_req)?; let mut req = ctx - .client + .as_ref() .request(Method::POST, url) .header(CONTENT_TYPE, "application/json") .header(ACCEPT, "application/json") - .header(CONTENT_LENGTH, body.len()); - if let Ok(key) = ctx.developer_key() { + .header(CONTENT_LENGTH, body.len()) + .headers(headers); + if let (Some(sig_ctx), Ok(key)) = (sig_context, ctx.signing_key()) { req = req.header( AUTH_SIG_HEADER, - SignatureHeader::sign(&AnySigningKey::Ed25519(key.clone()), &body, sig_context)? - .to_header(), + SignatureHeader::sign(&key, &body, sig_ctx)?.to_header(), ); } let res = req.body(body).send().await?; diff --git a/core/startos/src/net/acme.rs b/core/startos/src/net/acme.rs index f1648f3eb..2d562b0df 100644 --- a/core/startos/src/net/acme.rs +++ b/core/startos/src/net/acme.rs @@ -1,9 +1,12 @@ use std::collections::{BTreeMap, BTreeSet}; +use std::net::IpAddr; use std::str::FromStr; +use std::sync::Arc; -use async_acme::acme::Identifier; +use async_acme::acme::{ACME_TLS_ALPN_NAME, Identifier}; use clap::Parser; use clap::builder::ValueParserFactory; +use futures::StreamExt; use imbl_value::InternedString; use itertools::Itertools; use models::{ErrorData, FromStrParser}; @@ -11,14 +14,209 @@ use openssl::pkey::{PKey, Private}; use openssl::x509::X509; use rpc_toolkit::{Context, HandlerExt, ParentHandler, from_fn_async}; use serde::{Deserialize, Serialize}; +use tokio_rustls::rustls::ServerConfig; +use tokio_rustls::rustls::crypto::CryptoProvider; +use tokio_rustls::rustls::pki_types::{CertificateDer, PrivateKeyDer, PrivatePkcs8KeyDer}; +use tokio_rustls::rustls::server::ClientHello; +use tokio_rustls::rustls::sign::CertifiedKey; use ts_rs::TS; use url::Url; use crate::context::{CliContext, RpcContext}; use crate::db::model::Database; use crate::db::model::public::AcmeSettings; +use crate::db::{DbAccess, DbAccessByKey, DbAccessMut}; +use crate::net::tls::{SingleCertResolver, TlsHandler}; +use crate::net::web_server::Accept; use crate::prelude::*; use crate::util::serde::{Pem, Pkcs8Doc}; +use crate::util::sync::{SyncMutex, Watch}; + +pub type AcmeTlsAlpnCache = + Arc>>>>>; + +pub struct AcmeTlsHandler { + pub db: TypedPatchDb, + pub acme_cache: AcmeTlsAlpnCache, + pub crypto_provider: Arc, + pub get_provider: S, + pub in_progress: Watch>>, +} +impl AcmeTlsHandler +where + for<'a> M: DbAccessByKey = &'a AcmeProvider> + + DbAccessMut + + HasModel> + + Send + + Sync, + S: GetAcmeProvider + Clone, +{ + pub async fn get_cert(&self, san_info: &BTreeSet) -> Option { + let provider = self.get_provider.get_provider(san_info).await?; + let provider = provider.as_ref(); + loop { + let peek = self.db.peek().await; + let store = >::access(&peek); + if let Some(cert) = store + .as_certs() + .as_idx(&provider.0) + .and_then(|p| p.as_idx(JsonKey::new_ref(san_info))) + { + let cert = cert.de().log_err()?; + return Some( + CertifiedKey::from_der( + cert.fullchain + .into_iter() + .map(|c| Ok(CertificateDer::from(c.to_der()?))) + .collect::>() + .log_err()?, + PrivateKeyDer::from(PrivatePkcs8KeyDer::from( + cert.key.0.private_key_to_pkcs8().log_err()?, + )), + &*self.crypto_provider, + ) + .log_err()?, + ); + } + + if !self.in_progress.send_if_modified(|x| { + if !x.contains(san_info) { + x.insert(san_info.clone()); + true + } else { + false + } + }) { + self.in_progress + .clone() + .wait_for(|x| !x.contains(san_info)) + .await; + continue; + } + + let contact = >::access_by_key(&peek, &provider)? + .as_contact() + .de() + .log_err()?; + + let identifiers: Vec<_> = san_info + .iter() + .map(|d| match d.parse::() { + Ok(a) => Identifier::Ip(a), + _ => Identifier::Dns((&**d).into()), + }) + .collect::>(); + + let cache_entries = san_info + .iter() + .cloned() + .map(|d| (d, Watch::new(None))) + .collect::>(); + self.acme_cache.mutate(|c| { + c.extend(cache_entries.iter().map(|(k, v)| (k.clone(), v.clone()))); + }); + + let cert = async_acme::rustls_helper::order( + |identifier, cert| { + let domain = InternedString::from_display(&identifier); + if let Some(entry) = cache_entries.get(&domain) { + entry.send(Some(Arc::new(cert))); + } + Ok(()) + }, + provider.0.as_str(), + &identifiers, + Some(&AcmeCertCache(&self.db)), + &contact, + ) + .await + .log_err()?; + + self.acme_cache + .mutate(|c| c.retain(|c, _| !cache_entries.contains_key(c))); + + self.in_progress.send_modify(|i| i.remove(san_info)); + + return Some(cert); + } + } +} + +pub trait GetAcmeProvider { + fn get_provider<'a, 'b: 'a>( + &'b self, + san_info: &'a BTreeSet, + ) -> impl Future + Send + 'b>> + Send + 'a; +} + +impl<'a, A, M, S> TlsHandler<'a, A> for Arc> +where + A: Accept + 'a, + ::Metadata: Send + Sync, + for<'m> M: DbAccessByKey = &'m AcmeProvider> + + DbAccessMut + + HasModel> + + Send + + Sync, + S: GetAcmeProvider + Clone + Send + Sync, +{ + async fn get_config( + &'a mut self, + hello: &'a ClientHello<'a>, + _: &'a ::Metadata, + ) -> Option { + let domain = hello.server_name()?; + if hello + .alpn() + .into_iter() + .flatten() + .any(|a| a == ACME_TLS_ALPN_NAME) + { + let cert = self + .acme_cache + .peek(|c| c.get(domain).cloned()) + .ok_or_else(|| { + Error::new( + eyre!("No challenge recv available for {domain}"), + ErrorKind::OpenSsl, + ) + }) + .log_err()?; + tracing::info!("Waiting for verification cert for {domain}"); + let cert = cert + .filter(|c| futures::future::ready(c.is_some())) + .next() + .await + .flatten()?; + tracing::info!("Verification cert received for {domain}"); + let mut cfg = ServerConfig::builder_with_provider(self.crypto_provider.clone()) + .with_safe_default_protocol_versions() + .log_err()? + .with_no_client_auth() + .with_cert_resolver(Arc::new(SingleCertResolver(cert))); + + cfg.alpn_protocols = vec![ACME_TLS_ALPN_NAME.to_vec()]; + tracing::info!("performing ACME auth challenge"); + + return Some(cfg); + } + + let domains: BTreeSet = [domain.into()].into_iter().collect(); + + let crypto_provider = self.crypto_provider.clone(); + if let Some(cert) = self.get_cert(&domains).await { + return Some( + ServerConfig::builder_with_provider(crypto_provider) + .with_safe_default_protocol_versions() + .log_err()? + .with_no_client_auth() + .with_cert_resolver(Arc::new(SingleCertResolver(Arc::new(cert)))), + ); + } + + None + } +} #[derive(Debug, Default, Deserialize, Serialize, HasModel)] #[model = "Model"] @@ -32,29 +230,35 @@ impl AcmeCertStore { } } +impl DbAccess for Database { + fn access<'a>(db: &'a Model) -> &'a Model { + db.as_private().as_key_store().as_acme() + } +} +impl DbAccessMut for Database { + fn access_mut<'a>(db: &'a mut Model) -> &'a mut Model { + db.as_private_mut().as_key_store_mut().as_acme_mut() + } +} + #[derive(Debug, Deserialize, Serialize)] pub struct AcmeCert { pub key: Pem>, pub fullchain: Vec>, } -pub struct AcmeCertCache<'a>(pub &'a TypedPatchDb); +pub struct AcmeCertCache<'a, M: HasModel>(pub &'a TypedPatchDb); #[async_trait::async_trait] -impl<'a> async_acme::cache::AcmeCache for AcmeCertCache<'a> { +impl<'a, M> async_acme::cache::AcmeCache for AcmeCertCache<'a, M> +where + M: HasModel> + DbAccessMut + Send + Sync, +{ type Error = ErrorData; async fn read_account(&self, contacts: &[&str]) -> Result>, Self::Error> { let contacts = JsonKey::new(contacts.into_iter().map(|s| (*s).to_owned()).collect_vec()); - let Some(account) = self - .0 - .peek() - .await - .into_private() - .into_key_store() - .into_acme() - .into_accounts() - .into_idx(&contacts) - else { + let peek = self.0.peek().await; + let Some(account) = M::access(&peek).as_accounts().as_idx(&contacts) else { return Ok(None); }; Ok(Some(account.de()?.0.document.into_vec())) @@ -68,9 +272,7 @@ impl<'a> async_acme::cache::AcmeCache for AcmeCertCache<'a> { }; self.0 .mutate(|db| { - db.as_private_mut() - .as_key_store_mut() - .as_acme_mut() + M::access_mut(db) .as_accounts_mut() .insert(&contacts, &Pem::new(key)) }) @@ -96,16 +298,11 @@ impl<'a> async_acme::cache::AcmeCache for AcmeCertCache<'a> { let directory_url = directory_url .parse::() .with_kind(ErrorKind::ParseUrl)?; - let Some(cert) = self - .0 - .peek() - .await - .into_private() - .into_key_store() - .into_acme() - .into_certs() - .into_idx(&directory_url) - .and_then(|a| a.into_idx(&identifiers)) + let peek = self.0.peek().await; + let Some(cert) = M::access(&peek) + .as_certs() + .as_idx(&directory_url) + .and_then(|a| a.as_idx(&identifiers)) else { return Ok(None); }; @@ -160,9 +357,7 @@ impl<'a> async_acme::cache::AcmeCache for AcmeCertCache<'a> { }; self.0 .mutate(|db| { - db.as_private_mut() - .as_key_store_mut() - .as_acme_mut() + M::access_mut(db) .as_certs_mut() .upsert(&directory_url, || Ok(BTreeMap::new()))? .insert(&identifiers, &cert) @@ -235,6 +430,11 @@ impl AsRef for AcmeProvider { self.0.as_str() } } +impl AsRef for AcmeProvider { + fn as_ref(&self) -> &AcmeProvider { + self + } +} impl ValueParserFactory for AcmeProvider { type Parser = FromStrParser; fn value_parser() -> Self::Parser { diff --git a/core/startos/src/net/dns.rs b/core/startos/src/net/dns.rs index 844d41764..fac1249cd 100644 --- a/core/startos/src/net/dns.rs +++ b/core/startos/src/net/dns.rs @@ -11,36 +11,36 @@ use futures::future::BoxFuture; use futures::{FutureExt, StreamExt}; use helpers::NonDetachingJoinHandle; use hickory_client::client::Client; +use hickory_client::proto::DnsHandle; use hickory_client::proto::runtime::TokioRuntimeProvider; use hickory_client::proto::tcp::TcpClientStream; use hickory_client::proto::udp::UdpClientStream; use hickory_client::proto::xfer::DnsRequestOptions; -use hickory_client::proto::DnsHandle; +use hickory_server::ServerFuture; use hickory_server::authority::MessageResponseBuilder; use hickory_server::proto::op::{Header, ResponseCode}; use hickory_server::proto::rr::{Name, Record, RecordType}; use hickory_server::server::{Request, RequestHandler, ResponseHandler, ResponseInfo}; -use hickory_server::ServerFuture; use imbl::OrdMap; use imbl_value::InternedString; use itertools::Itertools; use models::{GatewayId, OptionExt, PackageId}; use patch_db::json_ptr::JsonPointer; use rpc_toolkit::{ - from_fn_async, from_fn_blocking, Context, HandlerArgs, HandlerExt, ParentHandler, + Context, HandlerArgs, HandlerExt, ParentHandler, from_fn_async, from_fn_blocking, }; use serde::{Deserialize, Serialize}; use tokio::net::{TcpListener, UdpSocket}; use tracing::instrument; -use crate::context::RpcContext; -use crate::db::model::public::NetworkInterfaceInfo; +use crate::context::{CliContext, RpcContext}; use crate::db::model::Database; +use crate::db::model::public::NetworkInterfaceInfo; use crate::net::gateway::NetworkInterfaceWatcher; use crate::prelude::*; use crate::util::actor::background::BackgroundJobQueue; use crate::util::io::file_string_stream; -use crate::util::serde::{display_serializable, HandlerExtSerde}; +use crate::util::serde::{HandlerExtSerde, display_serializable}; use crate::util::sync::{SyncRwLock, Watch}; pub fn dns_api() -> ParentHandler { @@ -66,7 +66,36 @@ pub fn dns_api() -> ParentHandler { "set-static", from_fn_async(set_static_dns) .no_display() - .with_about("Set static DNS servers"), + .with_about("Set static DNS servers") + .with_call_remote::(), + ) + .subcommand( + "dump-table", + from_fn_async(dump_table) + .with_display_serializable() + .with_custom_display_fn(|HandlerArgs { params, .. }, res| { + use prettytable::*; + + if let Some(format) = params.format { + return display_serializable(format, res); + } + + let mut table = Table::new(); + table.add_row(row![bc => "FQDN", "DESTINATION"]); + for (hostname, destination) in res { + if let Some(ip) = destination { + table.add_row(row![hostname, ip]); + } else { + table.add_row(row![hostname, "SELF"]); + } + } + + table.print_tty(false)?; + + Ok(()) + }) + .with_about("Dump address resolution table") + .with_call_remote::(), ) } @@ -142,6 +171,38 @@ pub async fn set_static_dns( .result } +pub async fn dump_table( + ctx: RpcContext, +) -> Result>, Error> { + Ok(ctx + .net_controller + .dns + .resolve + .upgrade() + .or_not_found("DnsController")? + .peek(|map| { + map.private_domains + .iter() + .map(|(d, _)| (d.clone(), None)) + .chain(map.services.iter().filter_map(|(svc, ip)| { + ip.iter() + .find(|(_, rc)| rc.strong_count() > 0) + .map(|(ip, _)| { + ( + svc.as_ref().map_or( + InternedString::from_static("startos"), + |svc| { + InternedString::from_display(&lazy_format!("{svc}.startos")) + }, + ), + Some(IpAddr::V4(*ip)), + ) + }) + })) + .collect() + })) +} + #[derive(Default)] struct ResolveMap { private_domains: BTreeMap>, @@ -222,9 +283,9 @@ impl DnsClient { }); loop { if let Err::<(), Error>(e) = async { - let mut static_changed = db + let mut dns_changed = db .subscribe( - "/public/serverInfo/network/dns/staticServers" + "/public/serverInfo/network/dns" .parse::() .with_kind(ErrorKind::Database)?, ) @@ -275,7 +336,7 @@ impl DnsClient { Client::new(stream, sender, None) .await .with_kind(ErrorKind::Network)?; - bg.insert(*addr, bg_thread.boxed()); + bg.insert(*addr, bg_thread.fuse().boxed()); client }; new.push((*addr, client)); @@ -286,7 +347,7 @@ impl DnsClient { client.replace(new); } futures::future::select( - static_changed.recv().boxed(), + dns_changed.recv().boxed(), futures::future::join( futures::future::join_all(bg.values_mut()), futures::future::pending::<()>(), @@ -333,10 +394,20 @@ struct Resolver { resolve: Arc>, } impl Resolver { - fn resolve(&self, name: &Name, src: IpAddr) -> Option> { + fn resolve(&self, name: &Name, mut src: IpAddr) -> Option> { if name.zone_of(&*LOCALHOST) { return Some(vec![Ipv4Addr::LOCALHOST.into(), Ipv6Addr::LOCALHOST.into()]); } + src = match src { + IpAddr::V6(v6) => { + if let Some(v4) = v6.to_ipv4_mapped() { + IpAddr::V4(v4) + } else { + IpAddr::V6(v6) + } + } + a => a, + }; self.resolve.peek(|r| { if r.private_domains .get(&*name.to_lowercase().to_utf8().trim_end_matches('.')) @@ -344,8 +415,7 @@ impl Resolver { { if let Some(res) = self.net_iface.peek(|i| { i.values() - .chain([NetworkInterfaceInfo::lxc_bridge().1]) - .flat_map(|i| i.ip_info.as_ref()) + .filter_map(|i| i.ip_info.as_ref()) .find(|i| i.subnets.iter().any(|s| s.contains(&src))) .map(|ip_info| { let mut res = ip_info.subnets.iter().collect::>(); @@ -354,6 +424,8 @@ impl Resolver { }) }) { return Some(res); + } else { + tracing::warn!("Could not determine source interface of {src}"); } } if STARTOS.zone_of(name) || EMBASSY.zone_of(name) { @@ -406,11 +478,7 @@ impl RequestHandler for Resolver { header, &ip.into_iter() .filter_map(|a| { - if let IpAddr::V4(a) = a { - Some(a) - } else { - None - } + if let IpAddr::V4(a) = a { Some(a) } else { None } }) .map(|ip| { Record::from_rdata( @@ -436,11 +504,7 @@ impl RequestHandler for Resolver { header, &ip.into_iter() .filter_map(|a| { - if let IpAddr::V6(a) = a { - Some(a) - } else { - None - } + if let IpAddr::V6(a) = a { Some(a) } else { None } }) .map(|ip| { Record::from_rdata( diff --git a/core/startos/src/net/forward.rs b/core/startos/src/net/forward.rs index 66e43e8d3..d02c8d1af 100644 --- a/core/startos/src/net/forward.rs +++ b/core/startos/src/net/forward.rs @@ -1,25 +1,26 @@ use std::collections::{BTreeMap, BTreeSet}; -use std::net::{IpAddr, SocketAddr, SocketAddrV6}; +use std::net::{IpAddr, SocketAddrV4}; use std::sync::{Arc, Weak}; +use std::time::Duration; use futures::channel::oneshot; use helpers::NonDetachingJoinHandle; use id_pool::IdPool; +use iddqd::{IdOrdItem, IdOrdMap}; use imbl::OrdMap; use models::GatewayId; -use rpc_toolkit::{from_fn_async, Context, HandlerArgs, HandlerExt, ParentHandler}; +use rpc_toolkit::{Context, HandlerArgs, HandlerExt, ParentHandler, from_fn_async}; use serde::{Deserialize, Serialize}; use tokio::process::Command; use tokio::sync::mpsc; use crate::context::{CliContext, RpcContext}; use crate::db::model::public::NetworkInterfaceInfo; -use crate::net::gateway::{DynInterfaceFilter, InterfaceFilter, SecureFilter}; -use crate::net::utils::ipv6_is_link_local; +use crate::net::gateway::{DynInterfaceFilter, InterfaceFilter}; use crate::prelude::*; -use crate::util::serde::{display_serializable, HandlerExtSerde}; -use crate::util::sync::Watch; use crate::util::Invoke; +use crate::util::serde::{HandlerExtSerde, display_serializable}; +use crate::util::sync::Watch; pub const START9_BRIDGE_IFACE: &str = "lxcbr0"; pub const FIRST_DYNAMIC_PRIVATE_PORT: u16 = 49152; @@ -60,17 +61,10 @@ pub fn forward_api() -> ParentHandler { } let mut table = Table::new(); - table.add_row(row![bc => "FROM", "TO", "FILTER / GATEWAY"]); + table.add_row(row![bc => "FROM", "TO", "FILTER"]); for (external, target) in res.0 { table.add_row(row![external, target.target, target.filter]); - for (source, gateway) in target.gateways { - table.add_row(row![ - format!("{}:{}", source, external), - target.target, - gateway - ]); - } } table.print_tty(false)?; @@ -81,162 +75,368 @@ pub fn forward_api() -> ParentHandler { ) } -struct ForwardRequest { - external: u16, - target: SocketAddr, - filter: DynInterfaceFilter, +struct ForwardMapping { + source: SocketAddrV4, + target: SocketAddrV4, rc: Weak<()>, } -#[derive(Clone)] -struct ForwardEntry { - external: u16, - target: SocketAddr, - prev_filter: DynInterfaceFilter, - forwards: BTreeMap, - rc: Weak<()>, +#[derive(Default)] +struct PortForwardState { + mappings: BTreeMap, // source -> target } -impl ForwardEntry { - fn new(external: u16, target: SocketAddr, rc: Weak<()>) -> Self { - Self { - external, - target, - prev_filter: false.into_dyn(), - forwards: BTreeMap::new(), - rc, - } - } - fn take(&mut self) -> Self { - Self { - external: self.external, - target: self.target, - prev_filter: std::mem::replace(&mut self.prev_filter, false.into_dyn()), - forwards: std::mem::take(&mut self.forwards), - rc: self.rc.clone(), - } - } - - async fn destroy(mut self) -> Result<(), Error> { - while let Some((source, interface)) = self.forwards.pop_first() { - unforward(interface.as_str(), source, self.target).await?; - } - Ok(()) - } - - async fn update( +impl PortForwardState { + async fn add_forward( &mut self, - ip_info: &OrdMap, - filter: Option, - ) -> Result<(), Error> { - if self.rc.strong_count() == 0 { - return self.take().destroy().await; - } - let filter_ref = filter.as_ref().unwrap_or(&self.prev_filter); - let mut keep = BTreeSet::::new(); - for (iface, info) in ip_info - .iter() - // .chain([NetworkInterfaceInfo::loopback()]) - .filter(|(id, info)| filter_ref.filter(*id, *info)) - { - if let Some(ip_info) = &info.ip_info { - for ipnet in &ip_info.subnets { - let addr = match ipnet.addr() { - IpAddr::V6(ip6) => SocketAddrV6::new( - ip6, - self.external, - 0, - if ipv6_is_link_local(ip6) { - ip_info.scope_id - } else { - 0 - }, - ) - .into(), - ip => SocketAddr::new(ip, self.external), - }; - keep.insert(addr); - if !self.forwards.contains_key(&addr) { - forward(iface.as_str(), addr, self.target).await?; - self.forwards.insert(addr, iface.clone()); - } + source: SocketAddrV4, + target: SocketAddrV4, + ) -> Result, Error> { + if let Some(existing) = self.mappings.get_mut(&source) { + if existing.target == target { + if let Some(existing_rc) = existing.rc.upgrade() { + return Ok(existing_rc); + } else { + let rc = Arc::new(()); + existing.rc = Arc::downgrade(&rc); + return Ok(rc); + } + } else { + // Different target, need to remove old and add new + if let Some(mapping) = self.mappings.remove(&source) { + unforward(mapping.source, mapping.target).await?; } } } - let rm = self - .forwards - .keys() - .copied() - .filter(|a| !keep.contains(a)) - .collect::>(); - for rm in rm { - if let Some((source, interface)) = self.forwards.remove_entry(&rm) { - unforward(interface.as_str(), source, self.target).await?; + + let rc = Arc::new(()); + forward(source, target).await?; + self.mappings.insert( + source, + ForwardMapping { + source, + target, + rc: Arc::downgrade(&rc), + }, + ); + + Ok(rc) + } + + async fn gc(&mut self) -> Result<(), Error> { + let to_remove: Vec = self + .mappings + .iter() + .filter(|(_, mapping)| mapping.rc.strong_count() == 0) + .map(|(source, _)| *source) + .collect(); + + for source in to_remove { + if let Some(mapping) = self.mappings.remove(&source) { + unforward(mapping.source, mapping.target).await?; } } - if let Some(filter) = filter { - self.prev_filter = filter; - } Ok(()) } - async fn update_request( - &mut self, - ForwardRequest { - external, - target, - filter, - rc, - }: ForwardRequest, - ip_info: &OrdMap, - ) -> Result<(), Error> { - if external != self.external || target != self.target { - self.take().destroy().await?; - *self = Self::new(external, target, rc); - self.update(ip_info, Some(filter)).await?; - } else { - self.rc = rc; - self.update(ip_info, Some(filter).filter(|f| f != &self.prev_filter)) - .await?; - } - Ok(()) + fn dump(&self) -> BTreeMap { + self.mappings + .iter() + .filter(|(_, mapping)| mapping.rc.strong_count() > 0) + .map(|(source, mapping)| (*source, mapping.target)) + .collect() } } -impl Drop for ForwardEntry { + +impl Drop for PortForwardState { fn drop(&mut self) { - if !self.forwards.is_empty() { - let take = self.take(); + if !self.mappings.is_empty() { + let mappings = std::mem::take(&mut self.mappings); tokio::spawn(async move { - take.destroy().await.log_err(); + for (_, mapping) in mappings { + unforward(mapping.source, mapping.target).await.log_err(); + } }); } } } -#[derive(Default, Clone)] -struct ForwardState { - state: BTreeMap, +enum PortForwardCommand { + AddForward { + source: SocketAddrV4, + target: SocketAddrV4, + respond: oneshot::Sender, Error>>, + }, + Gc { + respond: oneshot::Sender>, + }, + Dump { + respond: oneshot::Sender>, + }, } -impl ForwardState { + +pub struct PortForwardController { + req: mpsc::UnboundedSender, + _thread: NonDetachingJoinHandle<()>, +} + +impl PortForwardController { + pub fn new() -> Self { + let (req_send, mut req_recv) = mpsc::unbounded_channel::(); + let thread = NonDetachingJoinHandle::from(tokio::spawn(async move { + while let Err(e) = async { + Command::new("sysctl") + .arg("-w") + .arg("net.ipv4.ip_forward=1") + .invoke(ErrorKind::Network) + .await?; + if Command::new("iptables") + .arg("-t") + .arg("nat") + .arg("-C") + .arg("POSTROUTING") + .arg("-j") + .arg("MASQUERADE") + .invoke(ErrorKind::Network) + .await + .is_err() + { + Command::new("iptables") + .arg("-t") + .arg("nat") + .arg("-A") + .arg("POSTROUTING") + .arg("-j") + .arg("MASQUERADE") + .invoke(ErrorKind::Network) + .await?; + } + Ok::<_, Error>(()) + } + .await + { + tracing::error!("error initializing PortForwardController: {e:#}"); + tracing::debug!("{e:?}"); + tokio::time::sleep(Duration::from_secs(5)).await; + } + let mut state = PortForwardState::default(); + while let Some(cmd) = req_recv.recv().await { + match cmd { + PortForwardCommand::AddForward { + source, + target, + respond, + } => { + let result = state.add_forward(source, target).await; + respond.send(result).ok(); + } + PortForwardCommand::Gc { respond } => { + let result = state.gc().await; + respond.send(result).ok(); + } + PortForwardCommand::Dump { respond } => { + respond.send(state.dump()).ok(); + } + } + } + })); + + Self { + req: req_send, + _thread: thread, + } + } + + pub async fn add_forward( + &self, + source: SocketAddrV4, + target: SocketAddrV4, + ) -> Result, Error> { + let (send, recv) = oneshot::channel(); + self.req + .send(PortForwardCommand::AddForward { + source, + target, + respond: send, + }) + .map_err(err_has_exited)?; + + recv.await.map_err(err_has_exited)? + } + + pub async fn gc(&self) -> Result<(), Error> { + let (send, recv) = oneshot::channel(); + self.req + .send(PortForwardCommand::Gc { respond: send }) + .map_err(err_has_exited)?; + + recv.await.map_err(err_has_exited)? + } + + pub async fn dump(&self) -> Result, Error> { + let (send, recv) = oneshot::channel(); + self.req + .send(PortForwardCommand::Dump { respond: send }) + .map_err(err_has_exited)?; + + recv.await.map_err(err_has_exited) + } +} + +struct InterfaceForwardRequest { + external: u16, + target: SocketAddrV4, + filter: DynInterfaceFilter, + rc: Arc<()>, +} + +#[derive(Clone)] +struct InterfaceForwardEntry { + external: u16, + filter: BTreeMap)>, + // Maps source SocketAddr -> strong reference for the forward created in PortForwardController + forwards: BTreeMap>, +} + +impl IdOrdItem for InterfaceForwardEntry { + type Key<'a> = u16; + fn key(&self) -> Self::Key<'_> { + self.external + } + + iddqd::id_upcast!(); +} + +impl InterfaceForwardEntry { + fn new(external: u16) -> Self { + Self { + external, + filter: BTreeMap::new(), + forwards: BTreeMap::new(), + } + } + + async fn update( + &mut self, + ip_info: &OrdMap, + port_forward: &PortForwardController, + ) -> Result<(), Error> { + let mut keep = BTreeSet::::new(); + + for (iface, info) in ip_info.iter() { + if let Some(target) = self + .filter + .iter() + .filter(|(_, (_, rc))| rc.strong_count() > 0) + .find(|(filter, _)| filter.filter(iface, info)) + .map(|(_, (target, _))| *target) + { + if let Some(ip_info) = &info.ip_info { + for addr in ip_info.subnets.iter().filter_map(|net| { + if let IpAddr::V4(ip) = net.addr() { + Some(SocketAddrV4::new(ip, self.external)) + } else { + None + } + }) { + keep.insert(addr); + if !self.forwards.contains_key(&addr) { + let rc = port_forward.add_forward(addr, target).await?; + self.forwards.insert(addr, rc); + } + } + } + } + } + + // Remove forwards that should no longer exist (drops the strong references) + self.forwards.retain(|addr, _| keep.contains(addr)); + + Ok(()) + } + + async fn update_request( + &mut self, + InterfaceForwardRequest { + external, + target, + filter, + mut rc, + }: InterfaceForwardRequest, + ip_info: &OrdMap, + port_forward: &PortForwardController, + ) -> Result, Error> { + if external != self.external { + return Err(Error::new( + eyre!("Mismatched external port in InterfaceForwardEntry"), + ErrorKind::InvalidRequest, + )); + } + + let entry = self + .filter + .entry(filter) + .or_insert_with(|| (target, Arc::downgrade(&rc))); + if entry.0 != target { + entry.0 = target; + entry.1 = Arc::downgrade(&rc); + } + if let Some(existing) = entry.1.upgrade() { + rc = existing; + } else { + entry.1 = Arc::downgrade(&rc); + } + + self.update(ip_info, port_forward).await?; + + Ok(rc) + } + + async fn gc( + &mut self, + ip_info: &OrdMap, + port_forward: &PortForwardController, + ) -> Result<(), Error> { + self.filter.retain(|_, (_, rc)| rc.strong_count() > 0); + + self.update(ip_info, port_forward).await + } +} + +struct InterfaceForwardState { + port_forward: PortForwardController, + state: IdOrdMap, +} + +impl InterfaceForwardState { + fn new(port_forward: PortForwardController) -> Self { + Self { + port_forward, + state: IdOrdMap::new(), + } + } +} + +impl InterfaceForwardState { async fn handle_request( &mut self, - request: ForwardRequest, + request: InterfaceForwardRequest, ip_info: &OrdMap, - ) -> Result<(), Error> { + ) -> Result, Error> { self.state .entry(request.external) - .or_insert_with(|| ForwardEntry::new(request.external, request.target, Weak::new())) - .update_request(request, ip_info) + .or_insert_with(|| InterfaceForwardEntry::new(request.external)) + .update_request(request, ip_info, &self.port_forward) .await } + async fn sync( &mut self, ip_info: &OrdMap, ) -> Result<(), Error> { - for entry in self.state.values_mut() { - entry.update(ip_info, None).await?; + for mut entry in self.state.iter_mut() { + entry.gc(ip_info, &self.port_forward).await?; } - self.state.retain(|_, fwd| fwd.rc.strong_count() > 0); Ok(()) } } @@ -250,65 +450,85 @@ fn err_has_exited(_: T) -> Error { #[derive(Debug, Clone, Deserialize, Serialize)] pub struct ForwardTable(pub BTreeMap); + #[derive(Debug, Clone, Deserialize, Serialize)] pub struct ForwardTarget { - pub target: SocketAddr, + pub target: SocketAddrV4, pub filter: String, - pub gateways: BTreeMap, } -impl From<&ForwardState> for ForwardTable { - fn from(value: &ForwardState) -> Self { + +impl From<&InterfaceForwardState> for ForwardTable { + fn from(value: &InterfaceForwardState) -> Self { Self( value .state .iter() - .map(|(external, entry)| { - ( - *external, - ForwardTarget { - target: entry.target, - filter: format!("{:?}", entry.prev_filter), - gateways: entry.forwards.clone(), - }, - ) + .flat_map(|entry| { + entry + .filter + .iter() + .filter(|(_, (_, rc))| rc.strong_count() > 0) + .map(|(filter, (target, _))| { + ( + entry.external, + ForwardTarget { + target: *target, + filter: format!("{:?}", filter), + }, + ) + }) }) .collect(), ) } } -enum ForwardCommand { - Forward(ForwardRequest, oneshot::Sender>), +enum InterfaceForwardCommand { + Forward( + InterfaceForwardRequest, + oneshot::Sender, Error>>, + ), Sync(oneshot::Sender>), DumpTable(oneshot::Sender), } #[test] fn test() { + use crate::net::gateway::SecureFilter; + assert_ne!( false.into_dyn(), SecureFilter { secure: false }.into_dyn().into_dyn() ); } -pub struct PortForwardController { - req: mpsc::UnboundedSender, +pub struct InterfacePortForwardController { + req: mpsc::UnboundedSender, _thread: NonDetachingJoinHandle<()>, } -impl PortForwardController { + +impl InterfacePortForwardController { pub fn new(mut ip_info: Watch>) -> Self { - let (req_send, mut req_recv) = mpsc::unbounded_channel::(); + let port_forward = PortForwardController::new(); + + let (req_send, mut req_recv) = mpsc::unbounded_channel::(); let thread = NonDetachingJoinHandle::from(tokio::spawn(async move { - let mut state = ForwardState::default(); + let mut state = InterfaceForwardState::new(port_forward); let mut interfaces = ip_info.read_and_mark_seen(); loop { tokio::select! { msg = req_recv.recv() => { if let Some(cmd) = msg { match cmd { - ForwardCommand::Forward(req, re) => re.send(state.handle_request(req, &interfaces).await).ok(), - ForwardCommand::Sync(re) => re.send(state.sync(&interfaces).await).ok(), - ForwardCommand::DumpTable(re) => re.send((&state).into()).ok(), + InterfaceForwardCommand::Forward(req, re) => { + re.send(state.handle_request(req, &interfaces).await).ok() + } + InterfaceForwardCommand::Sync(re) => { + re.send(state.sync(&interfaces).await).ok() + } + InterfaceForwardCommand::DumpTable(re) => { + re.send((&state).into()).ok() + } }; } else { break; @@ -317,61 +537,61 @@ impl PortForwardController { _ = ip_info.changed() => { interfaces = ip_info.read(); state.sync(&interfaces).await.log_err(); + state.port_forward.gc().await.log_err(); } } } })); + Self { req: req_send, _thread: thread, } } + pub async fn add( &self, external: u16, filter: DynInterfaceFilter, - target: SocketAddr, + target: SocketAddrV4, ) -> Result, Error> { let rc = Arc::new(()); let (send, recv) = oneshot::channel(); self.req - .send(ForwardCommand::Forward( - ForwardRequest { + .send(InterfaceForwardCommand::Forward( + InterfaceForwardRequest { external, target, filter, - rc: Arc::downgrade(&rc), + rc, }, send, )) .map_err(err_has_exited)?; - recv.await.map_err(err_has_exited)?.map(|_| rc) + recv.await.map_err(err_has_exited)? } + pub async fn gc(&self) -> Result<(), Error> { let (send, recv) = oneshot::channel(); self.req - .send(ForwardCommand::Sync(send)) + .send(InterfaceForwardCommand::Sync(send)) .map_err(err_has_exited)?; recv.await.map_err(err_has_exited)? } + pub async fn dump_table(&self) -> Result { let (req, res) = oneshot::channel(); self.req - .send(ForwardCommand::DumpTable(req)) + .send(InterfaceForwardCommand::DumpTable(req)) .map_err(err_has_exited)?; res.await.map_err(err_has_exited) } } -async fn forward(interface: &str, source: SocketAddr, target: SocketAddr) -> Result<(), Error> { - if source.is_ipv6() { - return Ok(()); // TODO: socat? ip6tables? - } +async fn forward(source: SocketAddrV4, target: SocketAddrV4) -> Result<(), Error> { Command::new("/usr/lib/startos/scripts/forward-port") - .env("iiface", interface) - .env("oiface", START9_BRIDGE_IFACE) .env("sip", source.ip().to_string()) .env("dip", target.ip().to_string()) .env("sport", source.port().to_string()) @@ -381,14 +601,9 @@ async fn forward(interface: &str, source: SocketAddr, target: SocketAddr) -> Res Ok(()) } -async fn unforward(interface: &str, source: SocketAddr, target: SocketAddr) -> Result<(), Error> { - if source.is_ipv6() { - return Ok(()); // TODO: socat? ip6tables? - } +async fn unforward(source: SocketAddrV4, target: SocketAddrV4) -> Result<(), Error> { Command::new("/usr/lib/startos/scripts/forward-port") .env("UNDO", "1") - .env("iiface", interface) - .env("oiface", START9_BRIDGE_IFACE) .env("sip", source.ip().to_string()) .env("dip", target.ip().to_string()) .env("sport", source.port().to_string()) diff --git a/core/startos/src/net/gateway.rs b/core/startos/src/net/gateway.rs index f67a3700f..2db91cd70 100644 --- a/core/startos/src/net/gateway.rs +++ b/core/startos/src/net/gateway.rs @@ -3,10 +3,11 @@ use std::collections::{BTreeMap, BTreeSet, HashMap}; use std::future::Future; use std::net::{IpAddr, Ipv4Addr, SocketAddr, SocketAddrV6}; use std::sync::{Arc, Weak}; -use std::task::Poll; +use std::task::{Poll, ready}; use std::time::Duration; use clap::Parser; +use futures::future::Either; use futures::{FutureExt, Stream, StreamExt, TryStreamExt}; use helpers::NonDetachingJoinHandle; use imbl::{OrdMap, OrdSet}; @@ -16,33 +17,34 @@ use itertools::Itertools; use models::GatewayId; use nix::net::if_::if_nametoindex; use patch_db::json_ptr::JsonPointer; -use rpc_toolkit::{from_fn_async, Context, HandlerArgs, HandlerExt, ParentHandler}; +use rpc_toolkit::{Context, HandlerArgs, HandlerExt, ParentHandler, from_fn_async}; use serde::{Deserialize, Serialize}; use tokio::io::{AsyncBufReadExt, BufReader}; -use tokio::net::{TcpListener, TcpStream}; +use tokio::net::TcpListener; use tokio::process::Command; use tokio::sync::oneshot; use ts_rs::TS; +use visit_rs::{Visit, VisitFields}; use zbus::proxy::{PropertyChanged, PropertyStream, SignalStream}; use zbus::zvariant::{ DeserializeDict, Dict, OwnedObjectPath, OwnedValue, Type as ZType, Value as ZValue, }; -use zbus::{proxy, Connection}; +use zbus::{Connection, proxy}; use crate::context::{CliContext, RpcContext}; -use crate::db::model::public::{IpInfo, NetworkInterfaceInfo, NetworkInterfaceType}; use crate::db::model::Database; +use crate::db::model::public::{IpInfo, NetworkInterfaceInfo, NetworkInterfaceType}; use crate::net::forward::START9_BRIDGE_IFACE; use crate::net::gateway::device::DeviceProxy; use crate::net::utils::ipv6_is_link_local; -use crate::net::web_server::Accept; +use crate::net::web_server::{Accept, AcceptStream, Acceptor, MetadataVisitor}; use crate::prelude::*; +use crate::util::Invoke; use crate::util::collections::OrdMapIterMut; use crate::util::future::Until; use crate::util::io::open_file; -use crate::util::serde::{display_serializable, HandlerExtSerde}; +use crate::util::serde::{HandlerExtSerde, display_serializable}; use crate::util::sync::{SyncMutex, Watch}; -use crate::util::Invoke; pub fn gateway_api() -> ParentHandler { ParentHandler::new() @@ -244,6 +246,8 @@ mod active_connection { default_service = "org.freedesktop.NetworkManager" )] trait ConnectionSettings { + fn delete(&self) -> Result<(), Error>; + fn get_settings(&self) -> Result>, Error>; fn update2( @@ -583,15 +587,12 @@ async fn watch_ip( loop { until .run(async { - let external = active_connection_proxy.state_flags().await? & 0x80 != 0; - if external { - return Ok(()); - } - let device_type = match device_proxy.device_type().await? { 1 => Some(NetworkInterfaceType::Ethernet), 2 => Some(NetworkInterfaceType::Wireless), + 13 => Some(NetworkInterfaceType::Bridge), 29 => Some(NetworkInterfaceType::Wireguard), + 32 => Some(NetworkInterfaceType::Loopback), _ => None, }; @@ -671,7 +672,14 @@ async fn watch_ip( .into_iter() .map(IpNet::try_from) .try_collect()?; - let wan_ip = if !subnets.is_empty() { + let wan_ip = if !subnets.is_empty() + && !matches!( + device_type, + Some( + NetworkInterfaceType::Bridge + | NetworkInterfaceType::Loopback + ) + ) { match get_wan_ipv4(iface.as_str()).await { Ok(a) => a, Err(e) => { @@ -711,6 +719,7 @@ async fn watch_ip( ) }); ip_info.wan_ip = ip_info.wan_ip.or(prev_wan_ip); + let ip_info = Arc::new(ip_info); m.insert( iface.clone(), NetworkInterfaceInfo { @@ -785,13 +794,7 @@ impl NetworkInterfaceWatcher { watch_activated: impl IntoIterator, ) -> Self { let ip_info = Watch::new(OrdMap::new()); - let activated = Watch::new( - watch_activated - .into_iter() - .chain([NetworkInterfaceInfo::lxc_bridge().0.clone()]) - .map(|k| (k, false)) - .collect(), - ); + let activated = Watch::new(watch_activated.into_iter().map(|k| (k, false)).collect()); Self { activated: activated.clone(), ip_info: ip_info.clone(), @@ -831,7 +834,7 @@ impl NetworkInterfaceWatcher { self.ip_info.read() } - pub fn bind(&self, port: u16) -> Result { + pub fn bind(&self, bind: B, port: u16) -> Result, Error> { let arc = Arc::new(()); self.listeners.mutate(|l| { if l.get(&port).filter(|w| w.strong_count() > 0).is_some() { @@ -844,22 +847,20 @@ impl NetworkInterfaceWatcher { Ok(()) })?; let ip_info = self.ip_info.clone_unseen(); - let activated = self.activated.clone_unseen(); Ok(NetworkInterfaceListener { _arc: arc, ip_info, - activated, - listeners: ListenerMap::new(port), + listeners: ListenerMap::new(bind, port), }) } - pub fn upgrade_listener( + pub fn upgrade_listener( &self, SelfContainedNetworkInterfaceListener { mut listener, .. - }: SelfContainedNetworkInterfaceListener, - ) -> Result { + }: SelfContainedNetworkInterfaceListener, + ) -> Result, Error> { let port = listener.listeners.port; let arc = &listener._arc; self.listeners.mutate(|l| { @@ -1095,7 +1096,7 @@ impl NetworkInterfaceController { .ip_info .peek(|ifaces| ifaces.get(interface).map(|i| i.ip_info.is_some())) else { - return Ok(()); + return self.forget(interface).await; }; if has_ip_info { @@ -1115,7 +1116,21 @@ impl NetworkInterfaceController { let device_proxy = DeviceProxy::new(&connection, device).await?; - device_proxy.delete().await?; + let ac = device_proxy.active_connection().await?; + + if &*ac == "/" { + return Err(Error::new( + eyre!("Cannot delete device without active connection"), + ErrorKind::InvalidRequest, + )); + } + + let ac_proxy = active_connection::ActiveConnectionProxy::new(&connection, ac).await?; + + let settings = + ConnectionSettingsProxy::new(&connection, ac_proxy.connection().await?).await?; + + settings.delete().await?; ip_info .wait_for(|ifaces| ifaces.get(interface).map_or(true, |i| i.ip_info.is_none())) @@ -1158,45 +1173,6 @@ impl NetworkInterfaceController { } } -struct ListenerMap { - prev_filter: DynInterfaceFilter, - port: u16, - listeners: BTreeMap)>, -} -impl ListenerMap { - fn from_listener(listener: impl IntoIterator) -> Result { - let mut port = 0; - let mut listeners = BTreeMap::)>::new(); - for listener in listener { - let mut local = listener.local_addr().with_kind(ErrorKind::Network)?; - if let SocketAddr::V6(l) = &mut local { - if ipv6_is_link_local(*l.ip()) && l.scope_id() == 0 { - continue; // TODO determine scope id - } - } - if port != 0 && port != local.port() { - return Err(Error::new( - eyre!("Provided listeners are bound to different ports"), - ErrorKind::InvalidRequest, - )); - } - port = local.port(); - listeners.insert(local, (listener, None)); - } - if port == 0 { - return Err(Error::new( - eyre!("Listener array cannot be empty"), - ErrorKind::InvalidRequest, - )); - } - Ok(Self { - prev_filter: false.into_dyn(), - port, - listeners, - }) - } -} - pub trait InterfaceFilter: Any + Clone + std::fmt::Debug + Eq + Ord + Send + Sync { fn filter(&self, id: &GatewayId, info: &NetworkInterfaceInfo) -> bool; fn eq(&self, other: &dyn Any) -> bool { @@ -1224,6 +1200,14 @@ impl InterfaceFilter for bool { } } +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct TypeFilter(pub NetworkInterfaceType); +impl InterfaceFilter for TypeFilter { + fn filter(&self, _: &GatewayId, info: &NetworkInterfaceInfo) -> bool { + info.ip_info.as_ref().and_then(|i| i.device_type) == Some(self.0) + } +} + #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] pub struct IdFilter(pub GatewayId); impl InterfaceFilter for IdFilter { @@ -1355,10 +1339,17 @@ impl Ord for DynInterfaceFilter { } } -impl ListenerMap { - fn new(port: u16) -> Self { +struct ListenerMap { + prev_filter: DynInterfaceFilter, + bind: B, + port: u16, + listeners: BTreeMap, +} +impl ListenerMap { + fn new(bind: B, port: u16) -> Self { Self { prev_filter: false.into_dyn(), + bind, port, listeners: BTreeMap::new(), } @@ -1368,14 +1359,11 @@ impl ListenerMap { fn update( &mut self, ip_info: &OrdMap, - lxc_bridge: bool, filter: &impl InterfaceFilter, ) -> Result<(), Error> { let mut keep = BTreeSet::::new(); for (_, info) in ip_info .iter() - .chain([NetworkInterfaceInfo::loopback()]) - .chain(Some(NetworkInterfaceInfo::lxc_bridge()).filter(|_| lxc_bridge)) .filter(|(id, info)| filter.filter(*id, *info)) { if let Some(ip_info) = &info.ip_info { @@ -1395,24 +1383,9 @@ impl ListenerMap { ip => SocketAddr::new(ip, self.port), }; keep.insert(addr); - if let Some((_, wan_ip)) = self.listeners.get_mut(&addr) { - *wan_ip = info.ip_info.as_ref().and_then(|i| i.wan_ip); - continue; + if !self.listeners.contains_key(&addr) { + self.listeners.insert(addr, self.bind.bind(addr)?); } - self.listeners.insert( - addr, - ( - TcpListener::from_std( - mio::net::TcpListener::bind(addr) - .with_ctx(|_| { - (ErrorKind::Network, lazy_format!("binding to {addr:?}")) - })? - .into(), - ) - .with_kind(ErrorKind::Network)?, - info.ip_info.as_ref().and_then(|i| i.wan_ip), - ), - ); } } } @@ -1420,24 +1393,13 @@ impl ListenerMap { self.prev_filter = filter.clone().into_dyn(); Ok(()) } - fn poll_accept(&self, cx: &mut std::task::Context<'_>) -> Poll> { - for (bind_addr, (listener, wan_ip)) in self.listeners.iter() { - if let Poll::Ready((stream, addr)) = listener.poll_accept(cx)? { - if let Err(e) = socket2::SockRef::from(&stream).set_tcp_keepalive( - &socket2::TcpKeepalive::new() - .with_time(Duration::from_secs(900)) - .with_interval(Duration::from_secs(60)) - .with_retries(5), - ) { - tracing::error!("Failed to set tcp keepalive: {e}"); - tracing::debug!("{e:?}"); - } - return Poll::Ready(Ok(Accepted { - stream, - peer: addr, - wan_ip: *wan_ip, - bind: *bind_addr, - })); + fn poll_accept( + &mut self, + cx: &mut std::task::Context<'_>, + ) -> Poll::Metadata, AcceptStream), Error>> { + for (addr, listener) in self.listeners.iter_mut() { + if let Poll::Ready((metadata, stream)) = listener.poll_accept(cx)? { + return Poll::Ready(Ok((*addr, metadata, stream))); } } Poll::Pending @@ -1448,65 +1410,102 @@ pub fn lookup_info_by_addr( ip_info: &OrdMap, addr: SocketAddr, ) -> Option<(&GatewayId, &NetworkInterfaceInfo)> { - ip_info - .iter() - .chain([ - NetworkInterfaceInfo::loopback(), - NetworkInterfaceInfo::lxc_bridge(), - ]) - .find(|(_, i)| { - i.ip_info - .as_ref() - .map_or(false, |i| i.subnets.iter().any(|i| i.addr() == addr.ip())) - }) + ip_info.iter().find(|(_, i)| { + i.ip_info + .as_ref() + .map_or(false, |i| i.subnets.iter().any(|i| i.addr() == addr.ip())) + }) } -pub struct NetworkInterfaceListener { +pub trait Bind { + type Accept: Accept; + fn bind(&mut self, addr: SocketAddr) -> Result; +} + +#[derive(Clone, Copy, Default)] +pub struct BindTcp; +impl Bind for BindTcp { + type Accept = TcpListener; + fn bind(&mut self, addr: SocketAddr) -> Result { + TcpListener::from_std( + mio::net::TcpListener::bind(addr) + .with_kind(ErrorKind::Network)? + .into(), + ) + .with_kind(ErrorKind::Network) + } +} + +pub trait FromGatewayInfo { + fn from_gateway_info(id: &GatewayId, info: &NetworkInterfaceInfo) -> Self; +} +#[derive(Clone, Debug)] +pub struct GatewayInfo { + pub id: GatewayId, + pub info: NetworkInterfaceInfo, +} +impl Visit for GatewayInfo { + fn visit(&self, visitor: &mut V) -> ::Result { + visitor.visit(self) + } +} +impl FromGatewayInfo for GatewayInfo { + fn from_gateway_info(id: &GatewayId, info: &NetworkInterfaceInfo) -> Self { + Self { + id: id.clone(), + info: info.clone(), + } + } +} + +pub struct NetworkInterfaceListener { pub ip_info: Watch>, - activated: Watch>, - listeners: ListenerMap, + listeners: ListenerMap, _arc: Arc<()>, } -impl NetworkInterfaceListener { - pub fn port(&self) -> u16 { - self.listeners.port - } - - #[cfg_attr(feature = "unstable", inline(never))] - pub fn poll_accept( - &mut self, - cx: &mut std::task::Context<'_>, - filter: &impl InterfaceFilter, - ) -> Poll> { - while self.ip_info.poll_changed(cx).is_ready() - || self.activated.poll_changed(cx).is_ready() - || !DynInterfaceFilterT::eq(&self.listeners.prev_filter, filter.as_any()) - { - let lxc_bridge = self.activated.peek(|a| { - a.get(NetworkInterfaceInfo::lxc_bridge().0) - .copied() - .unwrap_or_default() - }); - self.ip_info - .peek_and_mark_seen(|ip_info| self.listeners.update(ip_info, lxc_bridge, filter))?; - } - self.listeners.poll_accept(cx) - } - +impl NetworkInterfaceListener { pub(super) fn new( mut ip_info: Watch>, - activated: Watch>, + bind: B, port: u16, ) -> Self { ip_info.mark_unseen(); Self { ip_info, - activated, - listeners: ListenerMap::new(port), + listeners: ListenerMap::new(bind, port), _arc: Arc::new(()), } } + pub fn port(&self) -> u16 { + self.listeners.port + } + + #[cfg_attr(feature = "unstable", inline(never))] + pub fn poll_accept( + &mut self, + cx: &mut std::task::Context<'_>, + filter: &impl InterfaceFilter, + ) -> Poll::Metadata, AcceptStream), Error>> { + while self.ip_info.poll_changed(cx).is_ready() + || !DynInterfaceFilterT::eq(&self.listeners.prev_filter, filter.as_any()) + { + self.ip_info + .peek_and_mark_seen(|ip_info| self.listeners.update(ip_info, filter))?; + } + let (addr, inner, stream) = ready!(self.listeners.poll_accept(cx)?); + Poll::Ready(Ok(( + self.ip_info + .peek(|ip_info| { + lookup_info_by_addr(ip_info, addr) + .map(|(id, info)| M::from_gateway_info(id, info)) + }) + .or_not_found(lazy_format!("gateway for {addr}"))?, + inner, + stream, + ))) + } + pub fn change_ip_info_source( &mut self, mut ip_info: Watch>, @@ -1515,7 +1514,10 @@ impl NetworkInterfaceListener { self.ip_info = ip_info; } - pub async fn accept(&mut self, filter: &impl InterfaceFilter) -> Result { + pub async fn accept( + &mut self, + filter: &impl InterfaceFilter, + ) -> Result<(M, ::Metadata, AcceptStream), Error> { futures::future::poll_fn(|cx| self.poll_accept(cx, filter)).await } @@ -1531,37 +1533,84 @@ impl NetworkInterfaceListener { } } -pub struct Accepted { - pub stream: TcpStream, - pub peer: SocketAddr, - pub wan_ip: Option, - pub bind: SocketAddr, +#[derive(VisitFields)] +pub struct NetworkInterfaceListenerAcceptMetadata { + pub inner: ::Metadata, + pub info: GatewayInfo, } - -pub struct SelfContainedNetworkInterfaceListener { - _watch_thread: NonDetachingJoinHandle<()>, - listener: NetworkInterfaceListener, -} -impl SelfContainedNetworkInterfaceListener { - pub fn bind(port: u16) -> Self { - let ip_info = Watch::new(OrdMap::new()); - let activated = Watch::new( - [(NetworkInterfaceInfo::lxc_bridge().0.clone(), false)] - .into_iter() - .collect(), - ); - let _watch_thread = tokio::spawn(watcher(ip_info.clone(), activated.clone())).into(); +impl Clone for NetworkInterfaceListenerAcceptMetadata +where + ::Metadata: Clone, +{ + fn clone(&self) -> Self { Self { - _watch_thread, - listener: NetworkInterfaceListener::new(ip_info, activated, port), + inner: self.inner.clone(), + info: self.info.clone(), } } } -impl Accept for SelfContainedNetworkInterfaceListener { +impl Visit for NetworkInterfaceListenerAcceptMetadata +where + B: Bind, + ::Metadata: Visit + Clone + Send + Sync + 'static, + V: MetadataVisitor, +{ + fn visit(&self, visitor: &mut V) -> V::Result { + self.visit_fields(visitor).collect() + } +} + +impl Accept for NetworkInterfaceListener { + type Metadata = NetworkInterfaceListenerAcceptMetadata; fn poll_accept( &mut self, cx: &mut std::task::Context<'_>, - ) -> std::task::Poll> { + ) -> Poll> { + NetworkInterfaceListener::poll_accept(self, cx, &true).map(|res| { + res.map(|(info, inner, stream)| { + ( + NetworkInterfaceListenerAcceptMetadata { inner, info }, + stream, + ) + }) + }) + } +} + +pub struct SelfContainedNetworkInterfaceListener { + _watch_thread: NonDetachingJoinHandle<()>, + listener: NetworkInterfaceListener, +} +impl SelfContainedNetworkInterfaceListener { + pub fn bind(bind: B, port: u16) -> Self { + let ip_info = Watch::new(OrdMap::new()); + let _watch_thread = + tokio::spawn(watcher(ip_info.clone(), Watch::new(BTreeMap::new()))).into(); + Self { + _watch_thread, + listener: NetworkInterfaceListener::new(ip_info, bind, port), + } + } +} +impl Accept for SelfContainedNetworkInterfaceListener { + type Metadata = as Accept>::Metadata; + fn poll_accept( + &mut self, + cx: &mut std::task::Context<'_>, + ) -> std::task::Poll> { Accept::poll_accept(&mut self.listener, cx) } } + +pub type UpgradableListener = + Option, NetworkInterfaceListener>>; + +impl Acceptor> +where + B: Bind + Send + Sync + 'static, + B::Accept: Send + Sync, +{ + pub fn bind_upgradable(listener: SelfContainedNetworkInterfaceListener) -> Self { + Self::new(Some(Either::Left(listener))) + } +} diff --git a/core/startos/src/net/host/address.rs b/core/startos/src/net/host/address.rs index 393936724..6d7723a23 100644 --- a/core/startos/src/net/host/address.rs +++ b/core/startos/src/net/host/address.rs @@ -4,17 +4,17 @@ use std::net::Ipv4Addr; use clap::Parser; use imbl_value::InternedString; use models::GatewayId; -use rpc_toolkit::{from_fn_async, Context, Empty, HandlerArgs, HandlerExt, ParentHandler}; +use rpc_toolkit::{Context, Empty, HandlerArgs, HandlerExt, ParentHandler, from_fn_async}; use serde::{Deserialize, Serialize}; use ts_rs::TS; use crate::context::{CliContext, RpcContext}; use crate::db::model::DatabaseModel; use crate::net::acme::AcmeProvider; -use crate::net::host::{all_hosts, HostApiKind}; +use crate::net::host::{HostApiKind, all_hosts}; use crate::net::tor::OnionAddress; use crate::prelude::*; -use crate::util::serde::{display_serializable, HandlerExtSerde}; +use crate::util::serde::{HandlerExtSerde, display_serializable}; #[derive(Clone, Debug, Deserialize, Serialize)] #[serde(rename_all = "kebab-case")] @@ -105,8 +105,8 @@ fn handle_duplicates(db: &mut DatabaseModel) -> Result<(), Error> { Ok(()) } -pub fn address_api( -) -> ParentHandler { +pub fn address_api() +-> ParentHandler { ParentHandler::::new() .subcommand( "domain", @@ -357,15 +357,7 @@ pub async fn add_onion( OnionParams { onion }: OnionParams, inheritance: Kind::Inheritance, ) -> Result<(), Error> { - let onion = onion - .strip_suffix(".onion") - .ok_or_else(|| { - Error::new( - eyre!("onion hostname must end in .onion"), - ErrorKind::InvalidOnionAddress, - ) - })? - .parse::()?; + let onion = onion.parse::()?; ctx.db .mutate(|db| { db.as_private().as_key_store().as_onion().get_key(&onion)?; @@ -388,15 +380,7 @@ pub async fn remove_onion( OnionParams { onion }: OnionParams, inheritance: Kind::Inheritance, ) -> Result<(), Error> { - let onion = onion - .strip_suffix(".onion") - .ok_or_else(|| { - Error::new( - eyre!("onion hostname must end in .onion"), - ErrorKind::InvalidOnionAddress, - ) - })? - .parse::()?; + let onion = onion.parse::()?; ctx.db .mutate(|db| { Kind::host_for(&inheritance, db)? diff --git a/core/startos/src/net/host/binding.rs b/core/startos/src/net/host/binding.rs index bb2e12454..59939b689 100644 --- a/core/startos/src/net/host/binding.rs +++ b/core/startos/src/net/host/binding.rs @@ -1,11 +1,11 @@ use std::collections::{BTreeMap, BTreeSet}; use std::str::FromStr; -use clap::builder::ValueParserFactory; use clap::Parser; +use clap::builder::ValueParserFactory; use imbl::OrdSet; use models::{FromStrParser, GatewayId, HostId}; -use rpc_toolkit::{from_fn_async, Context, Empty, HandlerArgs, HandlerExt, ParentHandler}; +use rpc_toolkit::{Context, Empty, HandlerArgs, HandlerExt, ParentHandler, from_fn_async}; use serde::{Deserialize, Serialize}; use ts_rs::TS; @@ -16,7 +16,7 @@ use crate::net::gateway::InterfaceFilter; use crate::net::host::HostApiKind; use crate::net::vhost::AlpnInfo; use crate::prelude::*; -use crate::util::serde::{display_serializable, HandlerExtSerde}; +use crate::util::serde::{HandlerExtSerde, display_serializable}; #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, TS)] #[ts(export)] @@ -170,8 +170,8 @@ pub struct AddSslOptions { pub alpn: Option, } -pub fn binding( -) -> ParentHandler { +pub fn binding() +-> ParentHandler { ParentHandler::::new() .subcommand( "list", diff --git a/core/startos/src/net/host/mod.rs b/core/startos/src/net/host/mod.rs index e2278a858..c5e6388eb 100644 --- a/core/startos/src/net/host/mod.rs +++ b/core/startos/src/net/host/mod.rs @@ -6,15 +6,15 @@ use clap::Parser; use imbl_value::InternedString; use itertools::Itertools; use models::{HostId, PackageId}; -use rpc_toolkit::{from_fn_async, Context, Empty, HandlerExt, OrEmpty, ParentHandler}; +use rpc_toolkit::{Context, Empty, HandlerExt, OrEmpty, ParentHandler, from_fn_async}; use serde::{Deserialize, Serialize}; use ts_rs::TS; use crate::context::RpcContext; use crate::db::model::DatabaseModel; use crate::net::forward::AvailablePorts; -use crate::net::host::address::{address_api, HostAddress, PublicDomainConfig}; -use crate::net::host::binding::{binding, BindInfo, BindOptions}; +use crate::net::host::address::{HostAddress, PublicDomainConfig, address_api}; +use crate::net::host::binding::{BindInfo, BindOptions, binding}; use crate::net::service_interface::HostnameInfo; use crate::net::tor::OnionAddress; use crate::prelude::*; diff --git a/core/startos/src/net/keys.rs b/core/startos/src/net/keys.rs index 2cfcb025d..41e96eedd 100644 --- a/core/startos/src/net/keys.rs +++ b/core/startos/src/net/keys.rs @@ -8,6 +8,7 @@ use crate::prelude::*; #[derive(Debug, Deserialize, Serialize, HasModel)] #[model = "Model"] +#[serde(rename_all = "camelCase")] pub struct KeyStore { pub onion: OnionStore, pub local_certs: CertStore, diff --git a/core/startos/src/net/mod.rs b/core/startos/src/net/mod.rs index a3878e6dc..739eb861d 100644 --- a/core/startos/src/net/mod.rs +++ b/core/startos/src/net/mod.rs @@ -12,6 +12,7 @@ pub mod service_interface; pub mod socks; pub mod ssl; pub mod static_server; +pub mod tls; pub mod tor; pub mod tunnel; pub mod utils; diff --git a/core/startos/src/net/net_controller.rs b/core/startos/src/net/net_controller.rs index 2f3793482..db9d3a175 100644 --- a/core/startos/src/net/net_controller.rs +++ b/core/startos/src/net/net_controller.rs @@ -1,46 +1,48 @@ use std::collections::{BTreeMap, BTreeSet}; -use std::net::{Ipv4Addr, SocketAddr}; +use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4}; use std::sync::{Arc, Weak}; use color_eyre::eyre::eyre; -use imbl::{vector, OrdMap}; +use imbl::{OrdMap, vector}; use imbl_value::InternedString; use ipnet::IpNet; -use models::{HostId, OptionExt, PackageId}; +use models::{GatewayId, HostId, OptionExt, PackageId}; use tokio::sync::Mutex; use tokio::task::JoinHandle; +use tokio_rustls::rustls::ClientConfig as TlsClientConfig; use tracing::instrument; -use crate::db::model::public::{NetworkInterfaceInfo, NetworkInterfaceType}; +use crate::HOST_IP; use crate::db::model::Database; +use crate::db::model::public::NetworkInterfaceType; use crate::error::ErrorCollection; use crate::hostname::Hostname; use crate::net::dns::DnsController; -use crate::net::forward::PortForwardController; +use crate::net::forward::{InterfacePortForwardController, START9_BRIDGE_IFACE}; use crate::net::gateway::{ AndFilter, DynInterfaceFilter, IdFilter, InterfaceFilter, NetworkInterfaceController, OrFilter, - PublicFilter, SecureFilter, + PublicFilter, SecureFilter, TypeFilter, }; use crate::net::host::address::HostAddress; use crate::net::host::binding::{AddSslOptions, BindId, BindOptions}; -use crate::net::host::{host_for, Host, Hosts}; +use crate::net::host::{Host, Hosts, host_for}; use crate::net::service_interface::{GatewayInfo, HostnameInfo, IpHostname, OnionHostname}; use crate::net::socks::SocksController; use crate::net::tor::{OnionAddress, TorController, TorSecretKey}; use crate::net::utils::ipv6_is_local; -use crate::net::vhost::{AlpnInfo, TargetInfo, VHostController}; +use crate::net::vhost::{AlpnInfo, DynVHostTarget, ProxyTarget, VHostController}; use crate::prelude::*; use crate::service::effects::callbacks::ServiceCallbacks; use crate::util::serde::MaybeUtf8String; -use crate::HOST_IP; pub struct NetController { pub(crate) db: TypedPatchDb, pub(super) tor: TorController, pub(super) vhost: VHostController, + pub(super) tls_client_config: Arc, pub(crate) net_iface: Arc, pub(super) dns: DnsController, - pub(super) forward: PortForwardController, + pub(super) forward: InterfacePortForwardController, pub(super) socks: SocksController, pub(super) server_hostnames: Vec>, pub(crate) callbacks: Arc, @@ -55,12 +57,26 @@ impl NetController { let net_iface = Arc::new(NetworkInterfaceController::new(db.clone())); let tor = TorController::new()?; let socks = SocksController::new(socks_listen, tor.clone())?; + let crypto_provider = Arc::new(tokio_rustls::rustls::crypto::ring::default_provider()); + let tls_client_config = Arc::new(crate::net::tls::client_config( + crypto_provider.clone(), + [&*db + .peek() + .await + .as_private() + .as_key_store() + .as_local_certs() + .as_root_cert() + .de()? + .0], + )?); Ok(Self { db: db.clone(), tor, - vhost: VHostController::new(db.clone(), net_iface.clone()), + vhost: VHostController::new(db.clone(), net_iface.clone(), crypto_provider), + tls_client_config, dns: DnsController::init(db, &net_iface.watcher).await?, - forward: PortForwardController::new(net_iface.watcher.subscribe()), + forward: InterfacePortForwardController::new(net_iface.watcher.subscribe()), net_iface, socks, server_hostnames: vec![ @@ -133,8 +149,8 @@ impl NetController { #[derive(Default, Debug)] struct HostBinds { - forwards: BTreeMap)>, - vhosts: BTreeMap<(Option, u16), (TargetInfo, Arc<()>)>, + forwards: BTreeMap)>, + vhosts: BTreeMap<(Option, u16), (ProxyTarget, Arc<()>)>, private_dns: BTreeMap>, tor: BTreeMap, Vec>)>, } @@ -225,8 +241,8 @@ impl NetServiceData { } async fn update(&mut self, ctrl: &NetController, id: HostId, host: Host) -> Result<(), Error> { - let mut forwards: BTreeMap = BTreeMap::new(); - let mut vhosts: BTreeMap<(Option, u16), TargetInfo> = BTreeMap::new(); + let mut forwards: BTreeMap = BTreeMap::new(); + let mut vhosts: BTreeMap<(Option, u16), ProxyTarget> = BTreeMap::new(); let mut private_dns: BTreeSet = BTreeSet::new(); let mut tor: BTreeMap)> = BTreeMap::new(); @@ -263,11 +279,13 @@ impl NetServiceData { for hostname in ctrl.server_hostnames.iter().cloned() { vhosts.insert( (hostname, external), - TargetInfo { + ProxyTarget { filter: bind.net.clone().into_dyn(), acme: None, addr, - connect_ssl: connect_ssl.clone(), + connect_ssl: connect_ssl + .clone() + .map(|_| ctrl.tls_client_config.clone()), }, ); } @@ -278,19 +296,19 @@ impl NetServiceData { if hostnames.insert(hostname.clone()) { vhosts.insert( (Some(hostname), external), - TargetInfo { + ProxyTarget { filter: OrFilter( - IdFilter( - NetworkInterfaceInfo::loopback().0.clone(), - ), - IdFilter( - NetworkInterfaceInfo::lxc_bridge().0.clone(), - ), + TypeFilter(NetworkInterfaceType::Loopback), + IdFilter(GatewayId::from(InternedString::from( + START9_BRIDGE_IFACE, + ))), ) .into_dyn(), acme: None, addr, - connect_ssl: connect_ssl.clone(), + connect_ssl: connect_ssl + .clone() + .map(|_| ctrl.tls_client_config.clone()), }, ); // TODO: wrap onion ssl stream directly in tor ctrl } @@ -306,7 +324,7 @@ impl NetServiceData { if let Some(public) = &public { vhosts.insert( (address.clone(), 5443), - TargetInfo { + ProxyTarget { filter: AndFilter( bind.net.clone(), AndFilter( @@ -317,12 +335,14 @@ impl NetServiceData { .into_dyn(), acme: public.acme.clone(), addr, - connect_ssl: connect_ssl.clone(), + connect_ssl: connect_ssl + .clone() + .map(|_| ctrl.tls_client_config.clone()), }, ); vhosts.insert( (address.clone(), 443), - TargetInfo { + ProxyTarget { filter: AndFilter( bind.net.clone(), if private { @@ -342,13 +362,15 @@ impl NetServiceData { .into_dyn(), acme: public.acme.clone(), addr, - connect_ssl: connect_ssl.clone(), + connect_ssl: connect_ssl + .clone() + .map(|_| ctrl.tls_client_config.clone()), }, ); } else { vhosts.insert( (address.clone(), 443), - TargetInfo { + ProxyTarget { filter: AndFilter( bind.net.clone(), PublicFilter { public: false }, @@ -356,7 +378,9 @@ impl NetServiceData { .into_dyn(), acme: None, addr, - connect_ssl: connect_ssl.clone(), + connect_ssl: connect_ssl + .clone() + .map(|_| ctrl.tls_client_config.clone()), }, ); } @@ -364,7 +388,7 @@ impl NetServiceData { if let Some(public) = public { vhosts.insert( (address.clone(), external), - TargetInfo { + ProxyTarget { filter: AndFilter( bind.net.clone(), if private { @@ -381,13 +405,15 @@ impl NetServiceData { .into_dyn(), acme: public.acme.clone(), addr, - connect_ssl: connect_ssl.clone(), + connect_ssl: connect_ssl + .clone() + .map(|_| ctrl.tls_client_config.clone()), }, ); } else { vhosts.insert( (address.clone(), external), - TargetInfo { + ProxyTarget { filter: AndFilter( bind.net.clone(), PublicFilter { public: false }, @@ -395,7 +421,9 @@ impl NetServiceData { .into_dyn(), acme: None, addr, - connect_ssl: connect_ssl.clone(), + connect_ssl: connect_ssl + .clone() + .map(|_| ctrl.tls_client_config.clone()), }, ); } @@ -414,7 +442,7 @@ impl NetServiceData { forwards.insert( external, ( - (self.ip, *port).into(), + SocketAddrV4::new(self.ip, *port), AndFilter( SecureFilter { secure: bind.options.secure.is_some(), @@ -429,6 +457,11 @@ impl NetServiceData { hostname_info.remove(port).unwrap_or_default(); for (gateway_id, info) in net_ifaces .iter() + .filter(|(_, info)| { + info.ip_info.as_ref().map_or(false, |i| { + !matches!(i.device_type, Some(NetworkInterfaceType::Bridge)) + }) + }) .filter(|(id, info)| bind.net.filter(id, info)) { let gateway = GatewayInfo { @@ -653,7 +686,10 @@ impl NetServiceData { if let Some(prev) = prev { prev } else { - (target.clone(), ctrl.vhost.add(key.0, key.1, target)?) + ( + target.clone(), + ctrl.vhost.add(key.0, key.1, DynVHostTarget::new(target))?, + ) }, ); } else { @@ -688,7 +724,7 @@ impl NetServiceData { .collect::>(); for onion in all { let mut prev = binds.tor.remove(&onion); - if let Some((key, tor_binds)) = tor.remove(&onion) { + if let Some((key, tor_binds)) = tor.remove(&onion).filter(|(_, b)| !b.is_empty()) { prev = prev.filter(|(b, _)| b == &tor_binds); binds.tor.insert( onion, diff --git a/core/startos/src/net/socks.rs b/core/startos/src/net/socks.rs index b6ac3030c..d556fa143 100644 --- a/core/startos/src/net/socks.rs +++ b/core/startos/src/net/socks.rs @@ -8,10 +8,10 @@ use socks5_impl::server::auth::NoAuth; use socks5_impl::server::{AuthAdaptor, ClientConnection, Server}; use tokio::net::{TcpListener, TcpStream}; +use crate::HOST_IP; use crate::net::tor::TorController; use crate::prelude::*; use crate::util::actor::background::BackgroundJobQueue; -use crate::HOST_IP; pub const DEFAULT_SOCKS_LISTEN: SocketAddr = SocketAddr::V4(SocketAddrV4::new( Ipv4Addr::new(HOST_IP[0], HOST_IP[1], HOST_IP[2], HOST_IP[3]), diff --git a/core/startos/src/net/ssl.rs b/core/startos/src/net/ssl.rs index 9b0c51f3c..fef0c2b0f 100644 --- a/core/startos/src/net/ssl.rs +++ b/core/startos/src/net/ssl.rs @@ -2,6 +2,7 @@ use std::cmp::{Ordering, min}; use std::collections::{BTreeMap, BTreeSet}; use std::net::IpAddr; use std::path::Path; +use std::sync::Arc; use std::time::{Duration, SystemTime, UNIX_EPOCH}; use futures::FutureExt; @@ -10,22 +11,43 @@ use libc::time_t; use openssl::asn1::{Asn1Integer, Asn1Time, Asn1TimeRef}; use openssl::bn::{BigNum, MsbOption}; use openssl::ec::{EcGroup, EcKey}; +use openssl::error::ErrorStack; use openssl::hash::MessageDigest; use openssl::nid::Nid; use openssl::pkey::{PKey, Private}; -use openssl::x509::{X509, X509Builder, X509Extension, X509NameBuilder}; +use openssl::x509::extension::{ + AuthorityKeyIdentifier, BasicConstraints, KeyUsage, SubjectAlternativeName, + SubjectKeyIdentifier, +}; +use openssl::x509::{X509, X509Builder, X509NameBuilder}; use openssl::*; use patch_db::HasModel; use serde::{Deserialize, Serialize}; +use tokio_rustls::rustls::ServerConfig; +use tokio_rustls::rustls::crypto::CryptoProvider; +use tokio_rustls::rustls::pki_types::{PrivateKeyDer, PrivatePkcs8KeyDer}; +use tokio_rustls::rustls::server::ClientHello; use tracing::instrument; +use visit_rs::Visit; use crate::SOURCE_DATE; use crate::account::AccountInfo; +use crate::db::model::Database; +use crate::db::{DbAccess, DbAccessMut}; use crate::hostname::Hostname; use crate::init::check_time_is_synchronized; +use crate::net::gateway::GatewayInfo; +use crate::net::tls::TlsHandler; +use crate::net::web_server::{Accept, ExtractVisitor, TcpMetadata, extract}; use crate::prelude::*; use crate::util::serde::Pem; +pub fn gen_nistp256() -> Result, ErrorStack> { + PKey::from_ec_key(EcKey::generate(&*EcGroup::from_curve_name( + Nid::X9_62_PRIME256V1, + )?)?) +} + #[derive(Debug, Deserialize, Serialize, HasModel)] #[model = "Model"] #[serde(rename_all = "camelCase")] @@ -96,9 +118,7 @@ impl Model { } else { PKeyPair { ed25519: PKey::generate_ed25519()?, - nistp256: PKey::from_ec_key(EcKey::generate(&*EcGroup::from_curve_name( - Nid::X9_62_PRIME256V1, - )?)?)?, + nistp256: gen_nistp256()?, } }; let int_key = self.as_int_key().de()?.0; @@ -125,6 +145,16 @@ impl Model { }) } } +impl DbAccess for Database { + fn access<'a>(db: &'a Model) -> &'a Model { + db.as_private().as_key_store().as_local_certs() + } +} +impl DbAccessMut for Database { + fn access_mut<'a>(db: &'a mut Model) -> &'a mut Model { + db.as_private_mut().as_key_store_mut().as_local_certs_mut() + } +} #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] pub struct CertData { @@ -300,22 +330,16 @@ pub fn make_root_cert( let cfg = conf::Conf::new(conf::ConfMethod::default())?; let ctx = builder.x509v3_context(None, Some(&cfg)); // subjectKeyIdentifier = hash - let subject_key_identifier = - X509Extension::new_nid(Some(&cfg), Some(&ctx), Nid::SUBJECT_KEY_IDENTIFIER, "hash")?; + let subject_key_identifier = SubjectKeyIdentifier::new().build(&ctx)?; // basicConstraints = critical, CA:true, pathlen:0 - let basic_constraints = X509Extension::new_nid( - Some(&cfg), - Some(&ctx), - Nid::BASIC_CONSTRAINTS, - "critical,CA:true", - )?; + let basic_constraints = BasicConstraints::new().critical().ca().build()?; // keyUsage = critical, digitalSignature, cRLSign, keyCertSign - let key_usage = X509Extension::new_nid( - Some(&cfg), - Some(&ctx), - Nid::KEY_USAGE, - "critical,digitalSignature,cRLSign,keyCertSign", - )?; + let key_usage = KeyUsage::new() + .critical() + .digital_signature() + .crl_sign() + .key_cert_sign() + .build()?; builder.append_extension(subject_key_identifier)?; builder.append_extension(basic_constraints)?; builder.append_extension(key_usage)?; @@ -350,30 +374,23 @@ pub fn make_int_cert( let cfg = conf::Conf::new(conf::ConfMethod::default())?; let ctx = builder.x509v3_context(Some(&signer.1), Some(&cfg)); + // subjectKeyIdentifier = hash - let subject_key_identifier = - X509Extension::new_nid(Some(&cfg), Some(&ctx), Nid::SUBJECT_KEY_IDENTIFIER, "hash")?; + let subject_key_identifier = SubjectKeyIdentifier::new().build(&ctx)?; // authorityKeyIdentifier = keyid:always,issuer - let authority_key_identifier = X509Extension::new_nid( - Some(&cfg), - Some(&ctx), - Nid::AUTHORITY_KEY_IDENTIFIER, - "keyid:always,issuer", - )?; + let authority_key_identifier = AuthorityKeyIdentifier::new() + .keyid(false) + .issuer(true) + .build(&ctx)?; // basicConstraints = critical, CA:true, pathlen:0 - let basic_constraints = X509Extension::new_nid( - Some(&cfg), - Some(&ctx), - Nid::BASIC_CONSTRAINTS, - "critical,CA:true,pathlen:0", - )?; + let basic_constraints = BasicConstraints::new().critical().ca().pathlen(0).build()?; // keyUsage = critical, digitalSignature, cRLSign, keyCertSign - let key_usage = X509Extension::new_nid( - Some(&cfg), - Some(&ctx), - Nid::KEY_USAGE, - "critical,digitalSignature,cRLSign,keyCertSign", - )?; + let key_usage = KeyUsage::new() + .critical() + .digital_signature() + .crl_sign() + .key_cert_sign() + .build()?; builder.append_extension(subject_key_identifier)?; builder.append_extension(authority_key_identifier)?; builder.append_extension(basic_constraints)?; @@ -423,6 +440,16 @@ impl SANInfo { } Self { dns, ips } } + pub fn x509_extension(&self) -> SubjectAlternativeName { + let mut san = SubjectAlternativeName::new(); + for h in &self.dns { + san.dns(&h.as_str()); + } + for ip in &self.ips { + san.ip(&ip.to_string()); + } + san + } } impl std::fmt::Display for SANInfo { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -485,28 +512,20 @@ pub fn make_leaf_cert( // Extensions let cfg = conf::Conf::new(conf::ConfMethod::default())?; let ctx = builder.x509v3_context(Some(&signer.1), Some(&cfg)); - // subjectKeyIdentifier = hash - let subject_key_identifier = - X509Extension::new_nid(Some(&cfg), Some(&ctx), Nid::SUBJECT_KEY_IDENTIFIER, "hash")?; - // authorityKeyIdentifier = keyid:always,issuer - let authority_key_identifier = X509Extension::new_nid( - Some(&cfg), - Some(&ctx), - Nid::AUTHORITY_KEY_IDENTIFIER, - "keyid,issuer:always", - )?; - let basic_constraints = - X509Extension::new_nid(Some(&cfg), Some(&ctx), Nid::BASIC_CONSTRAINTS, "CA:FALSE")?; - let key_usage = X509Extension::new_nid( - Some(&cfg), - Some(&ctx), - Nid::KEY_USAGE, - "critical,digitalSignature,keyEncipherment", - )?; - let san_string = applicant.1.to_string(); - let subject_alt_name = - X509Extension::new_nid(Some(&cfg), Some(&ctx), Nid::SUBJECT_ALT_NAME, &san_string)?; + let subject_key_identifier = SubjectKeyIdentifier::new().build(&ctx)?; + let authority_key_identifier = AuthorityKeyIdentifier::new() + .keyid(false) + .issuer(true) + .build(&ctx)?; + let subject_alt_name = applicant.1.x509_extension().build(&ctx)?; + let basic_constraints = BasicConstraints::new().build()?; + let key_usage = KeyUsage::new() + .critical() + .digital_signature() + .key_encipherment() + .build()?; + builder.append_extension(subject_key_identifier)?; builder.append_extension(authority_key_identifier)?; builder.append_extension(subject_alt_name)?; @@ -518,3 +537,161 @@ pub fn make_leaf_cert( let cert = builder.build(); Ok(cert) } + +#[instrument(skip_all)] +pub fn make_self_signed(applicant: (&PKey, &SANInfo)) -> Result { + let mut builder = X509Builder::new()?; + builder.set_version(CERTIFICATE_VERSION)?; + + let embargo = Asn1Time::from_unix(unix_time(SystemTime::now()) - 86400)?; + builder.set_not_before(&embargo)?; + + // Google Apple and Mozilla reject certificate horizons longer than 398 days + // https://techbeacon.com/security/google-apple-mozilla-enforce-1-year-max-security-certifications + let expiration = Asn1Time::days_from_now(397)?; + builder.set_not_after(&expiration)?; + + builder.set_serial_number(&*rand_serial()?)?; + + let mut subject_name_builder = X509NameBuilder::new()?; + subject_name_builder.append_entry_by_text( + "CN", + applicant + .1 + .dns + .first() + .map(MaybeWildcard::as_str) + .unwrap_or("localhost"), + )?; + subject_name_builder.append_entry_by_text("O", "Start9")?; + subject_name_builder.append_entry_by_text("OU", "StartOS")?; + let subject_name = subject_name_builder.build(); + builder.set_subject_name(&subject_name)?; + + builder.set_issuer_name(&subject_name)?; + + builder.set_pubkey(&applicant.0)?; + + // Extensions + let cfg = conf::Conf::new(conf::ConfMethod::default())?; + let ctx = builder.x509v3_context(None, Some(&cfg)); + + let subject_key_identifier = SubjectKeyIdentifier::new().build(&ctx)?; + let authority_key_identifier = AuthorityKeyIdentifier::new() + .keyid(false) + .issuer(true) + .build(&ctx)?; + let subject_alt_name = applicant.1.x509_extension().build(&ctx)?; + let basic_constraints = BasicConstraints::new().build()?; + let key_usage = KeyUsage::new() + .critical() + .digital_signature() + .key_encipherment() + .build()?; + + builder.append_extension(subject_key_identifier)?; + builder.append_extension(authority_key_identifier)?; + builder.append_extension(subject_alt_name)?; + builder.append_extension(basic_constraints)?; + builder.append_extension(key_usage)?; + + builder.sign(&applicant.0, MessageDigest::sha256())?; + + let cert = builder.build(); + Ok(cert) +} + +pub struct RootCaTlsHandler { + pub db: TypedPatchDb, + pub crypto_provider: Arc, +} +impl Clone for RootCaTlsHandler { + fn clone(&self) -> Self { + Self { + db: self.db.clone(), + crypto_provider: self.crypto_provider.clone(), + } + } +} + +impl<'a, A, M> TlsHandler<'a, A> for RootCaTlsHandler +where + A: Accept + 'a, + ::Metadata: Visit> + + Visit> + + Clone + + Send + + Sync + + 'static, + M: HasModel> + DbAccessMut + Send + Sync, +{ + async fn get_config( + &mut self, + hello: &ClientHello<'_>, + metadata: &::Metadata, + ) -> Option { + let hostnames: BTreeSet = hello + .server_name() + .map(InternedString::from) + .into_iter() + .chain( + extract::(metadata) + .map(|m| m.local_addr.ip()) + .as_ref() + .map(InternedString::from_display), + ) + .chain( + extract::(metadata) + .and_then(|i| i.info.ip_info) + .and_then(|i| i.wan_ip) + .as_ref() + .map(InternedString::from_display), + ) + .collect(); + let cert = self + .db + .mutate(|db| M::access_mut(db).cert_for(&hostnames)) + .await + .result + .log_err()?; + let cfg = ServerConfig::builder_with_provider(self.crypto_provider.clone()) + .with_safe_default_protocol_versions() + .log_err()? + .with_no_client_auth(); + if hello + .signature_schemes() + .contains(&tokio_rustls::rustls::SignatureScheme::ED25519) + { + cfg.with_single_cert( + cert.fullchain_ed25519() + .into_iter() + .map(|c| { + Ok(tokio_rustls::rustls::pki_types::CertificateDer::from( + c.to_der()?, + )) + }) + .collect::>() + .log_err()?, + PrivateKeyDer::from(PrivatePkcs8KeyDer::from( + cert.leaf.keys.ed25519.private_key_to_pkcs8().log_err()?, + )), + ) + } else { + cfg.with_single_cert( + cert.fullchain_nistp256() + .into_iter() + .map(|c| { + Ok(tokio_rustls::rustls::pki_types::CertificateDer::from( + c.to_der()?, + )) + }) + .collect::>() + .log_err()?, + PrivateKeyDer::from(PrivatePkcs8KeyDer::from( + cert.leaf.keys.nistp256.private_key_to_pkcs8().log_err()?, + )), + ) + } + .log_err() + } +} diff --git a/core/startos/src/net/static_server.rs b/core/startos/src/net/static_server.rs index b055dec72..de78905b8 100644 --- a/core/startos/src/net/static_server.rs +++ b/core/startos/src/net/static_server.rs @@ -9,7 +9,7 @@ use async_compression::tokio::bufread::GzipEncoder; use axum::Router; use axum::body::Body; use axum::extract::{self as x, Request}; -use axum::response::{Redirect, Response}; +use axum::response::{IntoResponse, Redirect, Response}; use axum::routing::{any, get}; use base64::display::Base64Display; use digest::Digest; @@ -26,16 +26,19 @@ use models::PackageId; use new_mime_guess::MimeGuess; use openssl::hash::MessageDigest; use openssl::x509::X509; -use rpc_toolkit::{Context, HttpServer, Server}; +use rpc_toolkit::{Context, HttpServer, ParentHandler, Server}; use tokio::io::{AsyncRead, AsyncReadExt, AsyncSeekExt, BufReader}; use tokio_util::io::ReaderStream; use url::Url; use crate::context::{DiagnosticContext, InitContext, InstallContext, RpcContext, SetupContext}; use crate::hostname::Hostname; +use crate::main_api; use crate::middleware::auth::{Auth, HasValidSession}; use crate::middleware::cors::Cors; use crate::middleware::db::SyncDb; +use crate::net::gateway::GatewayInfo; +use crate::net::tls::TlsHandshakeInfo; use crate::prelude::*; use crate::rpc_continuations::{Guid, RpcContinuations}; use crate::s9pk::S9pk; @@ -46,7 +49,6 @@ use crate::sign::commitment::merkle_archive::MerkleArchiveCommitment; use crate::util::io::open_file; use crate::util::net::SyncBody; use crate::util::serde::BASE64; -use crate::{diagnostic_api, init_api, install_api, main_api, setup_api}; const NOT_FOUND: &[u8] = b"Not Found"; const METHOD_NOT_ALLOWED: &[u8] = b"Method Not Allowed"; @@ -55,26 +57,151 @@ const INTERNAL_SERVER_ERROR: &[u8] = b"Internal Server Error"; const PROXY_STRIP_HEADERS: &[&str] = &["cookie", "host", "origin", "referer", "user-agent"]; -#[cfg(all(feature = "startd", not(feature = "test")))] -const EMBEDDED_UIS: Dir<'_> = - include_dir::include_dir!("$CARGO_MANIFEST_DIR/../../web/dist/static"); -#[cfg(not(all(feature = "startd", not(feature = "test"))))] -const EMBEDDED_UIS: Dir<'_> = Dir::new("", &[]); +pub const EMPTY_DIR: Dir<'_> = Dir::new("", &[]); -#[derive(Clone)] -pub enum UiMode { - Setup, - Install, - Main, +#[macro_export] +macro_rules! else_empty_dir { + ($cfg:meta => $dir:expr) => {{ + #[cfg(all($cfg, not(feature = "test")))] + { + $dir + } + #[cfg(not(all($cfg, not(feature = "test"))))] + { + crate::net::static_server::EMPTY_DIR + } + }}; } -impl UiMode { - fn path(&self, path: &str) -> PathBuf { - match self { - Self::Setup => Path::new("setup-wizard").join(path), - Self::Install => Path::new("install-wizard").join(path), - Self::Main => Path::new("ui").join(path), +const EMBEDDED_UI_ROOT: Dir<'_> = else_empty_dir!( + feature = "startd" => + include_dir::include_dir!("$CARGO_MANIFEST_DIR/../../web/dist/static") +); + +pub trait UiContext: Context + AsRef + Clone + Sized { + const UI_DIR: &'static Dir<'static>; + fn api() -> ParentHandler; + fn middleware(server: Server) -> HttpServer; + fn extend_router(self, router: Router) -> Router { + router + } +} + +impl UiContext for RpcContext { + const UI_DIR: &'static Dir<'static> = &else_empty_dir!( + feature = "startd" => + include_dir::include_dir!("$CARGO_MANIFEST_DIR/../../web/dist/static/ui") + ); + fn api() -> ParentHandler { + main_api() + } + fn middleware(server: Server) -> HttpServer { + server + .middleware(Cors::new()) + .middleware(Auth::new()) + .middleware(SyncDb::new()) + } + fn extend_router(self, router: Router) -> Router { + async fn https_redirect_if_public_http( + req: Request, + next: axum::middleware::Next, + ) -> Response { + if req + .extensions() + .get::() + .map_or(false, |p| p.info.public()) + && req.extensions().get::().is_none() + { + Redirect::temporary(&format!( + "https://{}{}", + req.headers() + .get(HOST) + .and_then(|s| s.to_str().ok()) + .unwrap_or("localhost"), + req.uri() + )) + .into_response() + } else { + next.run(req).await + } } + + router + .route("/proxy/{url}", { + let ctx = self.clone(); + any(move |x::Path(url): x::Path, request: Request| { + let ctx = ctx.clone(); + async move { + proxy_request(ctx, request, url) + .await + .unwrap_or_else(server_error) + } + }) + }) + .nest("/s9pk", s9pk_router(self.clone())) + .route( + "/static/local-root-ca.crt", + get(move || { + let ctx = self.clone(); + async move { + ctx.account + .peek(|account| cert_send(&account.root_ca_cert, &account.hostname)) + } + }), + ) + .layer(axum::middleware::from_fn(https_redirect_if_public_http)) + } +} + +impl UiContext for InitContext { + const UI_DIR: &'static Dir<'static> = &else_empty_dir!( + feature = "startd" => + include_dir::include_dir!("$CARGO_MANIFEST_DIR/../../web/dist/static/ui") + ); + fn api() -> ParentHandler { + main_api() + } + fn middleware(server: Server) -> HttpServer { + server.middleware(Cors::new()) + } +} + +impl UiContext for DiagnosticContext { + const UI_DIR: &'static Dir<'static> = &else_empty_dir!( + feature = "startd" => + include_dir::include_dir!("$CARGO_MANIFEST_DIR/../../web/dist/static/ui") + ); + fn api() -> ParentHandler { + main_api() + } + fn middleware(server: Server) -> HttpServer { + server.middleware(Cors::new()) + } +} + +impl UiContext for SetupContext { + const UI_DIR: &'static Dir<'static> = &else_empty_dir!( + feature = "startd" => + include_dir::include_dir!("$CARGO_MANIFEST_DIR/../../web/dist/static/setup-wizard") + ); + fn api() -> ParentHandler { + main_api() + } + fn middleware(server: Server) -> HttpServer { + server.middleware(Cors::new()) + } +} + +impl UiContext for InstallContext { + const UI_DIR: &'static Dir<'static> = &else_empty_dir!( + feature = "startd" => + include_dir::include_dir!("$CARGO_MANIFEST_DIR/../../web/dist/static/install-wizard") + ); + fn api() -> ParentHandler { + main_api() + } + fn middleware(server: Server) -> HttpServer { + server.middleware(Cors::new()) } } @@ -111,24 +238,23 @@ pub fn rpc_router>( ) } -fn serve_ui(req: Request, ui_mode: UiMode) -> Result { +fn serve_ui(req: Request) -> Result { let (request_parts, _body) = req.into_parts(); match &request_parts.method { &Method::GET | &Method::HEAD => { - let uri_path = ui_mode.path( - request_parts - .uri - .path() - .strip_prefix('/') - .unwrap_or(request_parts.uri.path()), - ); + let uri_path = request_parts + .uri + .path() + .strip_prefix('/') + .unwrap_or(request_parts.uri.path()); - let file = EMBEDDED_UIS - .get_file(&*uri_path) - .or_else(|| EMBEDDED_UIS.get_file(&*ui_mode.path("index.html"))); + let file = C::UI_DIR + .get_file(uri_path) + .or_else(|| C::UI_DIR.get_file("index.html")); if let Some(file) = file { - FileData::from_embedded(&request_parts, file)?.into_response(&request_parts) + FileData::from_embedded(&request_parts, file, C::UI_DIR)? + .into_response(&request_parts) } else { Ok(not_found()) } @@ -137,79 +263,15 @@ fn serve_ui(req: Request, ui_mode: UiMode) -> Result { } } -pub fn setup_ui_router(ctx: SetupContext) -> Router { - rpc_router( - ctx.clone(), - Server::new(move || ready(Ok(ctx.clone())), setup_api()).middleware(Cors::new()), - ) - .fallback(any(|request: Request| async move { - serve_ui(request, UiMode::Setup).unwrap_or_else(server_error) - })) -} - -pub fn diagnostic_ui_router(ctx: DiagnosticContext) -> Router { - rpc_router( - ctx.clone(), - Server::new(move || ready(Ok(ctx.clone())), diagnostic_api()).middleware(Cors::new()), - ) - .fallback(any(|request: Request| async move { - serve_ui(request, UiMode::Main).unwrap_or_else(server_error) - })) -} - -pub fn install_ui_router(ctx: InstallContext) -> Router { - rpc_router( - ctx.clone(), - Server::new(move || ready(Ok(ctx.clone())), install_api()).middleware(Cors::new()), - ) - .fallback(any(|request: Request| async move { - serve_ui(request, UiMode::Install).unwrap_or_else(server_error) - })) -} - -pub fn init_ui_router(ctx: InitContext) -> Router { - rpc_router( - ctx.clone(), - Server::new(move || ready(Ok(ctx.clone())), init_api()).middleware(Cors::new()), - ) - .fallback(any(|request: Request| async move { - serve_ui(request, UiMode::Main).unwrap_or_else(server_error) - })) -} - -pub fn main_ui_router(ctx: RpcContext) -> Router { - rpc_router(ctx.clone(), { - let ctx = ctx.clone(); - Server::new(move || ready(Ok(ctx.clone())), main_api::()) - .middleware(Cors::new()) - .middleware(Auth::new()) - .middleware(SyncDb::new()) - }) - .route("/proxy/{url}", { - let ctx = ctx.clone(); - any(move |x::Path(url): x::Path, request: Request| { - let ctx = ctx.clone(); - async move { - proxy_request(ctx, request, url) - .await - .unwrap_or_else(server_error) - } - }) - }) - .nest("/s9pk", s9pk_router(ctx.clone())) - .route( - "/static/local-root-ca.crt", - get(move || { - let ctx = ctx.clone(); - async move { - let account = ctx.account.read().await; - cert_send(&account.root_ca_cert, &account.hostname) - } - }), - ) - .fallback(any(|request: Request| async move { - serve_ui(request, UiMode::Main).unwrap_or_else(server_error) - })) +pub fn ui_router(ctx: C) -> Router { + ctx.clone() + .extend_router(rpc_router( + ctx.clone(), + C::middleware(Server::new(move || ready(Ok(ctx.clone())), C::api())), + )) + .fallback(any(|request: Request| async move { + serve_ui::(request).unwrap_or_else(server_error) + })) } pub fn refresher() -> Router { @@ -229,20 +291,6 @@ pub fn refresher() -> Router { })) } -pub fn redirecter() -> Router { - Router::new().fallback(get(|request: Request| async move { - Redirect::temporary(&format!( - "https://{}{}", - request - .headers() - .get(HOST) - .and_then(|s| s.to_str().ok()) - .unwrap_or("localhost"), - request.uri() - )) - })) -} - async fn proxy_request(ctx: RpcContext, request: Request, url: String) -> Result { if_authorized(&ctx, request, |mut request| async { for header in PROXY_STRIP_HEADERS { @@ -492,6 +540,7 @@ impl FileData { fn from_embedded( req: &RequestParts, file: &'static include_dir::File<'static>, + ui_dir: &'static Dir<'static>, ) -> Result { let path = file.path(); let (encoding, data, len, content_range) = if let Some(range) = req.headers.get(RANGE) { @@ -533,12 +582,12 @@ impl FileData { .fold((None, file.contents()), |acc, e| { if let Some(file) = (e == "br") .then_some(()) - .and_then(|_| EMBEDDED_UIS.get_file(format!("{}.br", path.display()))) + .and_then(|_| ui_dir.get_file(format!("{}.br", path.display()))) { (Some("br"), file.contents()) } else if let Some(file) = (e == "gzip" && acc.0 != Some("br")) .then_some(()) - .and_then(|_| EMBEDDED_UIS.get_file(format!("{}.gz", path.display()))) + .and_then(|_| ui_dir.get_file(format!("{}.gz", path.display()))) { (Some("gzip"), file.contents()) } else { diff --git a/core/startos/src/net/tls.rs b/core/startos/src/net/tls.rs new file mode 100644 index 000000000..0a58d7085 --- /dev/null +++ b/core/startos/src/net/tls.rs @@ -0,0 +1,315 @@ +use std::sync::Arc; +use std::task::{Poll, ready}; + +use futures::future::BoxFuture; +use futures::stream::FuturesUnordered; +use futures::{FutureExt, StreamExt}; +use imbl_value::InternedString; +use openssl::x509::X509Ref; +use tokio::io::AsyncWriteExt; +use tokio_rustls::LazyConfigAcceptor; +use tokio_rustls::rustls::crypto::CryptoProvider; +use tokio_rustls::rustls::pki_types::CertificateDer; +use tokio_rustls::rustls::server::{Acceptor, ClientHello, ResolvesServerCert}; +use tokio_rustls::rustls::sign::CertifiedKey; +use tokio_rustls::rustls::{ClientConfig, RootCertStore, ServerConfig}; +use visit_rs::{Visit, VisitFields}; + +use crate::net::web_server::{Accept, AcceptStream, MetadataVisitor}; +use crate::prelude::*; +use crate::util::io::{BackTrackingIO, ReadWriter}; +use crate::util::serde::MaybeUtf8String; +use crate::util::sync::SyncMutex; + +#[derive(Debug, Clone, VisitFields)] +pub struct TlsMetadata { + pub inner: M, + pub tls_info: TlsHandshakeInfo, +} +impl, M: Visit> Visit for TlsMetadata { + fn visit(&self, visitor: &mut V) -> ::Result { + self.visit_fields(visitor).collect() + } +} + +#[derive(Debug, Clone)] +pub struct TlsHandshakeInfo { + pub sni: Option, + pub alpn: Vec, +} +impl Visit for TlsHandshakeInfo { + fn visit(&self, visitor: &mut V) -> ::Result { + visitor.visit(self) + } +} + +pub trait TlsHandler<'a, A: Accept> { + fn get_config( + &'a mut self, + hello: &'a ClientHello<'a>, + metadata: &'a A::Metadata, + ) -> impl Future> + Send + 'a; +} + +#[derive(Clone)] +pub struct ChainedHandler(pub H0, pub H1); +impl<'a, A, H0, H1> TlsHandler<'a, A> for ChainedHandler +where + A: Accept + 'a, + ::Metadata: Send + Sync, + H0: TlsHandler<'a, A> + Send, + H1: TlsHandler<'a, A> + Send, +{ + async fn get_config( + &'a mut self, + hello: &'a ClientHello<'a>, + metadata: &'a ::Metadata, + ) -> Option { + if let Some(config) = self.0.get_config(hello, metadata).await { + return Some(config); + } + self.1.get_config(hello, metadata).await + } +} + +#[derive(Clone)] +pub struct TlsHandlerWrapper { + pub inner: I, + pub wrapper: W, +} + +pub trait WrapTlsHandler { + fn wrap<'a>( + &'a mut self, + prev: ServerConfig, + hello: &'a ClientHello<'a>, + metadata: &'a ::Metadata, + ) -> impl Future> + Send + 'a + where + Self: 'a; +} + +impl<'a, A, I, W> TlsHandler<'a, A> for TlsHandlerWrapper +where + A: Accept + 'a, + ::Metadata: Send + Sync, + I: TlsHandler<'a, A> + Send, + W: WrapTlsHandler + Send, +{ + async fn get_config( + &'a mut self, + hello: &'a ClientHello<'a>, + metadata: &'a ::Metadata, + ) -> Option { + let prev = self.inner.get_config(hello, metadata).await?; + self.wrapper.wrap(prev, hello, metadata).await + } +} + +#[derive(Debug)] +pub struct SingleCertResolver(pub Arc); +impl ResolvesServerCert for SingleCertResolver { + fn resolve(&self, _: ClientHello) -> Option> { + Some(self.0.clone()) + } +} + +pub struct TlsListener TlsHandler<'a, A>> { + pub accept: A, + pub tls_handler: H, + in_progress: SyncMutex< + FuturesUnordered< + BoxFuture< + 'static, + ( + H, + Result, AcceptStream)>, Error>, + ), + >, + >, + >, +} +impl TlsHandler<'a, A>> TlsListener { + pub fn new(accept: A, cert_handler: H) -> Self { + Self { + accept, + tls_handler: cert_handler, + in_progress: SyncMutex::new(FuturesUnordered::new()), + } + } +} +impl Accept for TlsListener +where + A: Accept + 'static, + A::Metadata: Send + 'static, + for<'a> H: TlsHandler<'a, A> + Clone + Send + 'static, +{ + type Metadata = TlsMetadata; + fn poll_accept( + &mut self, + cx: &mut std::task::Context<'_>, + ) -> Poll> { + self.in_progress.mutate(|in_progress| { + loop { + if !in_progress.is_empty() { + if let Poll::Ready(Some((handler, res))) = in_progress.poll_next_unpin(cx) { + if let Some(res) = res.transpose() { + self.tls_handler = handler; + return Poll::Ready(res); + } + continue; + } + } + + let (metadata, stream) = ready!(self.accept.poll_accept(cx)?); + let mut tls_handler = self.tls_handler.clone(); + let mut fut = async move { + let res = async { + let mut acceptor = LazyConfigAcceptor::new( + Acceptor::default(), + BackTrackingIO::new(stream), + ); + let mut mid: tokio_rustls::StartHandshake> = + match (&mut acceptor).await { + Ok(a) => a, + Err(e) => { + let mut stream = + acceptor.take_io().or_not_found("acceptor io")?; + let (_, buf) = stream.rewind(); + if std::str::from_utf8(buf) + .ok() + .and_then(|buf| { + buf.lines() + .map(|l| l.trim()) + .filter(|l| !l.is_empty()) + .next() + }) + .map_or(false, |buf| { + regex::Regex::new("[A-Z]+ (.+) HTTP/1") + .unwrap() + .is_match(buf) + }) + { + handle_http_on_https(stream).await.log_err(); + + return Ok(None); + } else { + return Err(e).with_kind(ErrorKind::Network); + } + } + }; + let hello = mid.client_hello(); + if let Some(cfg) = tls_handler.get_config(&hello, &metadata).await { + let metadata = TlsMetadata { + inner: metadata, + tls_info: TlsHandshakeInfo { + sni: hello.server_name().map(InternedString::intern), + alpn: hello + .alpn() + .into_iter() + .flatten() + .map(|a| MaybeUtf8String(a.to_vec())) + .collect(), + }, + }; + let buffered = mid.io.stop_buffering(); + mid.io + .write_all(&buffered) + .await + .with_kind(ErrorKind::Network)?; + return Ok(Some(( + metadata, + Box::pin(mid.into_stream(Arc::new(cfg)).await?) as AcceptStream, + ))); + } + + Ok(None) + } + .await; + (tls_handler, res) + } + .boxed(); + match fut.poll_unpin(cx) { + Poll::Pending => { + in_progress.push(fut); + return Poll::Pending; + } + Poll::Ready((handler, res)) => { + if let Some(res) = res.transpose() { + self.tls_handler = handler; + return Poll::Ready(res); + } + } + }; + } + }) + } +} + +async fn handle_http_on_https(stream: impl ReadWriter + Unpin + 'static) -> Result<(), Error> { + use axum::body::Body; + use axum::extract::Request; + use axum::response::Response; + use http::Uri; + + use crate::net::static_server::server_error; + + hyper_util::server::conn::auto::Builder::new(hyper_util::rt::TokioExecutor::new()) + .serve_connection( + hyper_util::rt::TokioIo::new(stream), + hyper_util::service::TowerToHyperService::new(axum::Router::new().fallback( + axum::routing::method_routing::any(move |req: Request| async move { + match async move { + let host = req + .headers() + .get(http::header::HOST) + .and_then(|host| host.to_str().ok()); + if let Some(host) = host { + let uri = Uri::from_parts({ + let mut parts = req.uri().to_owned().into_parts(); + parts.scheme = Some("https".parse()?); + parts.authority = Some(host.parse()?); + parts + })?; + Response::builder() + .status(http::StatusCode::TEMPORARY_REDIRECT) + .header(http::header::LOCATION, uri.to_string()) + .body(Body::default()) + } else { + Response::builder() + .status(http::StatusCode::BAD_REQUEST) + .body(Body::from("Host header required")) + } + } + .await + { + Ok(a) => a, + Err(e) => { + tracing::warn!("Error redirecting http request on ssl port: {e}"); + tracing::error!("{e:?}"); + server_error(Error::new(e, ErrorKind::Network)) + } + } + }), + )), + ) + .await + .map_err(|e| Error::new(color_eyre::eyre::Report::msg(e), ErrorKind::Network)) +} + +pub fn client_config<'a, I: IntoIterator>( + crypto_provider: Arc, + root_certs: I, +) -> Result { + let mut certs = RootCertStore::empty(); + for cert in root_certs { + certs + .add(CertificateDer::from_slice(&cert.to_der()?)) + .with_kind(ErrorKind::OpenSsl)?; + } + Ok(ClientConfig::builder_with_provider(crypto_provider.clone()) + .with_safe_default_protocol_versions() + .with_kind(ErrorKind::OpenSsl)? + .with_root_certificates(certs) + .with_no_client_auth()) +} diff --git a/core/startos/src/net/tor.rs b/core/startos/src/net/tor/arti.rs similarity index 98% rename from core/startos/src/net/tor.rs rename to core/startos/src/net/tor/arti.rs index 8a82cd5e4..1cfe7cfb1 100644 --- a/core/startos/src/net/tor.rs +++ b/core/startos/src/net/tor/arti.rs @@ -6,7 +6,7 @@ use std::sync::{Arc, Weak}; use std::time::{Duration, Instant}; use arti_client::config::onion_service::OnionServiceConfigBuilder; -use arti_client::{DataStream, TorClient, TorClientConfig}; +use arti_client::{TorClient, TorClientConfig}; use base64::Engine; use clap::Parser; use color_eyre::eyre::eyre; @@ -14,7 +14,7 @@ use futures::{FutureExt, StreamExt}; use helpers::NonDetachingJoinHandle; use imbl_value::InternedString; use itertools::Itertools; -use rpc_toolkit::{from_fn_async, Context, Empty, HandlerExt, ParentHandler}; +use rpc_toolkit::{Context, Empty, HandlerExt, ParentHandler, from_fn_async}; use serde::{Deserialize, Serialize}; use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tokio::net::TcpStream; @@ -34,8 +34,8 @@ use crate::util::actor::background::BackgroundJobQueue; use crate::util::future::Until; use crate::util::io::ReadWriter; use crate::util::serde::{ - deserialize_from_str, display_serializable, serialize_display, Base64, HandlerExtSerde, - WithIoFormat, BASE64, + BASE64, Base64, HandlerExtSerde, WithIoFormat, deserialize_from_str, display_serializable, + serialize_display, }; use crate::util::sync::{SyncMutex, SyncRwLock, Watch}; @@ -628,11 +628,7 @@ impl TorController { } else { false }; - if rm { - s.remove(&addr) - } else { - None - } + if rm { s.remove(&addr) } else { None } }) { s.shutdown().await } else { @@ -861,11 +857,11 @@ impl OnionService { }))) } - pub fn proxy_all>>( + pub async fn proxy_all>>( &self, bindings: impl IntoIterator, - ) -> Rcs { - self.0.bindings.mutate(|b| { + ) -> Result { + Ok(self.0.bindings.mutate(|b| { bindings .into_iter() .map(|(port, target)| { @@ -879,7 +875,7 @@ impl OnionService { } }) .collect() - }) + })) } pub fn gc(&self) -> bool { diff --git a/core/startos/src/net/tor/ctor.rs b/core/startos/src/net/tor/ctor.rs new file mode 100644 index 000000000..83011bd36 --- /dev/null +++ b/core/startos/src/net/tor/ctor.rs @@ -0,0 +1,1039 @@ +use std::collections::{BTreeMap, BTreeSet}; +use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4}; +use std::str::FromStr; +use std::sync::atomic::AtomicBool; +use std::sync::{Arc, Weak}; +use std::time::Duration; + +use base64::Engine; +use clap::Parser; +use color_eyre::eyre::eyre; +use futures::future::BoxFuture; +use futures::{FutureExt, TryFutureExt, TryStreamExt}; +use helpers::NonDetachingJoinHandle; +use imbl::OrdMap; +use imbl_value::InternedString; +use lazy_static::lazy_static; +use regex::Regex; +use rpc_toolkit::{Context, Empty, HandlerExt, ParentHandler, from_fn_async}; +use serde::{Deserialize, Serialize}; +use tokio::net::TcpStream; +use tokio::process::Command; +use tokio::sync::{mpsc, oneshot}; +use tokio::time::Instant; +use torut::control::{AsyncEvent, AuthenticatedConn, ConnError}; +use torut::onion::{OnionAddressV3, TorSecretKeyV3}; +use tracing::instrument; +use ts_rs::TS; + +use crate::context::{CliContext, RpcContext}; +use crate::logs::{LogSource, LogsParams, journalctl}; +use crate::prelude::*; +use crate::util::Invoke; +use crate::util::collections::ordmap_retain; +use crate::util::io::{ReadWriter, write_file_atomic}; +use crate::util::serde::{ + BASE64, Base64, HandlerExtSerde, WithIoFormat, deserialize_from_str, display_serializable, + serialize_display, +}; +use crate::util::sync::Watch; + +pub const SYSTEMD_UNIT: &str = "tor@default"; +const STARTING_HEALTH_TIMEOUT: u64 = 120; // 2min + +const TOR_CONTROL: SocketAddr = + SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 1, 1), 9051)); +const TOR_SOCKS: SocketAddr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 1, 1), 9050)); + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct OnionAddress(OnionAddressV3); +impl std::fmt::Display for OnionAddress { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} +impl FromStr for OnionAddress { + type Err = Error; + fn from_str(s: &str) -> Result { + Ok(Self( + s.strip_suffix(".onion") + .unwrap_or(s) + .parse::() + .with_kind(ErrorKind::Tor)?, + )) + } +} +impl Serialize for OnionAddress { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + serialize_display(self, serializer) + } +} +impl<'de> Deserialize<'de> for OnionAddress { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + deserialize_from_str(deserializer) + } +} +impl Ord for OnionAddress { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.0.get_raw_bytes().cmp(&other.0.get_raw_bytes()) + } +} +impl PartialOrd for OnionAddress { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct TorSecretKey(pub TorSecretKeyV3); +impl TorSecretKey { + pub fn onion_address(&self) -> OnionAddress { + OnionAddress(self.0.public().get_onion_address()) + } + pub fn from_bytes(bytes: [u8; 64]) -> Result { + Ok(Self(TorSecretKeyV3::from(bytes))) + } + pub fn generate() -> Self { + Self(TorSecretKeyV3::generate()) + } + pub fn is_valid(&self) -> bool { + let bytes = self.0.as_bytes()[..32].try_into().unwrap(); + curve25519_dalek::scalar::clamp_integer(bytes) == bytes + } +} +impl std::fmt::Display for TorSecretKey { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", BASE64.encode(self.0.as_bytes())) + } +} +impl FromStr for TorSecretKey { + type Err = Error; + fn from_str(s: &str) -> Result { + Self::from_bytes(Base64::<[u8; 64]>::from_str(s)?.0) + } +} +impl Serialize for TorSecretKey { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + serialize_display(self, serializer) + } +} +impl<'de> Deserialize<'de> for TorSecretKey { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + deserialize_from_str(deserializer) + } +} + +#[test] +fn test_generated_is_valid() { + for _ in 0..100 { + assert!(TorSecretKey::generate().is_valid()); + } +} + +#[test] +fn test_tor_key() { + // let key = crate::util::crypto::ed25519_expand_key( + // &hex::decode("c4b1a617bfdbcfb3f31e98c95542ce61718100e81cc6766eeebaa0dab42f0a93") + // .unwrap() + // .try_into() + // .unwrap(), + // ); + let key = + "4FpKpT4GZeEkUvH32AWMsndW+EG3XH46EmSFTh286G4AfG2U/Cc7y7L6k1dW5bl996QGDwe8gnaglq2hR2aD2w" + .parse::() + .unwrap(); + assert_eq!( + InternedString::from_display(&key.onion_address()), + InternedString::from("ja24lucrzgcusm72r2kmiujaa2g6b5o2w4wrwt5crfrhaz2qek5ozhqd.onion") + ); + eprintln!("{:?}", key.0.as_bytes()); + dbg!(key.to_string()); + dbg!(key.0.as_bytes()[0] & 0b111); + dbg!(key.onion_address()); + assert!(key.is_valid()); +} + +#[derive(Default, Deserialize, Serialize)] +pub struct OnionStore(BTreeMap); +impl Map for OnionStore { + type Key = OnionAddress; + type Value = TorSecretKey; + fn key_str(key: &Self::Key) -> Result, Error> { + Self::key_string(key) + } + fn key_string(key: &Self::Key) -> Result { + Ok(InternedString::from_display(key)) + } +} +impl OnionStore { + pub fn new() -> Self { + Self::default() + } + pub fn insert(&mut self, key: TorSecretKey) { + self.0.insert(key.onion_address(), key); + } +} +impl Model { + pub fn new_key(&mut self) -> Result { + let key = TorSecretKey::generate(); + self.insert_key(&key)?; + Ok(key) + } + pub fn insert_key(&mut self, key: &TorSecretKey) -> Result<(), Error> { + self.insert(&key.onion_address(), &key).map(|_| ()) + } + pub fn get_key(&self, address: &OnionAddress) -> Result { + self.as_idx(address) + .or_not_found(lazy_format!("private key for {address}"))? + .de() + } +} +impl std::fmt::Debug for OnionStore { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + struct OnionStoreMap<'a>(&'a BTreeMap); + impl<'a> std::fmt::Debug for OnionStoreMap<'a> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + #[derive(Debug)] + struct KeyFor(#[allow(unused)] OnionAddress); + let mut map = f.debug_map(); + for (k, v) in self.0 { + map.key(k); + map.value(&KeyFor(v.onion_address())); + } + map.finish() + } + } + f.debug_tuple("OnionStore") + .field(&OnionStoreMap(&self.0)) + .finish() + } +} + +enum ErrorLogSeverity { + Fatal { wipe_state: bool }, + Unknown { wipe_state: bool }, +} + +lazy_static! { + static ref LOG_REGEXES: Vec<(Regex, ErrorLogSeverity)> = vec![( + Regex::new("This could indicate a route manipulation attack, network overload, bad local network connectivity, or a bug\\.").unwrap(), + ErrorLogSeverity::Unknown { wipe_state: true } + ),( + Regex::new("died due to an invalid selected path").unwrap(), + ErrorLogSeverity::Fatal { wipe_state: false } + ),( + Regex::new("Tor has not observed any network activity for the past").unwrap(), + ErrorLogSeverity::Unknown { wipe_state: false } + )]; + static ref PROGRESS_REGEX: Regex = Regex::new("PROGRESS=([0-9]+)").unwrap(); +} + +pub fn tor_api() -> ParentHandler { + ParentHandler::new() + .subcommand( + "list-services", + from_fn_async(list_services) + .with_display_serializable() + .with_custom_display_fn(|handle, result| display_services(handle.params, result)) + .with_about("Display Tor V3 Onion Addresses") + .with_call_remote::(), + ) + .subcommand("logs", logs().with_about("Display Tor logs")) + .subcommand( + "logs", + from_fn_async(crate::logs::cli_logs::) + .no_display() + .with_about("Display Tor logs"), + ) + .subcommand( + "reset", + from_fn_async(reset) + .no_display() + .with_about("Reset Tor daemon") + .with_call_remote::(), + ) + .subcommand( + "key", + key::().with_about("Manage the onion service key store"), + ) +} + +pub fn key() -> ParentHandler { + ParentHandler::new() + .subcommand( + "generate", + from_fn_async(generate_key) + .with_about("Generate an onion service key and add it to the key store") + .with_call_remote::(), + ) + .subcommand( + "add", + from_fn_async(add_key) + .with_about("Add an onion service key to the key store") + .with_call_remote::(), + ) + .subcommand( + "list", + from_fn_async(list_keys) + .with_custom_display_fn(|_, res| { + for addr in res { + println!("{addr}"); + } + Ok(()) + }) + .with_about("List onion services with keys in the key store") + .with_call_remote::(), + ) +} + +pub async fn generate_key(ctx: RpcContext) -> Result { + ctx.db + .mutate(|db| { + Ok(db + .as_private_mut() + .as_key_store_mut() + .as_onion_mut() + .new_key()? + .onion_address()) + }) + .await + .result +} + +#[derive(Deserialize, Serialize, Parser)] +pub struct AddKeyParams { + pub key: Base64<[u8; 64]>, +} + +pub async fn add_key( + ctx: RpcContext, + AddKeyParams { key }: AddKeyParams, +) -> Result { + let key = TorSecretKey::from_bytes(key.0)?; + ctx.db + .mutate(|db| { + db.as_private_mut() + .as_key_store_mut() + .as_onion_mut() + .insert_key(&key) + }) + .await + .result?; + Ok(key.onion_address()) +} + +pub async fn list_keys(ctx: RpcContext) -> Result, Error> { + ctx.db + .peek() + .await + .into_private() + .into_key_store() + .into_onion() + .keys() +} + +#[derive(Deserialize, Serialize, Parser, TS)] +#[serde(rename_all = "camelCase")] +#[command(rename_all = "kebab-case")] +pub struct ResetParams { + #[arg(name = "wipe-state", short = 'w', long = "wipe-state")] + wipe_state: bool, + reason: String, +} + +pub async fn reset( + ctx: RpcContext, + ResetParams { reason, wipe_state }: ResetParams, +) -> Result<(), Error> { + ctx.net_controller + .tor + .reset(wipe_state, Error::new(eyre!("{reason}"), ErrorKind::Tor)) + .await +} + +pub fn display_services( + params: WithIoFormat, + services: Vec, +) -> Result<(), Error> { + use prettytable::*; + + if let Some(format) = params.format { + return display_serializable(format, services); + } + + let mut table = Table::new(); + for service in services { + let row = row![&service.to_string()]; + table.add_row(row); + } + table.print_tty(false)?; + Ok(()) +} + +pub async fn list_services(ctx: RpcContext, _: Empty) -> Result, Error> { + ctx.net_controller.tor.list_services().await +} + +pub fn logs() -> ParentHandler { + crate::logs::logs::(|_: &RpcContext, _| async { + Ok(LogSource::Unit(SYSTEMD_UNIT)) + }) +} + +fn event_handler(_event: AsyncEvent<'static>) -> BoxFuture<'static, Result<(), ConnError>> { + async move { Ok(()) }.boxed() +} + +#[derive(Clone)] +pub struct TorController(Arc); +impl TorController { + pub fn new() -> Result { + Ok(TorController(Arc::new(TorControl::new( + TOR_CONTROL, + TOR_SOCKS, + )))) + } + + pub fn service(&self, key: TorSecretKey) -> Result { + Ok(TorService { + services: self.0.services.clone(), + key, + }) + } + + pub async fn gc(&self, addr: Option) -> Result<(), Error> { + self.0.services.send_if_modified(|services| { + let mut changed = false; + let mut gc = |bindings: &mut OrdMap>>| { + ordmap_retain(bindings, |_, targets| { + let start_len = targets.len(); + targets.retain(|_, rc| rc.strong_count() > 0); + changed |= start_len != targets.len(); + !targets.is_empty() + }); + if bindings.is_empty() { + changed = true; + false + } else { + true + } + }; + if let Some(addr) = addr { + if !if let Some((_, bindings, needs_sync)) = services.get_mut(&addr) { + let keep = gc(bindings); + if !keep { + *needs_sync = Some(SyncState::Remove); + } + keep + } else { + true + } { + services.remove(&addr); + } + } else { + services.retain(|_, (_, bindings, _)| gc(bindings)); + } + changed + }); + Ok(()) + } + + pub async fn reset(&self, wipe_state: bool, context: Error) -> Result<(), Error> { + self.0 + .send + .send(TorCommand::Reset { + wipe_state, + context, + }) + .ok() + .ok_or_else(|| Error::new(eyre!("TorControl died"), ErrorKind::Tor)) + } + + pub async fn list_services(&self) -> Result, Error> { + let (reply, res) = oneshot::channel(); + self.0 + .send + .send(TorCommand::GetInfo { + query: "onions/current".into(), + reply, + }) + .ok() + .ok_or_else(|| Error::new(eyre!("TorControl died"), ErrorKind::Tor))?; + res.await + .ok() + .ok_or_else(|| Error::new(eyre!("TorControl died"), ErrorKind::Tor))?? + .lines() + .map(|l| l.trim()) + .filter(|l| !l.is_empty()) + .map(|l| l.parse::().with_kind(ErrorKind::Tor)) + .collect() + } + + pub async fn connect_onion( + &self, + addr: &OnionAddress, + port: u16, + ) -> Result, Error> { + if let Some(target) = self.0.services.peek(|s| { + s.get(addr).and_then(|(_, bindings, _)| { + bindings.get(&port).and_then(|b| { + b.iter() + .find(|(_, rc)| rc.strong_count() > 0) + .map(|(a, _)| *a) + }) + }) + }) { + tracing::debug!("Resolving {addr} internally to {target}"); + Ok(Box::new( + TcpStream::connect(target) + .await + .with_kind(ErrorKind::Network)?, + )) + } else { + let mut stream = TcpStream::connect(TOR_SOCKS) + .await + .with_kind(ErrorKind::Tor)?; + socks5_impl::client::connect(&mut stream, (addr.to_string(), port), None) + .await + .with_kind(ErrorKind::Tor)?; + Ok(Box::new(stream)) + } + } +} + +#[derive(Clone, Copy, PartialEq, Eq)] +enum SyncState { + Add, + Update, + Remove, +} + +pub struct TorService { + services: Watch< + BTreeMap< + OnionAddress, + ( + TorSecretKey, + OrdMap>>, + Option, + ), + >, + >, + key: TorSecretKey, +} + +impl TorService { + pub fn proxy_all>>( + &self, + bindings: impl IntoIterator, + ) -> Rcs { + self.services.send_modify(|services| { + let (_, entry, needs_sync) = services + .entry(self.key.onion_address()) + .or_insert_with(|| (self.key.clone(), OrdMap::new(), Some(SyncState::Add))); + let rcs = bindings + .into_iter() + .map(|(external, target)| { + let binding = entry.entry(external).or_default(); + let target = binding.entry(target).or_default(); + let rc = if let Some(rc) = Weak::upgrade(&*target) { + rc + } else { + if needs_sync.is_none() { + *needs_sync = Some(SyncState::Update); + } + Arc::new(()) + }; + *target = Arc::downgrade(&rc); + rc + }) + .collect(); + + rcs + }) + } +} + +type AuthenticatedConnection = AuthenticatedConn< + TcpStream, + Box) -> BoxFuture<'static, Result<(), ConnError>> + Send + Sync>, +>; + +enum TorCommand { + GetInfo { + query: String, + reply: oneshot::Sender>, + }, + Reset { + wipe_state: bool, + context: Error, + }, +} + +#[instrument(skip_all)] +async fn torctl( + tor_control: SocketAddr, + tor_socks: SocketAddr, + recv: &mut mpsc::UnboundedReceiver, + services: &mut Watch< + BTreeMap< + OnionAddress, + ( + TorSecretKey, + OrdMap>>, + Option, + ), + >, + >, + wipe_state: &AtomicBool, + health_timeout: &mut Duration, +) -> Result<(), Error> { + let bootstrap = async { + if Command::new("systemctl") + .arg("is-active") + .arg("--quiet") + .arg("tor") + .invoke(ErrorKind::Tor) + .await + .is_ok() + { + Command::new("systemctl") + .arg("stop") + .arg("tor") + .invoke(ErrorKind::Tor) + .await?; + for _ in 0..30 { + if TcpStream::connect(tor_control).await.is_err() { + break; + } + tokio::time::sleep(Duration::from_secs(1)).await; + } + if TcpStream::connect(tor_control).await.is_ok() { + return Err(Error::new( + eyre!("Tor is failing to shut down"), + ErrorKind::Tor, + )); + } + } + if wipe_state.load(std::sync::atomic::Ordering::SeqCst) { + tokio::fs::remove_dir_all("/var/lib/tor").await?; + wipe_state.store(false, std::sync::atomic::Ordering::SeqCst); + } + write_file_atomic( + "/etc/tor/torrc", + format!("SocksPort {TOR_SOCKS}\nControlPort {TOR_CONTROL}\nCookieAuthentication 1\n"), + ) + .await?; + tokio::fs::create_dir_all("/var/lib/tor").await?; + Command::new("chown") + .arg("-R") + .arg("debian-tor") + .arg("/var/lib/tor") + .invoke(ErrorKind::Filesystem) + .await?; + Command::new("systemctl") + .arg("start") + .arg("tor") + .invoke(ErrorKind::Tor) + .await?; + + let logs = journalctl( + LogSource::Unit(SYSTEMD_UNIT), + Some(0), + None, + Some("0"), + false, + true, + ) + .await?; + + let mut tcp_stream = None; + for _ in 0..60 { + if let Ok(conn) = TcpStream::connect(tor_control).await { + tcp_stream = Some(conn); + break; + } + tokio::time::sleep(Duration::from_secs(1)).await; + } + let tcp_stream = tcp_stream.ok_or_else(|| { + Error::new(eyre!("Timed out waiting for tor to start"), ErrorKind::Tor) + })?; + tracing::info!("Tor is started"); + + let mut conn = torut::control::UnauthenticatedConn::new(tcp_stream); + let auth = conn + .load_protocol_info() + .await? + .make_auth_data()? + .ok_or_else(|| eyre!("Cookie Auth Not Available")) + .with_kind(crate::ErrorKind::Tor)?; + conn.authenticate(&auth).await?; + let mut connection: AuthenticatedConnection = conn.into_authenticated().await; + connection.set_async_event_handler(Some(Box::new(|event| event_handler(event)))); + + let mut bootstrapped = false; + let mut last_increment = (String::new(), Instant::now()); + for _ in 0..300 { + match connection.get_info("status/bootstrap-phase").await { + Ok(a) => { + if a.contains("TAG=done") { + bootstrapped = true; + break; + } + if let Some(p) = PROGRESS_REGEX.captures(&a) { + if let Some(p) = p.get(1) { + if p.as_str() != &*last_increment.0 { + last_increment = (p.as_str().into(), Instant::now()); + } + } + } + } + Err(e) => { + let e = Error::from(e); + tracing::error!("{}", e); + tracing::debug!("{:?}", e); + } + } + if last_increment.1.elapsed() > Duration::from_secs(30) { + return Err(Error::new( + eyre!("Tor stuck bootstrapping at {}%", last_increment.0), + ErrorKind::Tor, + )); + } + tokio::time::sleep(Duration::from_secs(1)).await; + } + if !bootstrapped { + return Err(Error::new( + eyre!("Timed out waiting for tor to bootstrap"), + ErrorKind::Tor, + )); + } + Ok((connection, logs)) + }; + let pre_handler = async { + while let Some(command) = recv.recv().await { + match command { + TorCommand::GetInfo { reply, .. } => { + reply + .send(Err(Error::new( + eyre!("Tor has not finished bootstrapping..."), + ErrorKind::Tor, + ))) + .unwrap_or_default(); + } + TorCommand::Reset { + wipe_state: new_wipe_state, + context, + } => { + wipe_state.fetch_or(new_wipe_state, std::sync::atomic::Ordering::SeqCst); + return Err(context); + } + } + } + Ok(()) + }; + + let (mut connection, mut logs) = tokio::select! { + res = bootstrap => res?, + res = pre_handler => return res, + }; + + let hck_key = TorSecretKeyV3::generate(); + connection + .add_onion_v3( + &hck_key, + false, + false, + false, + None, + &mut [(80, SocketAddr::from(([127, 0, 0, 1], 80)))].iter(), + ) + .await?; + + let handler = async { + loop { + let recv = recv.recv(); + tokio::pin!(recv); + let mut changed = services.changed().boxed(); + + match futures::future::select(recv, &mut changed).await { + futures::future::Either::Left((Some(command), _)) => match command { + TorCommand::GetInfo { query, reply } => { + reply + .send(connection.get_info(&query).await.with_kind(ErrorKind::Tor)) + .unwrap_or_default(); + } + TorCommand::Reset { + wipe_state: new_wipe_state, + context, + } => { + wipe_state.fetch_or(new_wipe_state, std::sync::atomic::Ordering::SeqCst); + return Err(context); + } + }, + futures::future::Either::Left((None, _)) => break, + futures::future::Either::Right(_) => { + drop(changed); + let to_add = services.peek_and_mark_seen(|services| { + services + .iter() + .filter(|(_, (_, _, s))| s.is_some()) + .map(|(k, v)| (k.clone(), (*v).clone())) + .collect::>() + }); + + for (addr, (key, bindings, state)) in &to_add { + if matches!(state, Some(SyncState::Update) | Some(SyncState::Remove)) { + connection + .del_onion(&addr.0.get_address_without_dot_onion()) + .await + .with_kind(ErrorKind::Tor)?; + } + let bindings = bindings + .iter() + .filter_map(|(external, targets)| { + targets + .iter() + .find(|(_, rc)| rc.strong_count() > 0) + .map(|(target, _)| (*external, *target)) + }) + .collect::>(); + if !bindings.is_empty() { + connection + .add_onion_v3( + &key.0, + false, + false, + false, + None, + &mut bindings.iter(), + ) + .await?; + } + } + services.send_if_modified(|services| { + for (addr, (_, bindings_a, _)) in to_add { + if let Some((_, bindings_b, needs_sync)) = services.get_mut(&addr) { + if OrdMap::ptr_eq(&bindings_a, bindings_b) + || bindings_a.len() == bindings_b.len() + && bindings_a.iter().zip(bindings_b.iter()).all( + |((a_port, a), (b_port, b))| { + a_port == b_port + && a.len() == b.len() + && a.keys().zip(b.keys()).all(|(a, b)| a == b) + }, + ) + { + *needs_sync = None; + } else { + *needs_sync = Some(SyncState::Update); + } + } + } + false + }); + } + } + } + + Ok(()) + }; + let log_parser = async { + while let Some(log) = logs.try_next().await? { + for (regex, severity) in &*LOG_REGEXES { + if regex.is_match(&log.message) { + let (check, wipe_state) = match severity { + ErrorLogSeverity::Fatal { wipe_state } => (false, *wipe_state), + ErrorLogSeverity::Unknown { wipe_state } => (true, *wipe_state), + }; + let addr = hck_key.public().get_onion_address().to_string(); + if !check + || TcpStream::connect(tor_socks) + .map_err(|e| Error::new(e, ErrorKind::Tor)) + .and_then(|mut tor_socks| async move { + tokio::time::timeout( + Duration::from_secs(30), + socks5_impl::client::connect(&mut tor_socks, (addr, 80), None) + .map_err(|e| Error::new(e, ErrorKind::Tor)), + ) + .map_err(|e| Error::new(e, ErrorKind::Tor)) + .await? + }) + .await + .with_ctx(|_| (ErrorKind::Tor, "Tor is confirmed to be down")) + .log_err() + .is_some() + { + if wipe_state { + Command::new("systemctl") + .arg("stop") + .arg("tor") + .invoke(ErrorKind::Tor) + .await?; + tokio::fs::remove_dir_all("/var/lib/tor").await?; + } + return Err(Error::new(eyre!("{}", log.message), ErrorKind::Tor)); + } + } + } + } + Err(Error::new(eyre!("Log stream terminated"), ErrorKind::Tor)) + }; + let health_checker = async { + let mut last_success = Instant::now(); + loop { + tokio::time::sleep(Duration::from_secs(30)).await; + let addr = hck_key.public().get_onion_address().to_string(); + if TcpStream::connect(tor_socks) + .map_err(|e| Error::new(e, ErrorKind::Tor)) + .and_then(|mut tor_socks| async move { + tokio::time::timeout( + Duration::from_secs(30), + socks5_impl::client::connect(&mut tor_socks, (addr, 80), None) + .map_err(|e| Error::new(e, ErrorKind::Tor)), + ) + .map_err(|e| Error::new(e, ErrorKind::Tor)) + .await + }) + .await + .is_err() + { + if last_success.elapsed() > *health_timeout { + let err = Error::new( + eyre!( + "Tor health check failed for longer than current timeout ({health_timeout:?})" + ), + crate::ErrorKind::Tor, + ); + *health_timeout *= 2; + wipe_state.store(true, std::sync::atomic::Ordering::SeqCst); + return Err(err); + } + } else { + last_success = Instant::now(); + } + } + }; + + tokio::select! { + res = handler => res?, + res = log_parser => res?, + res = health_checker => res?, + } + + Ok(()) +} + +struct TorControl { + _thread: NonDetachingJoinHandle<()>, + send: mpsc::UnboundedSender, + services: Watch< + BTreeMap< + OnionAddress, + ( + TorSecretKey, + OrdMap>>, + Option, + ), + >, + >, +} +impl TorControl { + pub fn new(tor_control: SocketAddr, tor_socks: SocketAddr) -> Self { + let (send, mut recv) = mpsc::unbounded_channel(); + let services = Watch::new(BTreeMap::new()); + let mut thread_services = services.clone(); + Self { + _thread: tokio::spawn(async move { + let wipe_state = AtomicBool::new(false); + let mut health_timeout = Duration::from_secs(STARTING_HEALTH_TIMEOUT); + while let Err(e) = torctl( + tor_control, + tor_socks, + &mut recv, + &mut thread_services, + &wipe_state, + &mut health_timeout, + ) + .await + { + tracing::error!("{e}: Restarting tor"); + tracing::debug!("{e:?}"); + } + tracing::info!("TorControl is shut down.") + }) + .into(), + send, + services, + } + } +} + +#[tokio::test] +#[ignore] +async fn test_connection() { + let mut conn = torut::control::UnauthenticatedConn::new( + TcpStream::connect(SocketAddr::from(([127, 0, 0, 1], 9051))) + .await + .unwrap(), + ); + let auth = conn + .load_protocol_info() + .await + .unwrap() + .make_auth_data() + .unwrap() + .ok_or_else(|| eyre!("Cookie Auth Not Available")) + .with_kind(crate::ErrorKind::Tor) + .unwrap(); + conn.authenticate(&auth).await.unwrap(); + let mut connection: AuthenticatedConn< + TcpStream, + fn(AsyncEvent<'static>) -> BoxFuture<'static, Result<(), ConnError>>, + > = conn.into_authenticated().await; + let tor_key = torut::onion::TorSecretKeyV3::generate(); + connection.get_conf("SocksPort").await.unwrap(); + connection + .add_onion_v3( + &tor_key, + false, + false, + false, + None, + &mut [(443_u16, SocketAddr::from(([127, 0, 0, 1], 8443)))].iter(), + ) + .await + .unwrap(); + connection + .del_onion( + &tor_key + .public() + .get_onion_address() + .get_address_without_dot_onion(), + ) + .await + .unwrap(); + connection + .add_onion_v3( + &tor_key, + false, + false, + false, + None, + &mut [(8443_u16, SocketAddr::from(([127, 0, 0, 1], 8443)))].iter(), + ) + .await + .unwrap(); +} diff --git a/core/startos/src/net/tor/mod.rs b/core/startos/src/net/tor/mod.rs new file mode 100644 index 000000000..d4d5c8007 --- /dev/null +++ b/core/startos/src/net/tor/mod.rs @@ -0,0 +1,10 @@ +#[cfg(feature = "arti")] +mod arti; + +#[cfg(not(feature = "arti"))] +mod ctor; + +#[cfg(feature = "arti")] +pub use arti::{OnionAddress, OnionStore, TorController, TorSecretKey, tor_api}; +#[cfg(not(feature = "arti"))] +pub use ctor::{OnionAddress, OnionStore, TorController, TorSecretKey, tor_api}; diff --git a/core/startos/src/net/tunnel.rs b/core/startos/src/net/tunnel.rs index 7702f7544..b4b89783d 100644 --- a/core/startos/src/net/tunnel.rs +++ b/core/startos/src/net/tunnel.rs @@ -2,16 +2,17 @@ use clap::Parser; use imbl_value::InternedString; use models::GatewayId; use patch_db::json_ptr::JsonPointer; -use rpc_toolkit::{from_fn_async, Context, HandlerExt, ParentHandler}; +use rpc_toolkit::{Context, HandlerExt, ParentHandler, from_fn_async}; use serde::{Deserialize, Serialize}; use tokio::process::Command; use ts_rs::TS; use crate::context::{CliContext, RpcContext}; use crate::db::model::public::{NetworkInterfaceInfo, NetworkInterfaceType}; +use crate::net::host::all_hosts; use crate::prelude::*; -use crate::util::io::{write_file_atomic, TmpDir}; use crate::util::Invoke; +use crate::util::io::{TmpDir, write_file_atomic}; pub fn tunnel_api() -> ParentHandler { ParentHandler::new() @@ -125,14 +126,44 @@ pub async fn remove_tunnel( return Ok(()); }; - if existing.as_device_type().de()? != Some(NetworkInterfaceType::Wireguard) { + if existing.as_deref().as_device_type().de()? != Some(NetworkInterfaceType::Wireguard) { return Err(Error::new( eyre!("network interface {id} is not a proxy"), ErrorKind::InvalidRequest, )); } + ctx.db + .mutate(|db| { + for host in all_hosts(db) { + let host = host?; + host.as_public_domains_mut() + .mutate(|p| Ok(p.retain(|_, v| v.gateway != id)))?; + } + + Ok(()) + }) + .await + .result?; + ctx.net_controller.net_iface.delete_iface(&id).await?; + ctx.db + .mutate(|db| { + for host in all_hosts(db) { + let host = host?; + host.as_bindings_mut().mutate(|b| { + Ok(b.values_mut().for_each(|v| { + v.net.private_disabled.remove(&id); + v.net.public_enabled.remove(&id); + })) + })?; + } + + Ok(()) + }) + .await + .result?; + Ok(()) } diff --git a/core/startos/src/net/utils.rs b/core/startos/src/net/utils.rs index 98407c400..18c2c3705 100644 --- a/core/startos/src/net/utils.rs +++ b/core/startos/src/net/utils.rs @@ -1,3 +1,4 @@ +use std::collections::BTreeMap; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV6}; use std::path::Path; @@ -7,13 +8,56 @@ use futures::stream::BoxStream; use futures::{StreamExt, TryStreamExt}; use imbl_value::InternedString; use ipnet::{IpNet, Ipv4Net, Ipv6Net}; +use models::GatewayId; use nix::net::if_::if_nametoindex; use tokio::net::{TcpListener, TcpStream}; use tokio::process::Command; +use crate::db::model::public::{IpInfo, NetworkInterfaceType}; use crate::prelude::*; use crate::util::Invoke; +pub async fn load_ip_info() -> Result, Error> { + let output = String::from_utf8( + Command::new("ip") + .arg("-o") + .arg("addr") + .arg("show") + .invoke(crate::ErrorKind::Network) + .await?, + )?; + + let err_fn = || { + Error::new( + eyre!("malformed output from `ip`"), + crate::ErrorKind::Network, + ) + }; + + let mut res = BTreeMap::::new(); + + for line in output.lines() { + let split = line.split_ascii_whitespace().collect::>(); + let iface = GatewayId::from(InternedString::from(*split.get(1).ok_or_else(&err_fn)?)); + let subnet: IpNet = split.get(3).ok_or_else(&err_fn)?.parse()?; + let ip_info = res.entry(iface.clone()).or_default(); + ip_info.name = iface.into(); + ip_info.scope_id = split + .get(0) + .ok_or_else(&err_fn)? + .strip_suffix(":") + .ok_or_else(&err_fn)? + .parse()?; + ip_info.subnets.insert(subnet); + } + + for (id, ip_info) in res.iter_mut() { + ip_info.device_type = probe_iface_type(id.as_str()).await; + } + + Ok(res) +} + pub fn ipv6_is_link_local(addr: Ipv6Addr) -> bool { (addr.segments()[0] & 0xffc0) == 0xfe80 } @@ -75,6 +119,22 @@ pub async fn get_iface_ipv6_addr(iface: &str) -> Result Option { + match tokio::fs::read_to_string(Path::new("/sys/class/net").join(iface).join("uevent")) + .await + .ok()? + .lines() + .find_map(|l| l.strip_prefix("DEVTYPE=")) + { + Some("wlan") => Some(NetworkInterfaceType::Wireless), + Some("bridge") => Some(NetworkInterfaceType::Bridge), + Some("wireguard") => Some(NetworkInterfaceType::Wireguard), + None if iface_is_physical(iface).await => Some(NetworkInterfaceType::Ethernet), + None if iface_is_loopback(iface).await => Some(NetworkInterfaceType::Loopback), + _ => None, + } +} + pub async fn iface_is_physical(iface: &str) -> bool { tokio::fs::metadata(Path::new("/sys/class/net").join(iface).join("device")) .await @@ -87,6 +147,19 @@ pub async fn iface_is_wireless(iface: &str) -> bool { .is_ok() } +pub async fn iface_is_bridge(iface: &str) -> bool { + tokio::fs::metadata(Path::new("/sys/class/net").join(iface).join("bridge")) + .await + .is_ok() +} + +pub async fn iface_is_loopback(iface: &str) -> bool { + tokio::fs::read_to_string(Path::new("/sys/class/net").join(iface).join("type")) + .await + .ok() + .map_or(false, |x| x.trim() == "772") +} + pub fn list_interfaces() -> BoxStream<'static, Result> { try_stream! { let mut ifaces = tokio::fs::read_dir("/sys/class/net").await?; diff --git a/core/startos/src/net/vhost.rs b/core/startos/src/net/vhost.rs index 40fb1441c..80c3325fd 100644 --- a/core/startos/src/net/vhost.rs +++ b/core/startos/src/net/vhost.rs @@ -1,51 +1,48 @@ +use std::any::Any; use std::collections::{BTreeMap, BTreeSet}; use std::net::{IpAddr, SocketAddr}; use std::sync::{Arc, Weak}; +use std::task::{Poll, ready}; -use async_acme::acme::{ACME_TLS_ALPN_NAME, Identifier}; -use axum::body::Body; -use axum::extract::Request; -use axum::response::Response; +use async_acme::acme::ACME_TLS_ALPN_NAME; use color_eyre::eyre::eyre; use futures::FutureExt; +use futures::future::BoxFuture; use helpers::NonDetachingJoinHandle; -use http::Uri; -use imbl::OrdMap; -use imbl_value::InternedString; -use itertools::Itertools; -use models::{GatewayId, ResultExt}; +use imbl_value::{InOMap, InternedString}; +use models::ResultExt; use rpc_toolkit::{Context, HandlerArgs, HandlerExt, ParentHandler, from_fn}; use serde::{Deserialize, Serialize}; -use tokio::io::AsyncWriteExt; use tokio::net::TcpStream; -use tokio::sync::watch; +use tokio_rustls::TlsConnector; use tokio_rustls::rustls::crypto::CryptoProvider; -use tokio_rustls::rustls::pki_types::{ - CertificateDer, PrivateKeyDer, PrivatePkcs8KeyDer, ServerName, -}; -use tokio_rustls::rustls::server::{Acceptor, ResolvesServerCert}; -use tokio_rustls::rustls::sign::CertifiedKey; -use tokio_rustls::rustls::{RootCertStore, ServerConfig}; -use tokio_rustls::{LazyConfigAcceptor, TlsConnector}; -use tokio_stream::StreamExt; -use tokio_stream::wrappers::WatchStream; +use tokio_rustls::rustls::pki_types::ServerName; +use tokio_rustls::rustls::server::ClientHello; +use tokio_rustls::rustls::{ClientConfig, ServerConfig}; use tracing::instrument; use ts_rs::TS; +use visit_rs::Visit; use crate::context::{CliContext, RpcContext}; use crate::db::model::Database; -use crate::db::model::public::NetworkInterfaceInfo; -use crate::net::acme::{AcmeCertCache, AcmeProvider}; -use crate::net::gateway::{ - Accepted, AnyFilter, DynInterfaceFilter, InterfaceFilter, NetworkInterfaceController, - NetworkInterfaceListener, +use crate::db::model::public::AcmeSettings; +use crate::db::{DbAccessByKey, DbAccessMut}; +use crate::net::acme::{ + AcmeCertStore, AcmeProvider, AcmeTlsAlpnCache, AcmeTlsHandler, GetAcmeProvider, }; -use crate::net::static_server::server_error; +use crate::net::gateway::{ + AnyFilter, BindTcp, DynInterfaceFilter, GatewayInfo, InterfaceFilter, + NetworkInterfaceController, NetworkInterfaceListener, +}; +use crate::net::ssl::{CertStore, RootCaTlsHandler}; +use crate::net::tls::{ + ChainedHandler, TlsHandlerWrapper, TlsListener, TlsMetadata, WrapTlsHandler, +}; +use crate::net::web_server::{Accept, AcceptStream, ExtractVisitor, TcpMetadata, extract}; use crate::prelude::*; use crate::util::collections::EqSet; -use crate::util::io::BackTrackingIO; use crate::util::serde::{HandlerExtSerde, MaybeUtf8String, display_serializable}; -use crate::util::sync::SyncMutex; +use crate::util::sync::{SyncMutex, Watch}; pub fn vhost_api() -> ParentHandler { ParentHandler::new().subcommand( @@ -61,8 +58,7 @@ pub fn vhost_api() -> ParentHandler { } let mut table = Table::new(); - table - .add_row(row![bc => "FROM", "TO", "GATEWAYS", "ACME", "CONNECT SSL", "ACTIVE"]); + table.add_row(row![bc => "FROM", "TO", "ACTIVE"]); for (external, targets) in res { for (host, targets) in targets { @@ -73,10 +69,7 @@ pub fn vhost_api() -> ParentHandler { host.as_ref().map(|s| &**s).unwrap_or("*"), external.0 ), - target.addr, - target.gateways.iter().join(", "), - target.acme.as_ref().map(|a| a.0.as_str()).unwrap_or("NONE"), - target.connect_ssl.is_ok(), + target, idx == 0 ]); } @@ -91,30 +84,26 @@ pub fn vhost_api() -> ParentHandler { ) } -#[derive(Debug)] -struct SingleCertResolver(Arc); -impl ResolvesServerCert for SingleCertResolver { - fn resolve(&self, _: tokio_rustls::rustls::server::ClientHello) -> Option> { - Some(self.0.clone()) - } -} - // not allowed: <=1024, >=32768, 5355, 5432, 9050, 6010, 9051, 5353 pub struct VHostController { db: TypedPatchDb, interfaces: Arc, crypto_provider: Arc, - acme_tls_alpn_cache: AcmeTlsAlpnCache, - servers: SyncMutex>, + acme_cache: AcmeTlsAlpnCache, + servers: SyncMutex>>, } impl VHostController { - pub fn new(db: TypedPatchDb, interfaces: Arc) -> Self { + pub fn new( + db: TypedPatchDb, + interfaces: Arc, + crypto_provider: Arc, + ) -> Self { Self { db, interfaces, - crypto_provider: Arc::new(tokio_rustls::rustls::crypto::ring::default_provider()), - acme_tls_alpn_cache: Arc::new(SyncMutex::new(BTreeMap::new())), + crypto_provider, + acme_cache: Arc::new(SyncMutex::new(BTreeMap::new())), servers: SyncMutex::new(BTreeMap::new()), } } @@ -123,19 +112,18 @@ impl VHostController { &self, hostname: Option, external: u16, - target: TargetInfo, + target: DynVHostTarget, ) -> Result, Error> { self.servers.mutate(|writable| { let server = if let Some(server) = writable.remove(&external) { server } else { VHostServer::new( - external, + self.interfaces.watcher.bind(BindTcp, external)?, self.db.clone(), - self.interfaces.clone(), self.crypto_provider.clone(), - self.acme_tls_alpn_cache.clone(), - )? + self.acme_cache.clone(), + ) }; let rc = server.add(hostname, target); writable.insert(external, server); @@ -145,27 +133,26 @@ impl VHostController { pub fn dump_table( &self, - ) -> BTreeMap, BTreeMap>, EqSet>> - { + ) -> BTreeMap, BTreeMap>, EqSet>> { let ip_info = self.interfaces.watcher.ip_info(); self.servers.peek(|s| { s.iter() .map(|(k, v)| { ( JsonKey::new(*k), - v.mapping - .borrow() - .iter() - .map(|(k, v)| { - ( - JsonKey::new(k.clone()), - v.iter() - .filter(|(_, v)| v.strong_count() > 0) - .map(|(k, _)| ShowTargetInfo::new(k.clone(), &ip_info)) - .collect(), - ) - }) - .collect(), + v.mapping.peek(|m| { + m.iter() + .map(|(k, v)| { + ( + JsonKey::new(k.clone()), + v.iter() + .filter(|(_, v)| v.strong_count() > 0) + .map(|(k, _)| format!("{k:?}")) + .collect(), + ) + }) + .collect() + }), ) }) .collect() @@ -185,42 +172,181 @@ impl VHostController { } } -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] -pub struct TargetInfo { +pub trait VHostTarget: std::fmt::Debug + Eq { + type PreprocessRes: Send + 'static; + #[allow(unused_variables)] + fn filter(&self, metadata: &::Metadata) -> bool { + true + } + fn acme(&self) -> Option<&AcmeProvider> { + None + } + fn preprocess<'a>( + &'a self, + prev: ServerConfig, + hello: &'a ClientHello<'a>, + metadata: &'a ::Metadata, + ) -> impl Future> + Send + 'a; + fn handle_stream(&self, stream: AcceptStream, prev: Self::PreprocessRes); +} + +pub trait DynVHostTargetT: std::fmt::Debug + Any { + fn filter(&self, metadata: &::Metadata) -> bool; + fn acme(&self) -> Option<&AcmeProvider>; + fn preprocess<'a>( + &'a self, + prev: ServerConfig, + hello: &'a ClientHello<'a>, + metadata: &'a ::Metadata, + ) -> BoxFuture<'a, Option<(ServerConfig, Box)>>; + fn handle_stream(&self, stream: AcceptStream, prev: Box); + fn eq(&self, other: &dyn DynVHostTargetT) -> bool; +} +impl + 'static> DynVHostTargetT for T { + fn filter(&self, metadata: &::Metadata) -> bool { + VHostTarget::filter(self, metadata) + } + fn acme(&self) -> Option<&AcmeProvider> { + VHostTarget::acme(self) + } + fn preprocess<'a>( + &'a self, + prev: ServerConfig, + hello: &'a ClientHello<'a>, + metadata: &'a ::Metadata, + ) -> BoxFuture<'a, Option<(ServerConfig, Box)>> { + VHostTarget::preprocess(self, prev, hello, metadata) + .map(|o| o.map(|(cfg, res)| (cfg, Box::new(res) as Box))) + .boxed() + } + fn handle_stream(&self, stream: AcceptStream, prev: Box) { + if let Ok(prev) = prev.downcast() { + VHostTarget::handle_stream(self, stream, *prev); + } + } + fn eq(&self, other: &dyn DynVHostTargetT) -> bool { + Some(self) == (other as &dyn Any).downcast_ref() + } +} + +pub struct DynVHostTarget(Arc + Send + Sync>); +impl DynVHostTarget { + pub fn new + Send + Sync + 'static>(target: T) -> Self { + Self(Arc::new(target)) + } +} +impl Clone for DynVHostTarget { + fn clone(&self) -> Self { + Self(self.0.clone()) + } +} +impl std::fmt::Debug for DynVHostTarget { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.0.fmt(f) + } +} +impl PartialEq for DynVHostTarget { + fn eq(&self, other: &Self) -> bool { + self.0.eq(&*other.0) + } +} +impl Eq for DynVHostTarget {} +struct Preprocessed(DynVHostTarget, Box); +impl DynVHostTarget { + async fn into_preprocessed( + self, + prev: ServerConfig, + hello: &ClientHello<'_>, + metadata: &::Metadata, + ) -> Option<(ServerConfig, Preprocessed)> { + let (cfg, res) = self.0.preprocess(prev, hello, metadata).await?; + Some((cfg, Preprocessed(self, res))) + } +} +impl Preprocessed { + fn finish(self, stream: AcceptStream) { + (self.0).0.handle_stream(stream, self.1); + } +} + +#[derive(Debug, Clone)] +pub struct ProxyTarget { pub filter: DynInterfaceFilter, pub acme: Option, pub addr: SocketAddr, - pub connect_ssl: Result<(), AlpnInfo>, // Ok: yes, connect using ssl, pass through alpn; Err: connect tcp, use provided strategy for alpn + pub connect_ssl: Result, AlpnInfo>, // Ok: yes, connect using ssl, pass through alpn; Err: connect tcp, use provided strategy for alpn } +impl PartialEq for ProxyTarget { + fn eq(&self, other: &Self) -> bool { + self.filter == other.filter + && self.addr == other.addr + && self.connect_ssl.as_ref().map(Arc::as_ptr) + == other.connect_ssl.as_ref().map(Arc::as_ptr) + } +} +impl Eq for ProxyTarget {} -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)] -pub struct ShowTargetInfo { - pub gateways: BTreeSet, - pub acme: Option, - pub addr: SocketAddr, - pub connect_ssl: Result<(), AlpnInfo>, // Ok: yes, connect using ssl, pass through alpn; Err: connect tcp, use provided strategy for alpn -} -impl ShowTargetInfo { - pub fn new( - TargetInfo { - filter, - acme, - addr, - connect_ssl, - }: TargetInfo, - ip_info: &OrdMap, - ) -> Self { - ShowTargetInfo { - gateways: ip_info - .iter() - .filter(|(id, info)| filter.filter(*id, *info)) - .map(|(k, _)| k) - .cloned() - .collect(), - acme, - addr, - connect_ssl, +impl VHostTarget for ProxyTarget +where + A: Accept + 'static, + ::Metadata: Visit> + Clone + Send + Sync, +{ + type PreprocessRes = AcceptStream; + fn filter(&self, metadata: &::Metadata) -> bool { + let info = extract::(metadata); + info.as_ref() + .map_or(true, |i| self.filter.filter(&i.id, &i.info)) + } + fn acme(&self) -> Option<&AcmeProvider> { + self.acme.as_ref() + } + async fn preprocess<'a>( + &'a self, + mut prev: ServerConfig, + hello: &'a ClientHello<'a>, + metadata: &'a ::Metadata, + ) -> Option<(ServerConfig, Self::PreprocessRes)> { + let tcp_stream = TcpStream::connect(self.addr) + .await + .with_ctx(|_| (ErrorKind::Network, self.addr)) + .log_err()?; + match &self.connect_ssl { + Ok(client_cfg) => { + let mut client_cfg = (&**client_cfg).clone(); + client_cfg.alpn_protocols = hello + .alpn() + .into_iter() + .flatten() + .map(|x| x.to_vec()) + .collect(); + let target_stream = TlsConnector::from(Arc::new(client_cfg)) + .connect_with( + ServerName::IpAddress(self.addr.ip().into()), + tcp_stream, + |conn| { + prev.alpn_protocols + .extend(conn.alpn_protocol().into_iter().map(|p| p.to_vec())) + }, + ) + .await + .log_err()?; + return Some((prev, Box::pin(target_stream))); + } + Err(AlpnInfo::Reflect) => { + for alpn in hello.alpn().into_iter().flatten() { + prev.alpn_protocols.push(alpn.to_vec()); + } + } + Err(AlpnInfo::Specified(a)) => { + for alpn in a { + prev.alpn_protocols.push(alpn.0.clone()); + } + } } + Some((prev, Box::pin(tcp_stream))) + } + fn handle_stream(&self, mut stream: AcceptStream, mut prev: Self::PreprocessRes) { + tokio::spawn(async move { tokio::io::copy_bidirectional(&mut stream, &mut prev).await }); } } @@ -237,17 +363,194 @@ impl Default for AlpnInfo { } } -type AcmeTlsAlpnCache = - Arc>>>>>; -type Mapping = BTreeMap, BTreeMap>>; +type Mapping = BTreeMap, InOMap, Weak<()>>>; -struct VHostServer { - mapping: watch::Sender, +pub struct GetVHostAcmeProvider(pub Watch>); +impl Clone for GetVHostAcmeProvider { + fn clone(&self) -> Self { + Self(self.0.clone()) + } +} +impl GetAcmeProvider for GetVHostAcmeProvider { + async fn get_provider<'a, 'b: 'a>( + &'b self, + san_info: &'a BTreeSet, + ) -> Option + Send + 'b> { + self.0.peek(|m| -> Option { + san_info + .iter() + .fold(Some::>(None), |acc, x| { + let acc = acc?; + if x.parse::().is_ok() { + return Some(acc); + } + let (t, _) = m + .get(&Some(x.clone()))? + .iter() + .find(|(_, rc)| rc.strong_count() > 0)?; + let acme = t.0.acme()?; + Some(if let Some(acc) = acc { + if acme == acc { + // all must match + Some(acme) + } else { + None + } + } else { + Some(acme) + }) + }) + .flatten() + .cloned() + }) + } +} + +pub struct VHostConnector(Watch>, Option>); +impl Clone for VHostConnector { + fn clone(&self) -> Self { + Self(self.0.clone(), None) + } +} + +impl WrapTlsHandler for VHostConnector +where + A: Accept + 'static, + ::Metadata: Visit> + Send + Sync, +{ + async fn wrap<'a>( + &'a mut self, + prev: ServerConfig, + hello: &'a ClientHello<'a>, + metadata: &'a ::Metadata, + ) -> Option + where + Self: 'a, + { + if hello + .alpn() + .into_iter() + .flatten() + .any(|a| a == ACME_TLS_ALPN_NAME) + { + return Some(prev); + } + + let target = self.0.peek(|m| { + m.get(&hello.server_name().map(InternedString::from)) + .into_iter() + .flatten() + .filter(|(_, rc)| rc.strong_count() > 0) + .find(|(t, _)| t.0.filter(metadata)) + .map(|(e, _)| e.clone()) + })?; + + let (prev, store) = target.into_preprocessed(prev, hello, metadata).await?; + + self.1 = Some(store); + + Some(prev) + } +} + +struct VHostListener( + TlsListener< + A, + TlsHandlerWrapper< + ChainedHandler>>, RootCaTlsHandler>, + VHostConnector, + >, + >, +) +where + for<'a> M: HasModel> + + DbAccessMut + + DbAccessMut + + DbAccessByKey = &'a AcmeProvider> + + Send + + Sync, + A: Accept + 'static, + ::Metadata: Visit> + + Visit> + + Clone + + Send + + Sync + + 'static; +struct VHostListenerMetadata { + inner: TlsMetadata, + preprocessed: Preprocessed, +} +impl Accept for VHostListener +where + for<'a> M: HasModel> + + DbAccessMut + + DbAccessMut + + DbAccessByKey = &'a AcmeProvider> + + Send + + Sync + + 'static, + A: Accept + 'static, + ::Metadata: Visit> + + Visit> + + Clone + + Send + + Sync + + 'static, +{ + type Metadata = VHostListenerMetadata; + fn poll_accept( + &mut self, + cx: &mut std::task::Context<'_>, + ) -> Poll> { + let (metadata, stream) = ready!(self.0.poll_accept(cx)?); + let preprocessed = self.0.tls_handler.wrapper.1.take(); + Poll::Ready(Ok(( + VHostListenerMetadata { + inner: metadata, + preprocessed: preprocessed.ok_or_else(|| { + Error::new( + eyre!("tlslistener yielded but preprocessed isn't set"), + ErrorKind::Incoherent, + ) + })?, + }, + stream, + ))) + } +} +impl VHostListener +where + for<'a> M: HasModel> + + DbAccessMut + + DbAccessMut + + DbAccessByKey = &'a AcmeProvider> + + Send + + Sync + + 'static, + A: Accept + 'static, + ::Metadata: Visit> + + Visit> + + Clone + + Send + + Sync + + 'static, +{ + async fn handle_next(&mut self) -> Result<(), Error> { + let (metadata, stream) = futures::future::poll_fn(|cx| self.poll_accept(cx)).await?; + + metadata.preprocessed.finish(stream); + + Ok(()) + } +} + +struct VHostServer { + mapping: Watch>, _thread: NonDetachingJoinHandle<()>, } -impl<'a> From<&'a BTreeMap, BTreeMap>>> for AnyFilter { - fn from(value: &'a BTreeMap, BTreeMap>>) -> Self { +impl<'a> From<&'a BTreeMap, BTreeMap>>> for AnyFilter { + fn from(value: &'a BTreeMap, BTreeMap>>) -> Self { Self( value .iter() @@ -261,471 +564,69 @@ impl<'a> From<&'a BTreeMap, BTreeMap } } -impl VHostServer { - async fn accept( - listener: &mut NetworkInterfaceListener, - mut mapping: watch::Receiver, - db: TypedPatchDb, - acme_tls_alpn_cache: AcmeTlsAlpnCache, - crypto_provider: Arc, - ) -> Result<(), Error> { - let accepted; - - loop { - let any_filter = AnyFilter::from(&*mapping.borrow()); - - let changed_filter = mapping - .wait_for(|m| any_filter != AnyFilter::from(m)) - .boxed(); - - tokio::select! { - a = listener.accept(&any_filter) => { - accepted = a?; - break; - } - _ = changed_filter => { - tracing::debug!("port {} filter changed", listener.port()); - } - } - } - - let check = listener.check_filter(); - tokio::spawn(async move { - let bind = accepted.bind; - if let Err(e) = Self::handle_stream( - accepted, - check, - mapping, - db, - acme_tls_alpn_cache, - crypto_provider, - ) - .await - { - tracing::error!("Error in VHostController on {bind}: {e}"); - tracing::debug!("{e:?}") - } - }); - Ok(()) - } - - async fn handle_stream( - Accepted { - stream, - wan_ip, - bind, - .. - }: Accepted, - check_filter: impl FnOnce(SocketAddr, &DynInterfaceFilter) -> bool, - mapping: watch::Receiver, - db: TypedPatchDb, - acme_tls_alpn_cache: AcmeTlsAlpnCache, - crypto_provider: Arc, - ) -> Result<(), Error> { - let mut stream = BackTrackingIO::new(stream); - let mid: tokio_rustls::StartHandshake<&mut BackTrackingIO> = - match LazyConfigAcceptor::new(Acceptor::default(), &mut stream).await { - Ok(a) => a, - Err(e) => { - let (_, buf) = stream.rewind(); - if std::str::from_utf8(buf) - .ok() - .and_then(|buf| { - buf.lines() - .map(|l| l.trim()) - .filter(|l| !l.is_empty()) - .next() - }) - .map_or(false, |buf| { - regex::Regex::new("[A-Z]+ (.+) HTTP/1") - .unwrap() - .is_match(buf) - }) - { - return hyper_util::server::conn::auto::Builder::new( - hyper_util::rt::TokioExecutor::new(), - ) - .serve_connection( - hyper_util::rt::TokioIo::new(stream), - hyper_util::service::TowerToHyperService::new( - axum::Router::new().fallback(axum::routing::method_routing::any( - move |req: Request| async move { - match async move { - let host = req - .headers() - .get(http::header::HOST) - .and_then(|host| host.to_str().ok()); - if let Some(host) = host { - let uri = Uri::from_parts({ - let mut parts = - req.uri().to_owned().into_parts(); - parts.scheme = Some("https".parse()?); - parts.authority = Some(host.parse()?); - parts - })?; - Response::builder() - .status(http::StatusCode::TEMPORARY_REDIRECT) - .header(http::header::LOCATION, uri.to_string()) - .body(Body::default()) - } else { - Response::builder() - .status(http::StatusCode::BAD_REQUEST) - .body(Body::from("Host header required")) - } - } - .await - { - Ok(a) => a, - Err(e) => { - tracing::warn!( - "Error redirecting http request on ssl port: {e}" - ); - tracing::error!("{e:?}"); - server_error(Error::new(e, ErrorKind::Network)) - } - } - }, - )), - ), - ) - .await - .map_err(|e| { - Error::new(color_eyre::eyre::Report::msg(e), ErrorKind::Network) - }); - } else { - return Err(e).with_kind(ErrorKind::Network); - } - } - }; - let target_name: Option = - mid.client_hello().server_name().map(|s| s.into()); - if let Some(domain) = target_name.as_ref() { - if mid - .client_hello() - .alpn() - .into_iter() - .flatten() - .any(|alpn| alpn == ACME_TLS_ALPN_NAME) - { - let cert = WatchStream::new( - acme_tls_alpn_cache - .peek(|c| c.get(&**domain).cloned()) - .ok_or_else(|| { - Error::new( - eyre!("No challenge recv available for {domain}"), - ErrorKind::OpenSsl, - ) - })?, - ); - tracing::info!("Waiting for verification cert for {domain}"); - let cert = cert - .filter(|c| c.is_some()) - .next() - .await - .flatten() - .ok_or_else(|| { - Error::new( - eyre!("No challenge available for {domain}"), - ErrorKind::OpenSsl, - ) - })?; - tracing::info!("Verification cert received for {domain}"); - let mut cfg = ServerConfig::builder_with_provider(crypto_provider.clone()) - .with_safe_default_protocol_versions() - .with_kind(crate::ErrorKind::OpenSsl)? - .with_no_client_auth() - .with_cert_resolver(Arc::new(SingleCertResolver(cert))); - - cfg.alpn_protocols = vec![ACME_TLS_ALPN_NAME.to_vec()]; - tracing::info!("performing ACME auth challenge"); - let mut accept = mid.into_stream(Arc::new(cfg)); - let io = accept.get_mut().unwrap(); - let buffered = io.stop_buffering(); - io.write_all(&buffered).await?; - accept.await?; - tracing::info!("ACME auth challenge completed"); - return Ok(()); - } - } - let target = { - let m = mapping.borrow(); - m.get(&target_name) - .into_iter() - .flatten() - .find(|(_, rc)| rc.strong_count() > 0) - .or_else(|| { - if target_name - .as_ref() - .map(|s| s.parse::().is_ok()) - .unwrap_or(true) - { - m.get(&None) - .into_iter() - .flatten() - .find(|(_, rc)| rc.strong_count() > 0) - } else { - None - } - }) - .map(|(target, _)| target.clone()) - }; - if let Some(target) = target { - if !check_filter(bind, &target.filter) { - log::warn!("Connection from {bind} to {target:?} rejected by filter"); - return Ok(()); - } - let peek = db.peek().await; - let root = peek - .as_private() - .as_key_store() - .as_local_certs() - .as_root_cert() - .de()?; - let mut cfg = async { - if let Some((domain, provider, settings)) = - target_name.as_ref().and_then(|domain| { - target.acme.as_ref().and_then(|a| { - peek.as_public() - .as_server_info() - .as_network() - .as_acme() - .as_idx(a) - .map(|s| (domain, a, s)) - }) - }) - { - let acme_settings = settings.de()?; - let mut identifiers = vec![Identifier::Dns(domain.to_string())]; - if false - // Requires RFC 8738 - { - if let Some(wan_ip) = wan_ip { - identifiers.push(Identifier::Ip(wan_ip.into())); - } - } - let (send, recv) = watch::channel(None); - acme_tls_alpn_cache.mutate(|c| c.insert(domain.clone(), recv)); - let cert = async_acme::rustls_helper::order( - |_, cert| { - send.send_replace(Some(Arc::new(cert))); - Ok(()) - }, - provider.0.as_str(), - &identifiers, - Some(&AcmeCertCache(&db)), - &acme_settings.contact, - ) - .await - .with_kind(ErrorKind::OpenSsl)?; - return Ok(ServerConfig::builder_with_provider(crypto_provider.clone()) - .with_safe_default_protocol_versions() - .with_kind(crate::ErrorKind::OpenSsl)? - .with_no_client_auth() - .with_cert_resolver(Arc::new(SingleCertResolver(Arc::new(cert))))); - } - - let hostnames = target_name - .into_iter() - .chain([InternedString::from_display(&bind.ip())]) - .chain(wan_ip.as_ref().map(InternedString::from_display)) - .collect(); - let key = db - .mutate(|v| { - v.as_private_mut() - .as_key_store_mut() - .as_local_certs_mut() - .cert_for(&hostnames) - }) - .await - .result?; - let cfg = ServerConfig::builder_with_provider(crypto_provider.clone()) - .with_safe_default_protocol_versions() - .with_kind(crate::ErrorKind::OpenSsl)? - .with_no_client_auth(); - if mid - .client_hello() - .signature_schemes() - .contains(&tokio_rustls::rustls::SignatureScheme::ED25519) - { - cfg.with_single_cert( - key.fullchain_ed25519() - .into_iter() - .map(|c| { - Ok(tokio_rustls::rustls::pki_types::CertificateDer::from( - c.to_der()?, - )) - }) - .collect::>()?, - PrivateKeyDer::from(PrivatePkcs8KeyDer::from( - key.leaf.keys.ed25519.private_key_to_pkcs8()?, - )), - ) - } else { - cfg.with_single_cert( - key.fullchain_nistp256() - .into_iter() - .map(|c| { - Ok(tokio_rustls::rustls::pki_types::CertificateDer::from( - c.to_der()?, - )) - }) - .collect::>()?, - PrivateKeyDer::from(PrivatePkcs8KeyDer::from( - key.leaf.keys.nistp256.private_key_to_pkcs8()?, - )), - ) - } - .with_kind(crate::ErrorKind::OpenSsl) - } - .await?; - let mut tcp_stream = TcpStream::connect(target.addr).await?; - match target.connect_ssl { - Ok(()) => { - let mut client_cfg = - tokio_rustls::rustls::ClientConfig::builder_with_provider(crypto_provider) - .with_safe_default_protocol_versions() - .with_kind(crate::ErrorKind::OpenSsl)? - .with_root_certificates({ - let mut store = RootCertStore::empty(); - store - .add(CertificateDer::from(root.to_der()?)) - .with_kind(crate::ErrorKind::OpenSsl)?; - store - }) - .with_no_client_auth(); - client_cfg.alpn_protocols = mid - .client_hello() - .alpn() - .into_iter() - .flatten() - .map(|x| x.to_vec()) - .collect(); - let mut target_stream = TlsConnector::from(Arc::new(client_cfg)) - .connect_with( - ServerName::IpAddress(target.addr.ip().into()), - tcp_stream, - |conn| { - cfg.alpn_protocols - .extend(conn.alpn_protocol().into_iter().map(|p| p.to_vec())) - }, - ) - .await - .with_kind(crate::ErrorKind::OpenSsl)?; - let mut accept = mid.into_stream(Arc::new(cfg)); - let io = accept.get_mut().unwrap(); - let buffered = io.stop_buffering(); - io.write_all(&buffered).await?; - let mut tls_stream = match accept.await { - Ok(a) => a, - Err(e) => { - tracing::trace!( - "VHostController: failed to accept TLS connection on {bind}: {e}" - ); - tracing::trace!("{e:?}"); - return Ok(()); - } - }; - tokio::io::copy_bidirectional(&mut tls_stream, &mut target_stream).await - } - Err(AlpnInfo::Reflect) => { - for proto in mid.client_hello().alpn().into_iter().flatten() { - cfg.alpn_protocols.push(proto.into()); - } - let mut accept = mid.into_stream(Arc::new(cfg)); - let io = accept.get_mut().unwrap(); - let buffered = io.stop_buffering(); - io.write_all(&buffered).await?; - let mut tls_stream = match accept.await { - Ok(a) => a, - Err(e) => { - tracing::trace!( - "VHostController: failed to accept TLS connection on {bind}: {e}" - ); - tracing::trace!("{e:?}"); - return Ok(()); - } - }; - tokio::io::copy_bidirectional(&mut tls_stream, &mut tcp_stream).await - } - Err(AlpnInfo::Specified(alpn)) => { - cfg.alpn_protocols = alpn.into_iter().map(|a| a.0).collect(); - let mut accept = mid.into_stream(Arc::new(cfg)); - let io = accept.get_mut().unwrap(); - let buffered = io.stop_buffering(); - io.write_all(&buffered).await?; - let mut tls_stream = match accept.await { - Ok(a) => a, - Err(e) => { - tracing::trace!( - "VHostController: failed to accept TLS connection on {bind}: {e}" - ); - tracing::trace!("{e:?}"); - return Ok(()); - } - }; - tokio::io::copy_bidirectional(&mut tls_stream, &mut tcp_stream).await - } - } - .map_or_else( - |e| { - use std::io::ErrorKind as E; - match e.kind() { - E::UnexpectedEof - | E::BrokenPipe - | E::ConnectionAborted - | E::ConnectionReset - | E::ConnectionRefused - | E::TimedOut - | E::Interrupted - | E::NotConnected => Ok(()), - _ => Err(e), - } - }, - |_| Ok(()), - )?; - } else { - // 503 - } - Ok::<_, Error>(()) - } - +impl VHostServer { #[instrument(skip_all)] - fn new( - port: u16, - db: TypedPatchDb, - iface_ctrl: Arc, + fn new( + listener: A, + db: TypedPatchDb, crypto_provider: Arc, - acme_tls_alpn_cache: AcmeTlsAlpnCache, - ) -> Result { - let mut listener = iface_ctrl - .watcher - .bind(port) - .with_kind(crate::ErrorKind::Network)?; - let (map_send, map_recv) = watch::channel(BTreeMap::new()); - Ok(Self { - mapping: map_send, + acme_cache: AcmeTlsAlpnCache, + ) -> Self + where + for<'a> M: HasModel> + + DbAccessMut + + DbAccessMut + + DbAccessByKey = &'a AcmeProvider> + + Send + + Sync + + 'static, + A: Accept + Send + 'static, + ::Metadata: Visit> + + Visit> + + Clone + + Send + + Sync + + 'static, + { + let mapping = Watch::new(BTreeMap::new()); + Self { + mapping: mapping.clone(), _thread: tokio::spawn(async move { + let mut listener = VHostListener(TlsListener::new( + listener, + TlsHandlerWrapper { + inner: ChainedHandler( + Arc::new(AcmeTlsHandler { + db: db.clone(), + acme_cache, + crypto_provider: crypto_provider.clone(), + get_provider: GetVHostAcmeProvider(mapping.clone()), + in_progress: Watch::new(BTreeSet::new()), + }), + RootCaTlsHandler { + db, + crypto_provider, + }, + ), + wrapper: VHostConnector(mapping, None), + }, + )); loop { - if let Err(e) = Self::accept( - &mut listener, - map_recv.clone(), - db.clone(), - acme_tls_alpn_cache.clone(), - crypto_provider.clone(), - ) - .await - { - tracing::error!( - "VHostController: failed to accept connection on {port}: {e}" - ); + if let Err(e) = listener.handle_next().await { + tracing::error!("VHostServer: failed to accept connection: {e}"); tracing::debug!("{e:?}"); } } }) .into(), - }) + } } - fn add(&self, hostname: Option, target: TargetInfo) -> Result, Error> { + fn add( + &self, + hostname: Option, + target: DynVHostTarget, + ) -> Result, Error> { + let target = target.into(); let mut res = Ok(Arc::new(())); self.mapping.send_if_modified(|writable| { let mut changed = false; @@ -741,7 +642,7 @@ impl VHostServer { res = Ok(rc); changed }); - if !self.mapping.is_closed() { + if self.mapping.watcher_count() > 1 { res } else { Err(Error::new( @@ -766,6 +667,6 @@ impl VHostServer { }); } fn is_empty(&self) -> bool { - self.mapping.borrow().is_empty() + self.mapping.peek(|m| m.is_empty()) } } diff --git a/core/startos/src/net/web_server.rs b/core/startos/src/net/web_server.rs index 8a2a66d7d..a03365417 100644 --- a/core/startos/src/net/web_server.rs +++ b/core/startos/src/net/web_server.rs @@ -1,70 +1,200 @@ +use std::any::Any; +use std::collections::BTreeMap; use std::future::Future; use std::net::SocketAddr; use std::ops::Deref; +use std::pin::Pin; use std::sync::Arc; -use std::task::Poll; +use std::task::{Poll, ready}; use std::time::Duration; use axum::Router; use futures::future::Either; -use futures::FutureExt; +use futures::{FutureExt, TryFutureExt}; use helpers::NonDetachingJoinHandle; +use http::Extensions; use hyper_util::rt::{TokioIo, TokioTimer}; -use tokio::net::{TcpListener, TcpStream}; +use tokio::net::TcpListener; use tokio::sync::oneshot; +use visit_rs::{Visit, VisitFields, Visitor}; -use crate::context::{DiagnosticContext, InitContext, InstallContext, RpcContext, SetupContext}; -use crate::net::gateway::{ - lookup_info_by_addr, NetworkInterfaceListener, SelfContainedNetworkInterfaceListener, -}; -use crate::net::static_server::{ - diagnostic_ui_router, init_ui_router, install_ui_router, main_ui_router, redirecter, refresher, - setup_ui_router, -}; +use crate::net::static_server::{UiContext, ui_router}; use crate::prelude::*; use crate::util::actor::background::BackgroundJobQueue; +use crate::util::io::ReadWriter; use crate::util::sync::{SyncRwLock, Watch}; -pub struct Accepted { - pub https_redirect: bool, - pub stream: TcpStream, +pub type AcceptStream = Pin>; + +pub trait MetadataVisitor: Visitor { + fn visit(&mut self, metadata: &M) -> Self::Result; +} + +pub struct ExtensionVisitor<'a>(&'a mut Extensions); +impl<'a> Visitor for ExtensionVisitor<'a> { + type Result = (); +} +impl<'a> MetadataVisitor for ExtensionVisitor<'a> { + fn visit(&mut self, metadata: &M) -> Self::Result { + self.0.insert(metadata.clone()); + } +} +impl<'a> Visit> + for Box Visit> + Send + Sync + 'static> +{ + fn visit( + &self, + visitor: &mut ExtensionVisitor<'a>, + ) -> as Visitor>::Result { + (&**self).visit(visitor) + } +} + +pub struct ExtractVisitor(Option); +impl Visitor for ExtractVisitor { + type Result = (); +} +impl MetadataVisitor for ExtractVisitor { + fn visit(&mut self, metadata: &M) -> Self::Result { + if let Some(matching) = (metadata as &dyn Any).downcast_ref::() { + self.0 = Some(matching.clone()); + } + } +} +pub fn extract< + T: Clone + Send + Sync + 'static, + M: Visit> + Clone + Send + Sync + 'static, +>( + metadata: &M, +) -> Option { + let mut visitor = ExtractVisitor(None); + visitor.visit(metadata); + visitor.0 +} + +#[derive(Clone, Copy, Debug)] +pub struct TcpMetadata { + pub peer_addr: SocketAddr, + pub local_addr: SocketAddr, +} +impl Visit for TcpMetadata { + fn visit(&self, visitor: &mut V) -> ::Result { + visitor.visit(self) + } } pub trait Accept { - fn poll_accept(&mut self, cx: &mut std::task::Context<'_>) -> Poll>; + type Metadata; + fn poll_accept( + &mut self, + cx: &mut std::task::Context<'_>, + ) -> Poll>; + fn into_dyn(self) -> DynAccept + where + Self: Sized + Send + Sync + 'static, + for<'a> Self::Metadata: Visit> + Send + Sync + 'static, + { + DynAccept::new(self) + } } -impl Accept for Vec { - fn poll_accept(&mut self, cx: &mut std::task::Context<'_>) -> Poll> { - for listener in &*self { - if let Poll::Ready((stream, _)) = listener.poll_accept(cx)? { - return Poll::Ready(Ok(Accepted { - https_redirect: false, - stream, - })); +impl Accept for TcpListener { + type Metadata = TcpMetadata; + fn poll_accept( + &mut self, + cx: &mut std::task::Context<'_>, + ) -> Poll> { + if let Poll::Ready((stream, peer_addr)) = TcpListener::poll_accept(self, cx)? { + if let Err(e) = socket2::SockRef::from(&stream).set_tcp_keepalive( + &socket2::TcpKeepalive::new() + .with_time(Duration::from_secs(900)) + .with_interval(Duration::from_secs(60)) + .with_retries(5), + ) { + tracing::error!("Failed to set tcp keepalive: {e}"); + tracing::debug!("{e:?}"); + } + return Poll::Ready(Ok(( + TcpMetadata { + local_addr: self.local_addr()?, + peer_addr, + }, + Box::pin(stream), + ))); + } + Poll::Pending + } +} + +impl Accept for Vec +where + A: Accept, +{ + type Metadata = A::Metadata; + fn poll_accept( + &mut self, + cx: &mut std::task::Context<'_>, + ) -> Poll> { + for listener in self { + if let Poll::Ready(accepted) = listener.poll_accept(cx)? { + return Poll::Ready(Ok(accepted)); } } Poll::Pending } } -impl Accept for NetworkInterfaceListener { - fn poll_accept(&mut self, cx: &mut std::task::Context<'_>) -> Poll> { - NetworkInterfaceListener::poll_accept(self, cx, &true).map(|res| { - res.map(|a| { - let public = self - .ip_info - .peek(|i| lookup_info_by_addr(i, a.bind).map_or(true, |(_, i)| i.public())); - Accepted { - https_redirect: public, - stream: a.stream, - } - }) - }) + +#[derive(Clone, VisitFields)] +pub struct MapListenerMetadata { + pub inner: M, + pub key: K, +} +impl Visit for MapListenerMetadata +where + V: MetadataVisitor, + K: Visit, + M: Visit, +{ + fn visit(&self, visitor: &mut V) -> ::Result { + self.visit_fields(visitor).collect() } } -impl Accept for Either { - fn poll_accept(&mut self, cx: &mut std::task::Context<'_>) -> Poll> { +impl Accept for BTreeMap +where + K: Clone, + A: Accept, +{ + type Metadata = MapListenerMetadata; + fn poll_accept( + &mut self, + cx: &mut std::task::Context<'_>, + ) -> Poll> { + for (key, listener) in self { + if let Poll::Ready((metadata, stream)) = listener.poll_accept(cx)? { + return Poll::Ready(Ok(( + MapListenerMetadata { + inner: metadata, + key: key.clone(), + }, + stream, + ))); + } + } + Poll::Pending + } +} + +impl Accept for Either +where + A: Accept, + B: Accept, +{ + type Metadata = A::Metadata; + fn poll_accept( + &mut self, + cx: &mut std::task::Context<'_>, + ) -> Poll> { match self { Either::Left(a) => a.poll_accept(cx), Either::Right(b) => b.poll_accept(cx), @@ -72,7 +202,11 @@ impl Accept for Either { } } impl Accept for Option { - fn poll_accept(&mut self, cx: &mut std::task::Context<'_>) -> Poll> { + type Metadata = A::Metadata; + fn poll_accept( + &mut self, + cx: &mut std::task::Context<'_>, + ) -> Poll> { match self { None => Poll::Pending, Some(a) => a.poll_accept(cx), @@ -80,6 +214,68 @@ impl Accept for Option { } } +trait DynAcceptT: Send + Sync { + fn poll_accept( + &mut self, + cx: &mut std::task::Context<'_>, + ) -> Poll< + Result< + ( + Box Visit> + Send + Sync>, + AcceptStream, + ), + Error, + >, + >; +} +impl DynAcceptT for A +where + A: Accept + Send + Sync, + for<'a> ::Metadata: Visit> + Send + Sync + 'static, +{ + fn poll_accept( + &mut self, + cx: &mut std::task::Context<'_>, + ) -> Poll< + Result< + ( + Box Visit> + Send + Sync>, + AcceptStream, + ), + Error, + >, + > { + let (metadata, stream) = ready!(Accept::poll_accept(self, cx)?); + Poll::Ready(Ok((Box::new(metadata), stream))) + } +} +pub struct DynAccept(Box); +impl Accept for DynAccept { + type Metadata = Box Visit> + Send + Sync>; + fn poll_accept( + &mut self, + cx: &mut std::task::Context<'_>, + ) -> Poll> { + DynAcceptT::poll_accept(&mut *self.0, cx) + } + fn into_dyn(self) -> DynAccept + where + Self: Sized, + for<'a> Self::Metadata: Visit> + Send + Sync + 'static, + { + self + } +} +impl DynAccept { + pub fn new(accept: A) -> Self + where + A: Accept + Send + Sync + 'static, + for<'a> ::Metadata: Visit> + Send + Sync + 'static, + { + Self(Box::new(accept)) + } +} + #[pin_project::pin_project] pub struct Acceptor { acceptor: Watch, @@ -95,12 +291,15 @@ impl Acceptor { self.acceptor.poll_changed(cx) } - fn poll_accept(&mut self, cx: &mut std::task::Context<'_>) -> Poll> { - let _ = self.poll_changed(cx); + fn poll_accept( + &mut self, + cx: &mut std::task::Context<'_>, + ) -> Poll> { + while self.poll_changed(cx).is_ready() {} self.acceptor.peek_mut(|a| a.poll_accept(cx)) } - async fn accept(&mut self) -> Result { + async fn accept(&mut self) -> Result<(A::Metadata, AcceptStream), Error> { std::future::poll_fn(|cx| self.poll_accept(cx)).await } } @@ -111,20 +310,73 @@ impl Acceptor> { )) } } - -pub type UpgradableListener = - Option>; - -impl Acceptor { - pub fn bind_upgradable(listener: SelfContainedNetworkInterfaceListener) -> Self { - Self::new(Some(Either::Left(listener))) +impl Acceptor> { + pub async fn bind_dyn(listen: impl IntoIterator) -> Result { + Ok(Self::new( + futures::future::try_join_all( + listen + .into_iter() + .map(TcpListener::bind) + .map(|f| f.map_ok(DynAccept::new)), + ) + .await?, + )) + } +} +impl Acceptor> +where + K: Ord + Clone + Send + Sync + 'static, +{ + pub async fn bind_map( + listen: impl IntoIterator, + ) -> Result { + Ok(Self::new( + futures::future::try_join_all(listen.into_iter().map(|(key, addr)| async move { + Ok::<_, Error>(( + key, + TcpListener::bind(addr) + .await + .with_kind(ErrorKind::Network)?, + )) + })) + .await? + .into_iter() + .collect(), + )) + } +} +impl Acceptor> +where + K: Ord + Clone + Send + Sync + 'static, +{ + pub async fn bind_map_dyn( + listen: impl IntoIterator, + ) -> Result { + Ok(Self::new( + futures::future::try_join_all(listen.into_iter().map(|(key, addr)| async move { + Ok::<_, Error>(( + key, + TcpListener::bind(addr) + .await + .with_kind(ErrorKind::Network)?, + )) + })) + .await? + .into_iter() + .map(|(key, listener)| (key, listener.into_dyn())) + .collect(), + )) } } pub struct WebServerAcceptorSetter { acceptor: Watch, } -impl WebServerAcceptorSetter>> { +impl WebServerAcceptorSetter>> +where + A: Accept, + B: Accept, +{ pub fn try_upgrade Result>(&self, f: F) -> Result<(), Error> { let mut res = Ok(()); self.acceptor.send_modify(|a| { @@ -151,20 +403,24 @@ impl Deref for WebServerAcceptorSetter { pub struct WebServer { shutdown: oneshot::Sender<()>, - router: Watch>, + router: Watch, acceptor: Watch, thread: NonDetachingJoinHandle<()>, } -impl WebServer { +impl WebServer +where + A: Accept + Send + Sync + 'static, + for<'a> A::Metadata: Visit> + Send + Sync + 'static, +{ pub fn acceptor_setter(&self) -> WebServerAcceptorSetter { WebServerAcceptorSetter { acceptor: self.acceptor.clone(), } } - pub fn new(mut acceptor: Acceptor) -> Self { + pub fn new(mut acceptor: Acceptor, router: Router) -> Self { let acceptor_send = acceptor.acceptor.clone(); - let router = Watch::>::new(None); + let router = Watch::new(router); let service = router.clone_unseen(); let (shutdown, shutdown_recv) = oneshot::channel(); let thread = NonDetachingJoinHandle::from(tokio::spawn(async move { @@ -187,8 +443,14 @@ impl WebServer { } } - struct SwappableRouter(Watch>, bool); - impl hyper::service::Service> for SwappableRouter { + struct SwappableRouter { + router: Watch, + metadata: M, + } + impl Visit> + Send + Sync + 'static> + hyper::service::Service> + for SwappableRouter + { type Response = , >>::Response; @@ -199,19 +461,13 @@ impl WebServer { hyper::Request, >>::Future; - fn call(&self, req: hyper::Request) -> Self::Future { + fn call(&self, mut req: hyper::Request) -> Self::Future { use tower_service::Service; - if self.1 { - redirecter().call(req) - } else { - let router = self.0.read(); - if let Some(mut router) = router { - router.call(req) - } else { - refresher().call(req) - } - } + self.metadata + .visit(&mut ExtensionVisitor(req.extensions_mut())); + + self.router.read().call(req) } } @@ -238,16 +494,16 @@ impl WebServer { let mut err = None; for _ in 0..5 { if let Err(e) = async { - let accepted = acceptor.accept().await?; + let (metadata, stream) = acceptor.accept().await?; queue.add_job( graceful.watch( server .serve_connection_with_upgrades( - TokioIo::new(accepted.stream), - SwappableRouter( - service.clone(), - accepted.https_redirect, - ), + TokioIo::new(stream), + SwappableRouter { + router: service.clone(), + metadata, + }, ) .into_owned(), ), @@ -300,26 +556,10 @@ impl WebServer { } pub fn serve_router(&mut self, router: Router) { - self.router.send(Some(router)) + self.router.send(router) } - pub fn serve_main(&mut self, ctx: RpcContext) { - self.serve_router(main_ui_router(ctx)) - } - - pub fn serve_setup(&mut self, ctx: SetupContext) { - self.serve_router(setup_ui_router(ctx)) - } - - pub fn serve_diagnostic(&mut self, ctx: DiagnosticContext) { - self.serve_router(diagnostic_ui_router(ctx)) - } - - pub fn serve_install(&mut self, ctx: InstallContext) { - self.serve_router(install_ui_router(ctx)) - } - - pub fn serve_init(&mut self, ctx: InitContext) { - self.serve_router(init_ui_router(ctx)) + pub fn serve_ui_for(&mut self, ctx: C) { + self.serve_router(ui_router(ctx)) } } diff --git a/core/startos/src/net/wifi.rs b/core/startos/src/net/wifi.rs index 44465e501..6d6774998 100644 --- a/core/startos/src/net/wifi.rs +++ b/core/startos/src/net/wifi.rs @@ -1017,6 +1017,31 @@ pub async fn synchronize_network_manager>( .await?; } + Command::new("ip") + .arg("rule") + .arg("add") + .arg("pref") + .arg("1000") + .arg("from") + .arg("all") + .arg("lookup") + .arg("main") + .invoke(ErrorKind::Network) + .await + .log_err(); + Command::new("ip") + .arg("rule") + .arg("add") + .arg("pref") + .arg("1100") + .arg("from") + .arg("all") + .arg("lookup") + .arg("default") + .invoke(ErrorKind::Network) + .await + .log_err(); + Command::new("systemctl") .arg("restart") .arg("NetworkManager") diff --git a/core/startos/src/notifications.rs b/core/startos/src/notifications.rs index 6a55fb722..cbbea5da6 100644 --- a/core/startos/src/notifications.rs +++ b/core/startos/src/notifications.rs @@ -3,13 +3,13 @@ use std::fmt; use std::str::FromStr; use chrono::{DateTime, Utc}; -use clap::builder::ValueParserFactory; use clap::Parser; +use clap::builder::ValueParserFactory; use color_eyre::eyre::eyre; use helpers::const_true; use imbl_value::InternedString; use models::{FromStrParser, PackageId}; -use rpc_toolkit::{from_fn_async, Context, HandlerExt, ParentHandler}; +use rpc_toolkit::{Context, HandlerExt, ParentHandler, from_fn_async}; use serde::{Deserialize, Serialize}; use tracing::instrument; use ts_rs::TS; @@ -463,7 +463,8 @@ pub fn notify( data, seen: false, }, - ) + )?; + Ok(()) } #[test] diff --git a/core/startos/src/os_install/mod.rs b/core/startos/src/os_install/mod.rs index 651838cfb..7b5609b6a 100644 --- a/core/startos/src/os_install/mod.rs +++ b/core/startos/src/os_install/mod.rs @@ -361,6 +361,7 @@ pub async fn execute( match ARCH { "x86_64" => install.arg("--target=x86_64-efi"), "aarch64" => install.arg("--target=arm64-efi"), + "riscv64" => install.arg("--target=riscv64-efi"), _ => &mut install, }; } diff --git a/core/startos/src/registry/context.rs b/core/startos/src/registry/context.rs index b97a2679f..5da5b2937 100644 --- a/core/startos/src/registry/context.rs +++ b/core/startos/src/registry/context.rs @@ -5,6 +5,7 @@ use std::sync::Arc; use chrono::Utc; use clap::Parser; +use http::HeaderMap; use imbl_value::InternedString; use patch_db::PatchDb; use reqwest::{Client, Proxy}; @@ -168,25 +169,38 @@ impl CallRemote for CliContext { let url = if let Some(url) = self.registry_url.clone() { url } else if self.registry_hostname.is_some() { - format!( + let mut url: Url = format!( "http://{}", self.registry_listen.unwrap_or(DEFAULT_REGISTRY_LISTEN) ) .parse() - .map_err(Error::from)? + .map_err(Error::from)?; + url.path_segments_mut() + .map_err(|_| Error::new(eyre!("cannot extend URL path"), ErrorKind::ParseUrl))? + .push("rpc") + .push("v0"); + url } else { return Err( Error::new(eyre!("`--registry` required"), ErrorKind::InvalidRequest).into(), ); }; + method = method.strip_prefix("registry.").unwrap_or(method); let sig_context = self .registry_hostname .clone() - .or(url.host().as_ref().map(InternedString::from_display)) - .or_not_found("registry hostname")?; + .or_else(|| url.host().as_ref().map(InternedString::from_display)); - crate::middleware::signature::call_remote(self, url, &sig_context, method, params).await + crate::middleware::signature::call_remote( + self, + url, + HeaderMap::new(), + sig_context.as_deref(), + method, + params, + ) + .await } } @@ -195,61 +209,32 @@ impl CallRemote for RpcContext { &self, mut method: &str, params: Value, - RegistryUrlParams { registry }: RegistryUrlParams, + RegistryUrlParams { mut registry }: RegistryUrlParams, ) -> Result { - use reqwest::Method; - use reqwest::header::{ACCEPT, CONTENT_LENGTH, CONTENT_TYPE}; - use rpc_toolkit::RpcResponse; - use rpc_toolkit::yajrc::{GenericRpcMethod, Id, RpcRequest}; + let mut headers = HeaderMap::new(); + headers.insert( + DEVICE_INFO_HEADER, + DeviceInfo::load(self).await?.to_header_value(), + ); + + registry + .path_segments_mut() + .map_err(|_| Error::new(eyre!("cannot extend URL path"), ErrorKind::ParseUrl))? + .push("rpc") + .push("v0"); - let url = registry.join("rpc/v0")?; method = method.strip_prefix("registry.").unwrap_or(method); + let sig_context = registry.host_str().map(InternedString::from); - let rpc_req = RpcRequest { - id: Some(Id::Number(0.into())), - method: GenericRpcMethod::<_, _, Value>::new(method), + crate::middleware::signature::call_remote( + self, + registry, + headers, + sig_context.as_deref(), + method, params, - }; - let body = serde_json::to_vec(&rpc_req)?; - let res = self - .client - .request(Method::POST, url) - .header(CONTENT_TYPE, "application/json") - .header(ACCEPT, "application/json") - .header(CONTENT_LENGTH, body.len()) - .header( - DEVICE_INFO_HEADER, - DeviceInfo::load(self).await?.to_header_value(), - ) - .body(body) - .send() - .await?; - - if !res.status().is_success() { - let status = res.status(); - let txt = res.text().await?; - let mut res = Err(Error::new( - eyre!("{}", status.canonical_reason().unwrap_or(status.as_str())), - ErrorKind::Network, - )); - if !txt.is_empty() { - res = res.with_ctx(|_| (ErrorKind::Network, txt)); - } - return res.map_err(From::from); - } - - match res - .headers() - .get(CONTENT_TYPE) - .and_then(|v| v.to_str().ok()) - { - Some("application/json") => { - serde_json::from_slice::(&*res.bytes().await?) - .with_kind(ErrorKind::Deserialization)? - .result - } - _ => Err(Error::new(eyre!("unknown content type"), ErrorKind::Network).into()), - } + ) + .await } } diff --git a/core/startos/src/registry/device_info.rs b/core/startos/src/registry/device_info.rs index cb3f19089..9b76ace68 100644 --- a/core/startos/src/registry/device_info.rs +++ b/core/startos/src/registry/device_info.rs @@ -175,7 +175,7 @@ impl Middleware for DeviceInfoMiddleware { async move { if metadata.get_device_info { if let Some(device_info) = &self.device_info { - request.params["__device_info"] = + request.params["__DeviceInfo_device_info"] = to_value(&DeviceInfo::from_header_value(device_info)?)?; } } diff --git a/core/startos/src/registry/mod.rs b/core/startos/src/registry/mod.rs index 811188d4e..11fe2b807 100644 --- a/core/startos/src/registry/mod.rs +++ b/core/startos/src/registry/mod.rs @@ -141,9 +141,3 @@ pub fn registry_router(ctx: RegistryContext) -> Router { }), ) } - -impl WebServer { - pub fn serve_registry(&mut self, ctx: RegistryContext) { - self.serve_router(registry_router(ctx)) - } -} diff --git a/core/startos/src/registry/os/asset/add.rs b/core/startos/src/registry/os/asset/add.rs index e5ca3a934..915fb882f 100644 --- a/core/startos/src/registry/os/asset/add.rs +++ b/core/startos/src/registry/os/asset/add.rs @@ -83,7 +83,7 @@ pub struct AddAssetParams { pub platform: InternedString, #[ts(type = "string")] pub url: Url, - #[serde(rename = "__auth_signer")] + #[serde(rename = "__Auth_signer")] #[ts(skip)] pub signer: AnyVerifyingKey, pub signature: AnySignature, @@ -289,7 +289,7 @@ pub struct RemoveAssetParams { pub version: Version, #[ts(type = "string")] pub platform: InternedString, - #[serde(rename = "__auth_signer")] + #[serde(rename = "__Auth_signer")] #[ts(skip)] pub signer: AnyVerifyingKey, } diff --git a/core/startos/src/registry/os/asset/sign.rs b/core/startos/src/registry/os/asset/sign.rs index 61501b46e..68c0f571c 100644 --- a/core/startos/src/registry/os/asset/sign.rs +++ b/core/startos/src/registry/os/asset/sign.rs @@ -56,7 +56,7 @@ pub struct SignAssetParams { #[ts(type = "string")] platform: InternedString, #[ts(skip)] - #[serde(rename = "__auth_signer")] + #[serde(rename = "__Auth_signer")] signer: AnyVerifyingKey, signature: AnySignature, } diff --git a/core/startos/src/registry/os/version/mod.rs b/core/startos/src/registry/os/version/mod.rs index 4fb2b10e9..29105d577 100644 --- a/core/startos/src/registry/os/version/mod.rs +++ b/core/startos/src/registry/os/version/mod.rs @@ -68,7 +68,7 @@ pub struct AddVersionParams { pub source_version: VersionRange, #[arg(skip)] #[ts(skip)] - #[serde(rename = "__auth_signer")] + #[serde(rename = "__Auth_signer")] pub signer: Option, } @@ -146,7 +146,7 @@ pub struct GetOsVersionParams { platform: Option, #[ts(skip)] #[arg(skip)] - #[serde(rename = "__device_info")] + #[serde(rename = "__DeviceInfo_device_info")] pub device_info: Option, } diff --git a/core/startos/src/registry/package/add.rs b/core/startos/src/registry/package/add.rs index 7bd836ff9..baf1703cc 100644 --- a/core/startos/src/registry/package/add.rs +++ b/core/startos/src/registry/package/add.rs @@ -31,7 +31,7 @@ pub struct AddPackageParams { #[ts(type = "string")] pub url: Url, #[ts(skip)] - #[serde(rename = "__auth_signer")] + #[serde(rename = "__Auth_signer")] pub uploader: AnyVerifyingKey, pub commitment: MerkleArchiveCommitment, pub signature: AnySignature, @@ -169,7 +169,7 @@ pub struct RemovePackageParams { pub version: VersionString, #[ts(skip)] #[arg(skip)] - #[serde(rename = "__auth_signer")] + #[serde(rename = "__Auth_signer")] pub signer: Option, } diff --git a/core/startos/src/registry/package/get.rs b/core/startos/src/registry/package/get.rs index cdaef66a8..8f61e51ef 100644 --- a/core/startos/src/registry/package/get.rs +++ b/core/startos/src/registry/package/get.rs @@ -51,7 +51,7 @@ pub struct GetPackageParams { pub source_version: Option, #[ts(skip)] #[arg(skip)] - #[serde(rename = "__device_info")] + #[serde(rename = "__DeviceInfo_device_info")] pub device_info: Option, #[serde(default)] #[arg(default_value = "none")] diff --git a/core/startos/src/s9pk/merkle_archive/sink.rs b/core/startos/src/s9pk/merkle_archive/sink.rs index 5357eb2d6..745b91cf5 100644 --- a/core/startos/src/s9pk/merkle_archive/sink.rs +++ b/core/startos/src/s9pk/merkle_archive/sink.rs @@ -3,12 +3,10 @@ use tokio::io::{AsyncSeek, AsyncWrite}; use crate::prelude::*; use crate::util::io::TrackingIO; -#[async_trait::async_trait] pub trait Sink: AsyncWrite + Unpin + Send { - async fn current_position(&mut self) -> Result; + fn current_position(&mut self) -> impl Future> + Send + '_; } -#[async_trait::async_trait] impl Sink for S { async fn current_position(&mut self) -> Result { use tokio::io::AsyncSeekExt; @@ -17,7 +15,6 @@ impl Sink for S { } } -#[async_trait::async_trait] impl Sink for TrackingIO { async fn current_position(&mut self) -> Result { Ok(self.position()) diff --git a/core/startos/src/s9pk/v2/compat.rs b/core/startos/src/s9pk/v2/compat.rs index 923b07bb3..4e01f8889 100644 --- a/core/startos/src/s9pk/v2/compat.rs +++ b/core/startos/src/s9pk/v2/compat.rs @@ -16,10 +16,10 @@ use crate::s9pk::merkle_archive::source::TmpSource; use crate::s9pk::merkle_archive::{Entry, MerkleArchive}; use crate::s9pk::v1::manifest::{Manifest as ManifestV1, PackageProcedure}; use crate::s9pk::v1::reader::S9pkReader; -use crate::s9pk::v2::pack::{ImageSource, PackSource, CONTAINER_TOOL}; +use crate::s9pk::v2::pack::{CONTAINER_TOOL, ImageSource, PackSource}; use crate::s9pk::v2::{S9pk, SIG_CONTEXT}; -use crate::util::io::{create_file, TmpDir}; use crate::util::Invoke; +use crate::util::io::{TmpDir, create_file}; pub const MAGIC_AND_VERSION: &[u8] = &[0x3b, 0x3b, 0x01]; diff --git a/core/startos/src/s9pk/v2/pack.rs b/core/startos/src/s9pk/v2/pack.rs index 6e8371191..058ee32a8 100644 --- a/core/startos/src/s9pk/v2/pack.rs +++ b/core/startos/src/s9pk/v2/pack.rs @@ -3,7 +3,7 @@ use std::path::{Path, PathBuf}; use std::sync::Arc; use clap::Parser; -use futures::future::{ready, BoxFuture}; +use futures::future::{BoxFuture, ready}; use futures::{FutureExt, TryStreamExt}; use imbl_value::InternedString; use models::{DataUrl, ImageId, PackageId, VersionString}; @@ -18,20 +18,20 @@ use crate::context::CliContext; use crate::dependencies::{DependencyMetadata, MetadataSrc}; use crate::prelude::*; use crate::rpc_continuations::Guid; +use crate::s9pk::S9pk; use crate::s9pk::git_hash::GitHash; use crate::s9pk::manifest::Manifest; use crate::s9pk::merkle_archive::directory_contents::DirectoryContents; use crate::s9pk::merkle_archive::source::http::HttpSource; use crate::s9pk::merkle_archive::source::multi_cursor_file::MultiCursorFile; use crate::s9pk::merkle_archive::source::{ - into_dyn_read, ArchiveSource, DynFileSource, DynRead, FileSource, TmpSource, + ArchiveSource, DynFileSource, DynRead, FileSource, TmpSource, into_dyn_read, }; use crate::s9pk::merkle_archive::{Entry, MerkleArchive}; use crate::s9pk::v2::SIG_CONTEXT; -use crate::s9pk::S9pk; -use crate::util::io::{create_file, open_file, TmpDir}; +use crate::util::io::{TmpDir, create_file, open_file}; use crate::util::serde::IoFormat; -use crate::util::{new_guid, Invoke, PathOrUrl}; +use crate::util::{Invoke, PathOrUrl, new_guid}; #[cfg(not(feature = "docker"))] pub const CONTAINER_TOOL: &str = "podman"; @@ -369,10 +369,12 @@ impl ImageSource { workdir, .. } => { - vec![workdir - .as_deref() - .unwrap_or(Path::new(".")) - .join(dockerfile.as_deref().unwrap_or(Path::new("Dockerfile")))] + vec![ + workdir + .as_deref() + .unwrap_or(Path::new(".")) + .join(dockerfile.as_deref().unwrap_or(Path::new("Dockerfile"))), + ] } Self::DockerTag(_) => Vec::new(), } @@ -414,6 +416,8 @@ impl ImageSource { "--platform=linux/amd64".to_owned() } else if arch == "aarch64" { "--platform=linux/arm64".to_owned() + } else if arch == "riscv64" { + "--platform=linux/riscv64".to_owned() } else { format!("--platform=linux/{arch}") }; @@ -476,6 +480,8 @@ impl ImageSource { "--platform=linux/amd64".to_owned() } else if arch == "aarch64" { "--platform=linux/arm64".to_owned() + } else if arch == "riscv64" { + "--platform=linux/riscv64".to_owned() } else { format!("--platform=linux/{arch}") }; diff --git a/core/startos/src/service/effects/callbacks.rs b/core/startos/src/service/effects/callbacks.rs index 8493f8a02..dea736aeb 100644 --- a/core/startos/src/service/effects/callbacks.rs +++ b/core/startos/src/service/effects/callbacks.rs @@ -6,7 +6,7 @@ use std::time::{Duration, SystemTime}; use clap::Parser; use futures::future::join_all; use helpers::NonDetachingJoinHandle; -use imbl::{vector, Vector}; +use imbl::{Vector, vector}; use imbl_value::InternedString; use models::{HostId, PackageId, ServiceInterfaceId}; use serde::{Deserialize, Serialize}; diff --git a/core/startos/src/service/effects/net/ssl.rs b/core/startos/src/service/effects/net/ssl.rs index be8a5d7d7..fcd1dac9d 100644 --- a/core/startos/src/service/effects/net/ssl.rs +++ b/core/startos/src/service/effects/net/ssl.rs @@ -95,7 +95,7 @@ pub async fn get_ssl_certificate( .as_entries()? .into_iter() .flat_map(|(_, net)| net.as_ip_info().transpose_ref()) - .flat_map(|net| net.as_subnets().de().log_err()) + .flat_map(|net| net.as_deref().as_subnets().de().log_err()) .flatten() .any(|s| s.addr() == ip) { diff --git a/core/startos/src/service/mod.rs b/core/startos/src/service/mod.rs index d98f43379..b4c895ee0 100644 --- a/core/startos/src/service/mod.rs +++ b/core/startos/src/service/mod.rs @@ -15,12 +15,12 @@ use futures::future::BoxFuture; use futures::stream::FusedStream; use futures::{FutureExt, SinkExt, StreamExt, TryStreamExt}; use helpers::NonDetachingJoinHandle; -use imbl_value::{json, InternedString}; +use imbl_value::{InternedString, json}; use itertools::Itertools; use models::{ActionId, HostId, ImageId, PackageId}; use nix::sys::signal::Signal; use persistent_container::{PersistentContainer, Subcontainer}; -use rpc_toolkit::{from_fn_async, CallRemoteHandler, Empty, HandlerArgs, HandlerFor}; +use rpc_toolkit::{HandlerArgs, HandlerFor}; use serde::{Deserialize, Serialize}; use service_actor::ServiceActor; use start_stop::StartStop; @@ -47,11 +47,11 @@ use crate::service::action::update_tasks; use crate::service::rpc::{ExitParams, InitKind}; use crate::service::service_map::InstallProgressHandles; use crate::service::uninstall::cleanup; +use crate::util::Never; use crate::util::actor::concurrent::ConcurrentActor; -use crate::util::io::{create_file, delete_file, AsyncReadStream, TermSize}; +use crate::util::io::{AsyncReadStream, TermSize, create_file, delete_file}; use crate::util::net::WebSocketExt; use crate::util::serde::Pem; -use crate::util::Never; use crate::volume::data_dir; use crate::{CAP_1_KiB, DATA_DIR}; @@ -707,57 +707,6 @@ pub async fn rebuild(ctx: RpcContext, RebuildParams { id }: RebuildParams) -> Re Ok(()) } -#[derive(Deserialize, Serialize, Parser, TS)] -pub struct ConnectParams { - pub id: PackageId, -} - -pub async fn connect_rpc( - ctx: RpcContext, - ConnectParams { id }: ConnectParams, -) -> Result { - let id_ref = &id; - crate::lxc::connect( - &ctx, - ctx.services - .get(&id) - .await - .as_ref() - .or_not_found(lazy_format!("service for {id_ref}"))? - .seed - .persistent_container - .lxc_container - .get() - .or_not_found(lazy_format!("container for {id_ref}"))?, - ) - .await -} - -pub async fn connect_rpc_cli( - HandlerArgs { - context, - parent_method, - method, - params, - inherited_params, - raw_params, - }: HandlerArgs, -) -> Result<(), Error> { - let ctx = context.clone(); - let guid = CallRemoteHandler::::new(from_fn_async(connect_rpc)) - .handle_async(HandlerArgs { - context, - parent_method, - method, - params: rpc_toolkit::util::Flat(params, Empty {}), - inherited_params, - raw_params, - }) - .await?; - - crate::lxc::connect_cli(&ctx, guid).await -} - #[derive(Deserialize, Serialize, TS)] #[serde(rename_all = "camelCase")] pub struct AttachParams { @@ -768,7 +717,7 @@ pub struct AttachParams { pub stderr_tty: bool, pub pty_size: Option, #[ts(skip)] - #[serde(rename = "__auth_session")] + #[serde(rename = "__Auth_session")] session: Option, #[ts(type = "string | null")] subcontainer: Option, diff --git a/core/startos/src/service/service_actor.rs b/core/startos/src/service/service_actor.rs index 697245c5d..4dd99a86e 100644 --- a/core/startos/src/service/service_actor.rs +++ b/core/startos/src/service/service_actor.rs @@ -1,6 +1,8 @@ use std::sync::Arc; use std::time::Duration; +use futures::FutureExt; +use futures::future::{BoxFuture, Either}; use imbl::vector; use super::ServiceActorSeed; @@ -16,131 +18,162 @@ use crate::util::actor::background::BackgroundJobQueue; #[derive(Clone)] pub(super) struct ServiceActor(pub(super) Arc); -enum ServiceActorLoopNext { - Wait, - DontWait, -} - impl Actor for ServiceActor { fn init(&mut self, jobs: &BackgroundJobQueue) { let seed = self.0.clone(); let mut current = seed.persistent_container.state.subscribe(); jobs.add_job(async move { let _ = current.wait_for(|s| s.rt_initialized).await; + let mut start_stop_task: Option> = None; loop { - match service_actor_loop(¤t, &seed).await { - ServiceActorLoopNext::Wait => tokio::select! { - _ = current.changed() => (), - }, - ServiceActorLoopNext::DontWait => (), - } + let wait = match service_actor_loop(¤t, &seed, &mut start_stop_task).await { + Ok(()) => Either::Right(current.changed().then(|res| async move { + match res { + Ok(()) => (), + Err(_) => futures::future::pending().await, + } + })), + Err(e) => { + tracing::error!("error synchronizing state of service: {e}"); + tracing::debug!("{e:?}"); + + seed.synchronized.notify_waiters(); + + tracing::error!("Retrying in {}s...", SYNC_RETRY_COOLDOWN_SECONDS); + Either::Left(tokio::time::sleep(Duration::from_secs( + SYNC_RETRY_COOLDOWN_SECONDS, + ))) + } + }; + tokio::pin!(wait); + let start_stop_handler = async { + match &mut start_stop_task { + Some(task) => { + let err = task.await.log_err().is_none(); // TODO: ideally this error should be sent to service logs + start_stop_task.take(); + if err { + tokio::time::sleep(Duration::from_secs( + SYNC_RETRY_COOLDOWN_SECONDS, + )) + .await; + } + } + _ => futures::future::pending().await, + } + }; + tokio::pin!(start_stop_handler); + futures::future::select(wait, start_stop_handler).await; } }); } } -async fn service_actor_loop( +async fn service_actor_loop<'a>( current: &tokio::sync::watch::Receiver, - seed: &Arc, -) -> ServiceActorLoopNext { + seed: &'a Arc, + start_stop_task: &mut Option< + Either>, BoxFuture<'a, Result<(), Error>>>, + >, +) -> Result<(), Error> { let id = &seed.id; let kinds = current.borrow().kinds(); - if let Err(e) = async { - let major_changes_state = seed - .ctx - .db - .mutate(|d| { - if let Some(i) = d.as_public_mut().as_package_data_mut().as_idx_mut(&id) { - let previous = i.as_status().de()?; - let main_status = match &kinds { - ServiceStateKinds { - transition_state: Some(TransitionKind::Restarting), - .. - } => MainStatus::Restarting, - ServiceStateKinds { - transition_state: Some(TransitionKind::BackingUp), - .. - } => previous.backing_up(), - ServiceStateKinds { - running_status: Some(status), - desired_state: StartStop::Start, - .. - } => MainStatus::Running { - started: status.started, - health: previous.health().cloned().unwrap_or_default(), - }, - ServiceStateKinds { - running_status: None, - desired_state: StartStop::Start, - .. - } => MainStatus::Starting { - health: previous.health().cloned().unwrap_or_default(), - }, - ServiceStateKinds { - running_status: Some(_), - desired_state: StartStop::Stop, - .. - } => MainStatus::Stopping, - ServiceStateKinds { - running_status: None, - desired_state: StartStop::Stop, - .. - } => MainStatus::Stopped, - }; - i.as_status_mut().ser(&main_status)?; - return Ok(previous - .major_changes(&main_status) - .then_some((previous, main_status))); - } - Ok(None) - }) - .await - .result?; - if let Some((previous, new_state)) = major_changes_state { - if let Some(callbacks) = seed.ctx.callbacks.get_status(id) { - callbacks - .call(vector![to_value(&previous)?, to_value(&new_state)?]) - .await?; + + let major_changes_state = seed + .ctx + .db + .mutate(|d| { + if let Some(i) = d.as_public_mut().as_package_data_mut().as_idx_mut(&id) { + let previous = i.as_status().de()?; + let main_status = match &kinds { + ServiceStateKinds { + transition_state: Some(TransitionKind::Restarting), + .. + } => MainStatus::Restarting, + ServiceStateKinds { + transition_state: Some(TransitionKind::BackingUp), + .. + } => previous.backing_up(), + ServiceStateKinds { + running_status: Some(status), + desired_state: StartStop::Start, + .. + } => MainStatus::Running { + started: status.started, + health: previous.health().cloned().unwrap_or_default(), + }, + ServiceStateKinds { + running_status: None, + desired_state: StartStop::Start, + .. + } => MainStatus::Starting { + health: previous.health().cloned().unwrap_or_default(), + }, + ServiceStateKinds { + running_status: Some(_), + desired_state: StartStop::Stop, + .. + } => MainStatus::Stopping, + ServiceStateKinds { + running_status: None, + desired_state: StartStop::Stop, + .. + } => MainStatus::Stopped, + }; + i.as_status_mut().ser(&main_status)?; + return Ok(previous + .major_changes(&main_status) + .then_some((previous, main_status))); } + Ok(None) + }) + .await + .result?; + + if let Some((previous, new_state)) = major_changes_state { + if let Some(callbacks) = seed.ctx.callbacks.get_status(id) { + callbacks + .call(vector![to_value(&previous)?, to_value(&new_state)?]) + .await?; } - seed.synchronized.notify_waiters(); - - match kinds { - ServiceStateKinds { - running_status: None, - desired_state: StartStop::Start, - .. - } => { - seed.persistent_container.start().await?; - } - ServiceStateKinds { - running_status: Some(_), - desired_state: StartStop::Stop, - .. - } => { - seed.persistent_container.stop().await?; - seed.persistent_container - .state - .send_if_modified(|s| s.running_status.take().is_some()); - } - _ => (), - }; - - Ok::<_, Error>(()) - } - .await - { - tracing::error!("error synchronizing state of service: {e}"); - tracing::debug!("{e:?}"); - - seed.synchronized.notify_waiters(); - - tracing::error!("Retrying in {}s...", SYNC_RETRY_COOLDOWN_SECONDS); - tokio::time::sleep(Duration::from_secs(SYNC_RETRY_COOLDOWN_SECONDS)).await; - return ServiceActorLoopNext::DontWait; } seed.synchronized.notify_waiters(); - ServiceActorLoopNext::Wait + match kinds { + ServiceStateKinds { + running_status: None, + desired_state: StartStop::Start, + .. + } => { + let task = start_stop_task + .take() + .filter(|task| matches!(task, Either::Right(_))); + *start_stop_task = Some( + task.unwrap_or_else(|| Either::Right(seed.persistent_container.start().boxed())), + ); + } + ServiceStateKinds { + running_status: Some(_), + desired_state: StartStop::Stop, + .. + } => { + let task = start_stop_task + .take() + .filter(|task| matches!(task, Either::Left(_))); + *start_stop_task = Some(task.unwrap_or_else(|| { + Either::Left( + async { + seed.persistent_container.stop().await?; + seed.persistent_container + .state + .send_if_modified(|s| s.running_status.take().is_some()); + Ok::<_, Error>(()) + } + .boxed(), + ) + })); + } + _ => (), + }; + Ok(()) } diff --git a/core/startos/src/system.rs b/core/startos/src/system.rs index e4befb77f..a76ca8641 100644 --- a/core/startos/src/system.rs +++ b/core/startos/src/system.rs @@ -1,6 +1,5 @@ use std::collections::BTreeSet; use std::fmt; -use std::sync::Arc; use std::time::Duration; use chrono::Utc; @@ -10,8 +9,6 @@ use futures::{FutureExt, TryStreamExt}; use imbl::vector; use imbl_value::InternedString; use rpc_toolkit::{Context, Empty, HandlerExt, ParentHandler, from_fn_async}; -use rustls::RootCertStore; -use rustls_pki_types::CertificateDer; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use tokio::process::Command; use tokio::sync::broadcast::Receiver; @@ -1024,7 +1021,7 @@ pub struct TestSmtpParams { #[arg(long)] pub login: String, #[arg(long)] - pub password: Option, + pub password: String, } pub async fn test_smtp( _: RpcContext, @@ -1037,74 +1034,23 @@ pub async fn test_smtp( password, }: TestSmtpParams, ) -> Result<(), Error> { - #[cfg(feature = "mail-send")] - { - use mail_send::SmtpClientBuilder; - use mail_send::mail_builder::{self, MessageBuilder}; - use rustls_pki_types::pem::PemObject; + use lettre::message::header::ContentType; + use lettre::transport::smtp::authentication::Credentials; + use lettre::{AsyncSmtpTransport, AsyncTransport, Message, Tokio1Executor}; - let Some(pass_val) = password else { - return Err(Error::new( - eyre!("mail-send requires a password"), - ErrorKind::InvalidRequest, - )); - }; - - let mut root_cert_store = RootCertStore::empty(); - let pem = tokio::fs::read("/etc/ssl/certs/ca-certificates.crt").await?; - for cert in CertificateDer::pem_slice_iter(&pem) { - root_cert_store.add_parsable_certificates([cert.with_kind(ErrorKind::OpenSsl)?]); - } - - let cfg = Arc::new( - rustls::ClientConfig::builder_with_provider(Arc::new( - rustls::crypto::ring::default_provider(), - )) - .with_safe_default_protocol_versions()? - .with_root_certificates(root_cert_store) - .with_no_client_auth(), - ); - let client = SmtpClientBuilder::new_with_tls_config(server, port, cfg) - .implicit_tls(false) - .credentials((login.split("@").next().unwrap().to_owned(), pass_val)); - - fn parse_address<'a>(addr: &'a str) -> mail_builder::headers::address::Address<'a> { - if addr.find("<").map_or(false, |start| { - addr.find(">").map_or(false, |end| start < end) - }) { - addr.split_once("<") - .map(|(name, addr)| (name.trim(), addr.strip_suffix(">").unwrap_or(addr))) - .unwrap() - .into() - } else { - addr.into() - } - } - - let message = MessageBuilder::new() - .from(parse_address(&from)) - .to(parse_address(&to)) - .subject("StartOS Test Email") - .text_body("This is a test email sent from your StartOS Server"); - client - .connect() - .await - .map_err(|e| { - Error::new( - eyre!("mail-send connection error: {:?}", e), - ErrorKind::Unknown, - ) - })? - .send(message) - .await - .map_err(|e| Error::new(eyre!("mail-send send error: {:?}", e), ErrorKind::Unknown))?; - Ok(()) - } - #[cfg(not(feature = "mail-send"))] - Err(Error::new( - eyre!("test-smtp requires mail-send feature to be enabled"), - ErrorKind::InvalidRequest, - )) + AsyncSmtpTransport::::relay(&server)? + .credentials(Credentials::new(login, password)) + .build() + .send( + Message::builder() + .from(from.parse()?) + .to(to.parse()?) + .subject("StartOS Test Email") + .header(ContentType::TEXT_PLAIN) + .body("This is a test email sent from your StartOS Server".to_owned())?, + ) + .await?; + Ok(()) } #[tokio::test] diff --git a/core/startos/src/tunnel/api.rs b/core/startos/src/tunnel/api.rs index da73232f2..e2e60ffe7 100644 --- a/core/startos/src/tunnel/api.rs +++ b/core/startos/src/tunnel/api.rs @@ -1,49 +1,61 @@ -use std::net::Ipv4Addr; +use std::net::{IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4}; use clap::Parser; +use imbl_value::InternedString; use ipnet::Ipv4Net; -use rpc_toolkit::{from_fn_async, Context, Empty, HandlerExt, ParentHandler}; +use rpc_toolkit::{Context, Empty, HandlerArgs, HandlerExt, ParentHandler, from_fn_async}; use serde::{Deserialize, Serialize}; use crate::context::CliContext; use crate::prelude::*; use crate::tunnel::context::TunnelContext; -use crate::tunnel::wg::WgSubnetConfig; +use crate::tunnel::wg::{WgConfig, WgSubnetClients, WgSubnetConfig}; +use crate::util::serde::{HandlerExtSerde, display_serializable}; pub fn tunnel_api() -> ParentHandler { ParentHandler::new() + .subcommand("web", super::web::web_api::()) .subcommand( "db", super::db::db_api::() .with_about("Commands to interact with the db i.e. dump and apply"), ) + .subcommand( + "auth", + super::auth::auth_api::().with_about("Add or remove authorized clients"), + ) .subcommand( "subnet", subnet_api::().with_about("Add, remove, or modify subnets"), ) - // .subcommand( - // "port-forward", - // ParentHandler::::new() - // .subcommand( - // "add", - // from_fn_async(add_forward) - // .with_metadata("sync_db", Value::Bool(true)) - // .no_display() - // .with_about("Add a new port forward") - // .with_call_remote::(), - // ) - // .subcommand( - // "remove", - // from_fn_async(remove_forward) - // .with_metadata("sync_db", Value::Bool(true)) - // .no_display() - // .with_about("Remove a port forward") - // .with_call_remote::(), - // ), - // ) + .subcommand( + "device", + device_api::().with_about("Add, remove, or list devices in subnets"), + ) + .subcommand( + "port-forward", + ParentHandler::::new() + .subcommand( + "add", + from_fn_async(add_forward) + .with_metadata("sync_db", Value::Bool(true)) + .no_display() + .with_about("Add a new port forward") + .with_call_remote::(), + ) + .subcommand( + "remove", + from_fn_async(remove_forward) + .with_metadata("sync_db", Value::Bool(true)) + .no_display() + .with_about("Remove a port forward") + .with_call_remote::(), + ), + ) } #[derive(Deserialize, Serialize, Parser)] +#[serde(rename_all = "camelCase")] pub struct SubnetParams { subnet: Ipv4Net, } @@ -68,44 +80,89 @@ pub fn subnet_api() -> ParentHandler { .with_about("Remove a subnet") .with_call_remote::(), ) - // .subcommand( - // "set-default-forward-target", - // from_fn_async(set_default_forward_target) - // .with_metadata("sync_db", Value::Bool(true)) - // .no_display() - // .with_about("Set the default target for port forwarding") - // .with_call_remote::(), - // ) - // .subcommand( - // "add-device", - // from_fn_async(add_device) - // .with_metadata("sync_db", Value::Bool(true)) - // .no_display() - // .with_about("Add a device to a subnet") - // .with_call_remote::(), - // ) - // .subcommand( - // "remove-device", - // from_fn_async(remove_device) - // .with_metadata("sync_db", Value::Bool(true)) - // .no_display() - // .with_about("Remove a device from a subnet") - // .with_call_remote::(), - // ) +} + +pub fn device_api() -> ParentHandler { + ParentHandler::new() + .subcommand( + "add", + from_fn_async(add_device) + .with_metadata("sync_db", Value::Bool(true)) + .no_display() + .with_about("Add a device to a subnet") + .with_call_remote::(), + ) + .subcommand( + "remove", + from_fn_async(remove_device) + .with_metadata("sync_db", Value::Bool(true)) + .no_display() + .with_about("Remove a device from a subnet") + .with_call_remote::(), + ) + .subcommand( + "list", + from_fn_async(list_devices) + .with_display_serializable() + .with_custom_display_fn(|HandlerArgs { params, .. }, res| { + use prettytable::*; + + if let Some(format) = params.format { + return display_serializable(format, res); + } + + let mut table = Table::new(); + table.add_row(row![bc => "NAME", "IP", "PUBLIC KEY"]); + for (ip, config) in res.clients.0 { + table.add_row(row![config.name, ip, config.key.verifying_key()]); + } + + table.print_tty(false)?; + + Ok(()) + }) + .with_about("List devices in a subnet") + .with_call_remote::(), + ) + .subcommand( + "show-config", + from_fn_async(show_config) + .with_about("Show the WireGuard configuration for a device") + .with_call_remote::(), + ) +} + +#[derive(Deserialize, Serialize, Parser)] +#[serde(rename_all = "camelCase")] +pub struct AddSubnetParams { + name: InternedString, } pub async fn add_subnet( ctx: TunnelContext, - _: Empty, - SubnetParams { subnet }: SubnetParams, + AddSubnetParams { name }: AddSubnetParams, + SubnetParams { mut subnet }: SubnetParams, ) -> Result<(), Error> { + if subnet.prefix_len() > 24 { + return Err(Error::new( + eyre!("invalid subnet"), + ErrorKind::InvalidRequest, + )); + } + let addr = subnet + .hosts() + .next() + .ok_or_else(|| Error::new(eyre!("invalid subnet"), ErrorKind::InvalidRequest))?; + subnet = Ipv4Net::new_assert(addr, subnet.prefix_len()); let server = ctx .db .mutate(|db| { let map = db.as_wg_mut().as_subnets_mut(); - if !map.contains_key(&subnet)? { - map.insert(&subnet, &WgSubnetConfig::new())?; - } + map.upsert(&subnet, || { + Ok(WgSubnetConfig::new(InternedString::default())) + })? + .as_name_mut() + .ser(&name)?; db.as_wg().de() }) .await @@ -128,3 +185,221 @@ pub async fn remove_subnet( .result?; server.sync().await } + +#[derive(Deserialize, Serialize, Parser)] +#[serde(rename_all = "camelCase")] +pub struct AddDeviceParams { + subnet: Ipv4Net, + name: InternedString, + ip: Option, +} + +pub async fn add_device( + ctx: TunnelContext, + AddDeviceParams { subnet, name, ip }: AddDeviceParams, +) -> Result<(), Error> { + let server = ctx + .db + .mutate(|db| { + db.as_wg_mut() + .as_subnets_mut() + .as_idx_mut(&subnet) + .or_not_found(&subnet)? + .as_clients_mut() + .mutate(|WgSubnetClients(clients)| { + let ip = if let Some(ip) = ip { + ip + } else { + subnet + .hosts() + .find(|ip| !clients.contains_key(ip) && *ip != subnet.addr()) + .ok_or_else(|| { + Error::new( + eyre!("no available ips in subnet"), + ErrorKind::InvalidRequest, + ) + })? + }; + + if ip.octets()[3] == 0 || ip.octets()[3] == 255 { + return Err(Error::new(eyre!("invalid ip"), ErrorKind::InvalidRequest)); + } + if ip == subnet.addr() { + return Err(Error::new(eyre!("invalid ip"), ErrorKind::InvalidRequest)); + } + if !subnet.contains(&ip) { + return Err(Error::new( + eyre!("ip not in subnet"), + ErrorKind::InvalidRequest, + )); + } + let client = clients + .entry(ip) + .or_insert_with(|| WgConfig::generate(name.clone())); + client.name = name; + + Ok(()) + })?; + db.as_wg().de() + }) + .await + .result?; + server.sync().await +} + +#[derive(Deserialize, Serialize, Parser)] +#[serde(rename_all = "camelCase")] +pub struct RemoveDeviceParams { + subnet: Ipv4Net, + ip: Ipv4Addr, +} + +pub async fn remove_device( + ctx: TunnelContext, + RemoveDeviceParams { subnet, ip }: RemoveDeviceParams, +) -> Result<(), Error> { + let server = ctx + .db + .mutate(|db| { + db.as_wg_mut() + .as_subnets_mut() + .as_idx_mut(&subnet) + .or_not_found(&subnet)? + .as_clients_mut() + .remove(&ip)? + .or_not_found(&ip)?; + db.as_wg().de() + }) + .await + .result?; + server.sync().await +} + +#[derive(Deserialize, Serialize, Parser)] +#[serde(rename_all = "camelCase")] +pub struct ListDevicesParams { + subnet: Ipv4Net, +} + +pub async fn list_devices( + ctx: TunnelContext, + ListDevicesParams { subnet }: ListDevicesParams, +) -> Result { + ctx.db + .peek() + .await + .as_wg() + .as_subnets() + .as_idx(&subnet) + .or_not_found(&subnet)? + .de() +} + +#[derive(Deserialize, Serialize, Parser)] +#[serde(rename_all = "camelCase")] +pub struct ShowConfigParams { + subnet: Ipv4Net, + ip: Ipv4Addr, + wan_addr: Option, + #[serde(rename = "__ConnectInfo_local_addr")] + #[arg(skip)] + local_addr: Option, +} + +pub async fn show_config( + ctx: TunnelContext, + ShowConfigParams { + subnet, + ip, + wan_addr, + local_addr, + }: ShowConfigParams, +) -> Result { + let peek = ctx.db.peek().await; + let wg = peek.as_wg(); + let client = wg + .as_subnets() + .as_idx(&subnet) + .or_not_found(&subnet)? + .as_clients() + .as_idx(&ip) + .or_not_found(&ip)? + .de()?; + let wan_addr = if let Some(wan_addr) = wan_addr.or(local_addr.map(|a| a.ip())).filter(|ip| { + !ip.is_loopback() + && !match ip { + IpAddr::V4(ipv4) => ipv4.is_private() || ipv4.is_link_local(), + IpAddr::V6(ipv6) => ipv6.is_unique_local() || ipv6.is_unicast_link_local(), + } + }) { + wan_addr + } else if let Some(webserver) = peek.as_webserver().as_listen().de()? { + webserver.ip() + } else { + ctx.net_iface + .peek(|i| { + i.iter().find_map(|(_, info)| { + info.ip_info + .as_ref() + .filter(|_| info.public()) + .iter() + .find_map(|info| info.subnets.iter().next()) + .copied() + }) + }) + .or_not_found("a public IP address")? + .addr() + }; + Ok(client + .client_config( + ip, + wg.as_key().de()?.verifying_key(), + (wan_addr, wg.as_port().de()?).into(), + ) + .to_string()) +} + +#[derive(Deserialize, Serialize, Parser)] +#[serde(rename_all = "camelCase")] +pub struct AddPortForwardParams { + source: SocketAddrV4, + target: SocketAddrV4, +} + +pub async fn add_forward( + ctx: TunnelContext, + AddPortForwardParams { source, target }: AddPortForwardParams, +) -> Result<(), Error> { + let rc = ctx.forward.add_forward(source, target).await?; + ctx.active_forwards.mutate(|m| { + m.insert(source, rc); + }); + + ctx.db + .mutate(|db| db.as_port_forwards_mut().insert(&source, &target)) + .await + .result?; + + Ok(()) +} + +#[derive(Deserialize, Serialize, Parser)] +#[serde(rename_all = "camelCase")] +pub struct RemovePortForwardParams { + source: SocketAddrV4, +} + +pub async fn remove_forward( + ctx: TunnelContext, + RemovePortForwardParams { source, .. }: RemovePortForwardParams, +) -> Result<(), Error> { + ctx.db + .mutate(|db| db.as_port_forwards_mut().remove(&source)) + .await + .result?; + if let Some(rc) = ctx.active_forwards.mutate(|m| m.remove(&source)) { + drop(rc); + ctx.forward.gc().await?; + } + Ok(()) +} diff --git a/core/startos/src/tunnel/auth.rs b/core/startos/src/tunnel/auth.rs new file mode 100644 index 000000000..21482980f --- /dev/null +++ b/core/startos/src/tunnel/auth.rs @@ -0,0 +1,323 @@ +use clap::Parser; +use imbl::HashMap; +use imbl_value::InternedString; +use itertools::Itertools; +use patch_db::HasModel; +use rpc_toolkit::{Context, HandlerArgs, HandlerExt, ParentHandler, from_fn_async}; +use serde::{Deserialize, Serialize}; +use ts_rs::TS; + +use crate::auth::{Sessions, check_password}; +use crate::context::CliContext; +use crate::middleware::auth::AuthContext; +use crate::middleware::signature::SignatureAuthContext; +use crate::prelude::*; +use crate::rpc_continuations::OpenAuthedContinuations; +use crate::sign::AnyVerifyingKey; +use crate::tunnel::context::TunnelContext; +use crate::tunnel::db::TunnelDatabase; +use crate::util::serde::{HandlerExtSerde, display_serializable}; +use crate::util::sync::SyncMutex; + +impl SignatureAuthContext for TunnelContext { + type Database = TunnelDatabase; + type AdditionalMetadata = (); + type CheckPubkeyRes = (); + fn db(&self) -> &TypedPatchDb { + &self.db + } + async fn sig_context( + &self, + ) -> impl IntoIterator + Send, Error>> + Send { + let peek = self.db().peek().await; + peek.as_webserver() + .as_listen() + .de() + .map(|a| a.as_ref().map(InternedString::from_display)) + .transpose() + .into_iter() + .chain( + std::iter::once_with(move || { + peek.as_webserver() + .as_certificate() + .de() + .ok() + .flatten() + .and_then(|cert_data| cert_data.cert.0.first().cloned()) + .and_then(|cert| cert.subject_alt_names()) + .into_iter() + .flatten() + .filter_map(|san| { + san.dnsname().map(InternedString::from).or_else(|| { + san.ipaddress().and_then(|ip_bytes| { + let ip: std::net::IpAddr = match ip_bytes.len() { + 4 => std::net::IpAddr::V4(std::net::Ipv4Addr::from( + <[u8; 4]>::try_from(ip_bytes).ok()?, + )), + 16 => std::net::IpAddr::V6(std::net::Ipv6Addr::from( + <[u8; 16]>::try_from(ip_bytes).ok()?, + )), + _ => return None, + }; + Some(InternedString::from_display(&ip)) + }) + }) + }) + .map(Ok) + .collect::>() + }) + .flatten(), + ) + } + fn check_pubkey( + db: &Model, + pubkey: Option<&crate::sign::AnyVerifyingKey>, + _: Self::AdditionalMetadata, + ) -> Result { + if let Some(pubkey) = pubkey { + if db.as_auth_pubkeys().de()?.contains_key(pubkey) { + return Ok(()); + } + } + + Err(Error::new( + eyre!("Key is not authorized"), + ErrorKind::IncorrectPassword, + )) + } + async fn post_auth_hook( + &self, + _: Self::CheckPubkeyRes, + _: &rpc_toolkit::RpcRequest, + ) -> Result<(), Error> { + Ok(()) + } +} +impl AuthContext for TunnelContext { + const LOCAL_AUTH_COOKIE_PATH: &str = "/run/start-tunnel/rpc.authcookie"; + const LOCAL_AUTH_COOKIE_OWNERSHIP: &str = "root:root"; + fn access_sessions(db: &mut Model) -> &mut Model { + db.as_sessions_mut() + } + fn ephemeral_sessions(&self) -> &SyncMutex { + &self.ephemeral_sessions + } + fn open_authed_continuations(&self) -> &OpenAuthedContinuations> { + &self.open_authed_continuations + } + fn check_password(db: &Model, password: &str) -> Result<(), Error> { + check_password(&db.as_password().de()?.unwrap_or_default(), password) + } +} + +#[derive(Clone, Debug, Deserialize, Serialize, HasModel, TS, Parser)] +#[serde(rename_all = "camelCase")] +#[model = "Model"] +#[ts(export)] +pub struct SignerInfo { + pub name: InternedString, +} + +pub fn auth_api() -> ParentHandler { + ParentHandler::new() + .subcommand( + "login", + from_fn_async(crate::auth::login_impl::) + .with_metadata("login", Value::Bool(true)) + .no_cli(), + ) + .subcommand( + "logout", + from_fn_async(crate::auth::logout::) + .with_metadata("get_session", Value::Bool(true)) + .no_display() + .with_about("Log out of current auth session") + .with_call_remote::(), + ) + .subcommand("set-password", from_fn_async(set_password_rpc).no_cli()) + .subcommand( + "set-password", + from_fn_async(set_password_cli) + .with_about("Set user interface password") + .no_display(), + ) + .subcommand( + "reset-password", + from_fn_async(reset_password) + .with_about("Reset user interface password") + .no_display(), + ) + .subcommand( + "key", + ParentHandler::::new() + .subcommand( + "add", + from_fn_async(add_key) + .with_metadata("sync_db", Value::Bool(true)) + .no_display() + .with_about("Add a new authorized key") + .with_call_remote::(), + ) + .subcommand( + "remove", + from_fn_async(remove_key) + .with_metadata("sync_db", Value::Bool(true)) + .no_display() + .with_about("Remove an authorized key") + .with_call_remote::(), + ) + .subcommand( + "list", + from_fn_async(list_keys) + .with_metadata("sync_db", Value::Bool(true)) + .with_display_serializable() + .with_custom_display_fn(|HandlerArgs { params, .. }, res| { + use prettytable::*; + + if let Some(format) = params.format { + return display_serializable(format, res); + } + + let mut table = Table::new(); + table.add_row(row![bc => "NAME", "KEY"]); + for (key, info) in res { + table.add_row(row![info.name, key]); + } + + table.print_tty(false)?; + + Ok(()) + }) + .with_about("List authorized keys") + .with_call_remote::(), + ), + ) +} + +#[derive(Debug, Deserialize, Serialize, Parser)] +#[serde(rename_all = "camelCase")] +pub struct AddKeyParams { + pub name: InternedString, + pub key: AnyVerifyingKey, +} + +pub async fn add_key( + ctx: TunnelContext, + AddKeyParams { name, key }: AddKeyParams, +) -> Result<(), Error> { + ctx.db + .mutate(|db| { + db.as_auth_pubkeys_mut().mutate(|auth_pubkeys| { + auth_pubkeys.insert(key, SignerInfo { name }); + Ok(()) + }) + }) + .await + .result +} + +#[derive(Debug, Deserialize, Serialize, Parser)] +#[serde(rename_all = "camelCase")] +pub struct RemoveKeyParams { + pub key: AnyVerifyingKey, +} + +pub async fn remove_key( + ctx: TunnelContext, + RemoveKeyParams { key }: RemoveKeyParams, +) -> Result<(), Error> { + ctx.db + .mutate(|db| { + db.as_auth_pubkeys_mut() + .mutate(|auth_pubkeys| Ok(auth_pubkeys.remove(&key))) + }) + .await + .result?; + Ok(()) +} + +pub async fn list_keys(ctx: TunnelContext) -> Result, Error> { + ctx.db.peek().await.into_auth_pubkeys().de() +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct SetPasswordParams { + pub password: String, +} + +pub async fn set_password_rpc( + ctx: TunnelContext, + SetPasswordParams { password }: SetPasswordParams, +) -> Result<(), Error> { + let pwhash = argon2::hash_encoded( + password.as_bytes(), + &rand::random::<[u8; 16]>(), + &argon2::Config::rfc9106_low_mem(), + ) + .with_kind(ErrorKind::PasswordHashGeneration)?; + ctx.db + .mutate(|db| db.as_password_mut().ser(&Some(pwhash))) + .await + .result?; + + Ok(()) +} + +pub async fn set_password_cli( + HandlerArgs { + context, + parent_method, + method, + .. + }: HandlerArgs, +) -> Result<(), Error> { + let password = rpassword::prompt_password("New Password: ")?; + let confirm = rpassword::prompt_password("Confirm Password: ")?; + + if password != confirm { + return Err(Error::new( + eyre!("Passwords do not match"), + ErrorKind::InvalidRequest, + )); + } + + context + .call_remote::( + &parent_method.iter().chain(method.iter()).join("."), + to_value(&SetPasswordParams { password })?, + ) + .await?; + + println!("Password set successfully"); + + Ok(()) +} + +pub async fn reset_password( + HandlerArgs { + context, + parent_method, + method, + .. + }: HandlerArgs, +) -> Result<(), Error> { + println!("Generating a random password..."); + let params = SetPasswordParams { + password: base32::encode( + base32::Alphabet::Rfc4648Lower { padding: false }, + &rand::random::<[u8; 16]>(), + ), + }; + + context + .call_remote::( + &parent_method.iter().chain(method.iter()).join("."), + to_value(¶ms)?, + ) + .await?; + + println!("Your new password is:"); + println!("{}", params.password); + + Ok(()) +} diff --git a/core/startos/src/tunnel/client.conf.template b/core/startos/src/tunnel/client.conf.template index 2c7735eb9..58673b890 100644 --- a/core/startos/src/tunnel/client.conf.template +++ b/core/startos/src/tunnel/client.conf.template @@ -1,3 +1,5 @@ +# StartTunnel config for {name} + [Interface] Address = {addr}/24 PrivateKey = {privkey} @@ -5,6 +7,6 @@ PrivateKey = {privkey} [Peer] PublicKey = {server_pubkey} PresharedKey = {psk} -AllowedIPs = 0.0.0.0/0, ::/0 +AllowedIPs = 0.0.0.0/0,::/0 Endpoint = {server_addr} PersistentKeepalive = 25 \ No newline at end of file diff --git a/core/startos/src/tunnel/context.rs b/core/startos/src/tunnel/context.rs index ff4b15a56..421e8e2e6 100644 --- a/core/startos/src/tunnel/context.rs +++ b/core/startos/src/tunnel/context.rs @@ -1,31 +1,44 @@ -use std::collections::BTreeSet; -use std::net::{IpAddr, Ipv6Addr, SocketAddr}; +use std::collections::BTreeMap; +use std::net::{IpAddr, SocketAddr, SocketAddrV4}; use std::ops::Deref; use std::path::{Path, PathBuf}; use std::sync::Arc; use clap::Parser; +use cookie::{Cookie, Expiration, SameSite}; +use http::HeaderMap; use imbl::OrdMap; use imbl_value::InternedString; +use include_dir::Dir; +use models::GatewayId; use patch_db::PatchDb; use rpc_toolkit::yajrc::RpcError; -use rpc_toolkit::{CallRemote, Context, Empty}; +use rpc_toolkit::{CallRemote, Context, Empty, ParentHandler}; use serde::{Deserialize, Serialize}; +use tokio::process::Command; use tokio::sync::broadcast::Sender; use tracing::instrument; +use url::Url; -use crate::auth::{Sessions, check_password}; -use crate::context::CliContext; +use crate::auth::Sessions; use crate::context::config::ContextConfig; -use crate::middleware::auth::AuthContext; -use crate::middleware::signature::SignatureAuthContext; +use crate::context::{CliContext, RpcContext}; +use crate::db::model::public::{NetworkInterfaceInfo, NetworkInterfaceType}; +use crate::else_empty_dir; +use crate::middleware::auth::{Auth, AuthContext}; +use crate::middleware::cors::Cors; use crate::net::forward::PortForwardController; -use crate::net::gateway::NetworkInterfaceWatcher; +use crate::net::static_server::UiContext; use crate::prelude::*; use crate::rpc_continuations::{OpenAuthedContinuations, RpcContinuations}; -use crate::tunnel::TUNNEL_DEFAULT_PORT; +use crate::tunnel::TUNNEL_DEFAULT_LISTEN; +use crate::tunnel::api::tunnel_api; use crate::tunnel::db::TunnelDatabase; -use crate::util::sync::SyncMutex; +use crate::tunnel::wg::WIREGUARD_INTERFACE_NAME; +use crate::util::Invoke; +use crate::util::collections::OrdMapIterMut; +use crate::util::io::read_file_to_string; +use crate::util::sync::{SyncMutex, Watch}; #[derive(Debug, Clone, Default, Deserialize, Serialize, Parser)] #[serde(rename_all = "kebab-case")] @@ -59,14 +72,14 @@ impl TunnelConfig { pub struct TunnelContextSeed { pub listen: SocketAddr, - pub addrs: BTreeSet, pub db: TypedPatchDb, pub datadir: PathBuf, pub rpc_continuations: RpcContinuations, pub open_authed_continuations: OpenAuthedContinuations>, pub ephemeral_sessions: SyncMutex, - pub net_iface: NetworkInterfaceWatcher, + pub net_iface: Watch>, pub forward: PortForwardController, + pub active_forwards: SyncMutex>>, pub shutdown: Sender<()>, } @@ -75,6 +88,7 @@ pub struct TunnelContext(Arc); impl TunnelContext { #[instrument(skip_all)] pub async fn init(config: &TunnelConfig) -> Result { + Self::init_auth_cookie().await?; let (shutdown, _) = tokio::sync::broadcast::channel(1); let datadir = config .datadir @@ -90,19 +104,83 @@ impl TunnelContext { || async { Ok(Default::default()) }, ) .await?; - let listen = config.tunnel_listen.unwrap_or(SocketAddr::new( - Ipv6Addr::UNSPECIFIED.into(), - TUNNEL_DEFAULT_PORT, - )); - let net_iface = NetworkInterfaceWatcher::new(async { OrdMap::new() }, []); - let forward = PortForwardController::new(net_iface.subscribe()); + let listen = config.tunnel_listen.unwrap_or(TUNNEL_DEFAULT_LISTEN); + let ip_info = crate::net::utils::load_ip_info().await?; + let net_iface = db + .mutate(|db| { + db.as_gateways_mut().mutate(|g| { + for (_, v) in OrdMapIterMut::from(&mut *g) { + v.ip_info = None; + } + for (id, info) in ip_info { + if id.as_str() != WIREGUARD_INTERFACE_NAME { + g.entry(id).or_default().ip_info = Some(Arc::new(info)); + } + } + Ok(g.clone()) + }) + }) + .await + .result?; + let net_iface = Watch::new(net_iface); + let forward = PortForwardController::new(); + + Command::new("sysctl") + .arg("-w") + .arg("net.ipv4.ip_forward=1") + .invoke(ErrorKind::Network) + .await?; + + for iface in net_iface.peek(|i| { + i.iter() + .filter(|(_, info)| { + info.ip_info.as_ref().map_or(false, |i| { + i.device_type != Some(NetworkInterfaceType::Loopback) + }) + }) + .map(|(name, _)| name) + .filter(|id| id.as_str() != WIREGUARD_INTERFACE_NAME) + .cloned() + .collect::>() + }) { + if Command::new("iptables") + .arg("-t") + .arg("nat") + .arg("-C") + .arg("POSTROUTING") + .arg("-o") + .arg(iface.as_str()) + .arg("-j") + .arg("MASQUERADE") + .invoke(ErrorKind::Network) + .await + .is_err() + { + tracing::info!("Adding masquerade rule for interface {}", iface); + Command::new("iptables") + .arg("-t") + .arg("nat") + .arg("-A") + .arg("POSTROUTING") + .arg("-o") + .arg(iface.as_str()) + .arg("-j") + .arg("MASQUERADE") + .invoke(ErrorKind::Network) + .await + .log_err(); + } + } + + let peek = db.peek().await; + peek.as_wg().de()?.sync().await?; + let mut active_forwards = BTreeMap::new(); + for (from, to) in peek.as_port_forwards().de()?.0 { + active_forwards.insert(from, forward.add_forward(from, to).await?); + } + Ok(Self(Arc::new(TunnelContextSeed { listen, - addrs: crate::net::utils::all_socket_addrs_for(listen.port()) - .await? - .into_iter() - .map(|(_, a)| a.ip()) - .collect(), db, datadir, rpc_continuations: RpcContinuations::new(), @@ -110,6 +188,7 @@ impl TunnelContext { ephemeral_sessions: SyncMutex::new(Sessions::new()), net_iface, forward, + active_forwards: SyncMutex::new(active_forwards), shutdown, }))) } @@ -120,6 +199,12 @@ impl AsRef for TunnelContext { } } +impl AsRef>> for TunnelContext { + fn as_ref(&self) -> &OpenAuthedContinuations> { + &self.open_authed_continuations + } +} + impl Context for TunnelContext {} impl Deref for TunnelContext { type Target = TunnelContextSeed; @@ -133,66 +218,6 @@ pub struct TunnelAddrParams { pub tunnel: IpAddr, } -impl SignatureAuthContext for TunnelContext { - type Database = TunnelDatabase; - type AdditionalMetadata = (); - type CheckPubkeyRes = (); - fn db(&self) -> &TypedPatchDb { - &self.db - } - async fn sig_context( - &self, - ) -> impl IntoIterator + Send, Error>> + Send { - self.addrs - .iter() - .filter(|a| !match a { - IpAddr::V4(a) => a.is_loopback() || a.is_unspecified(), - IpAddr::V6(a) => a.is_loopback() || a.is_unspecified(), - }) - .map(|a| InternedString::from_display(&a)) - .map(Ok) - } - fn check_pubkey( - db: &Model, - pubkey: Option<&crate::sign::AnyVerifyingKey>, - _: Self::AdditionalMetadata, - ) -> Result { - if let Some(pubkey) = pubkey { - if db.as_auth_pubkeys().de()?.contains(pubkey) { - return Ok(()); - } - } - - Err(Error::new( - eyre!("Developer Key is not authorized"), - ErrorKind::IncorrectPassword, - )) - } - async fn post_auth_hook( - &self, - _: Self::CheckPubkeyRes, - _: &rpc_toolkit::RpcRequest, - ) -> Result<(), Error> { - Ok(()) - } -} -impl AuthContext for TunnelContext { - const LOCAL_AUTH_COOKIE_PATH: &str = "/run/start-tunnel/rpc.authcookie"; - const LOCAL_AUTH_COOKIE_OWNERSHIP: &str = "root:root"; - fn access_sessions(db: &mut Model) -> &mut Model { - db.as_sessions_mut() - } - fn ephemeral_sessions(&self) -> &SyncMutex { - &self.ephemeral_sessions - } - fn open_authed_continuations(&self) -> &OpenAuthedContinuations> { - &self.open_authed_continuations - } - fn check_password(db: &Model, password: &str) -> Result<(), Error> { - check_password(&db.as_password().de()?, password) - } -} - impl CallRemote for CliContext { async fn call_remote( &self, @@ -200,25 +225,97 @@ impl CallRemote for CliContext { params: Value, _: Empty, ) -> Result { - let tunnel_addr = if let Some(addr) = self.tunnel_addr { - addr + let (tunnel_addr, addr_from_config) = if let Some(addr) = self.tunnel_addr { + (addr, true) } else if let Some(addr) = self.tunnel_listen { - addr + (addr, true) + } else { + (TUNNEL_DEFAULT_LISTEN, false) + }; + + let local = + if let Ok(local) = read_file_to_string(TunnelContext::LOCAL_AUTH_COOKIE_PATH).await { + self.cookie_store + .lock() + .unwrap() + .insert_raw( + &Cookie::build(("local", local)) + .domain(&tunnel_addr.ip().to_string()) + .expires(Expiration::Session) + .same_site(SameSite::Strict) + .build(), + &format!("http://{tunnel_addr}").parse()?, + ) + .with_kind(crate::ErrorKind::Network)?; + true + } else { + false + }; + + let (url, sig_ctx) = if local && tunnel_addr.ip().is_loopback() { + (format!("http://{tunnel_addr}/rpc/v0").parse()?, None) + } else if addr_from_config { + ( + format!("https://{tunnel_addr}/rpc/v0").parse()?, + Some(InternedString::from_display(&tunnel_addr.ip())), + ) } else { return Err(Error::new(eyre!("`--tunnel` required"), ErrorKind::InvalidRequest).into()); }; - let sig_addr = self.tunnel_listen.unwrap_or(tunnel_addr); - let url = format!("https://{tunnel_addr}").parse()?; method = method.strip_prefix("tunnel.").unwrap_or(method); crate::middleware::signature::call_remote( self, url, - &InternedString::from_display(&sig_addr.ip()), + HeaderMap::new(), + sig_ctx.as_deref(), method, params, ) .await } } + +#[derive(Debug, Deserialize, Serialize, Parser)] +pub struct TunnelUrlParams { + pub tunnel: Url, +} + +impl CallRemote for RpcContext { + async fn call_remote( + &self, + mut method: &str, + params: Value, + TunnelUrlParams { tunnel }: TunnelUrlParams, + ) -> Result { + let url = tunnel.join("rpc/v0")?; + method = method.strip_prefix("tunnel.").unwrap_or(method); + + let sig_ctx = url.host_str().map(InternedString::from_display); + + crate::middleware::signature::call_remote( + self, + url, + HeaderMap::new(), + sig_ctx.as_deref(), + method, + params, + ) + .await + } +} + +impl UiContext for TunnelContext { + const UI_DIR: &'static include_dir::Dir<'static> = &else_empty_dir!( + feature = "tunnel" => + include_dir::include_dir!("$CARGO_MANIFEST_DIR/../../web/dist/static/start-tunnel") + ); + fn api() -> ParentHandler { + tracing::info!("loading tunnel api..."); + tunnel_api() + } + fn middleware(server: rpc_toolkit::Server) -> rpc_toolkit::HttpServer { + server.middleware(Cors::new()).middleware(Auth::new()) + } +} diff --git a/core/startos/src/tunnel/db.rs b/core/startos/src/tunnel/db.rs index 23ed05c63..cbdbd46d2 100644 --- a/core/startos/src/tunnel/db.rs +++ b/core/startos/src/tunnel/db.rs @@ -1,11 +1,14 @@ -use std::collections::{BTreeMap, HashSet}; -use std::net::{Ipv4Addr, SocketAddrV4}; +use std::collections::BTreeMap; +use std::net::SocketAddrV4; use std::path::PathBuf; +use std::time::Duration; +use axum::extract::ws; use clap::Parser; +use imbl::{HashMap, OrdMap}; use imbl_value::InternedString; -use ipnet::Ipv4Net; use itertools::Itertools; +use models::GatewayId; use patch_db::Dump; use patch_db::json_ptr::{JsonPointer, ROOT}; use rpc_toolkit::yajrc::RpcError; @@ -16,21 +19,48 @@ use ts_rs::TS; use crate::auth::Sessions; use crate::context::CliContext; +use crate::db::model::public::NetworkInterfaceInfo; use crate::prelude::*; +use crate::rpc_continuations::{Guid, RpcContinuation}; use crate::sign::AnyVerifyingKey; +use crate::tunnel::auth::SignerInfo; use crate::tunnel::context::TunnelContext; +use crate::tunnel::web::WebserverInfo; use crate::tunnel::wg::WgServer; +use crate::util::net::WebSocketExt; use crate::util::serde::{HandlerExtSerde, apply_expr}; -#[derive(Default, Deserialize, Serialize, HasModel)] +#[derive(Default, Deserialize, Serialize, HasModel, TS)] #[serde(rename_all = "camelCase")] #[model = "Model"] pub struct TunnelDatabase { + pub webserver: WebserverInfo, pub sessions: Sessions, - pub password: String, - pub auth_pubkeys: HashSet, + pub password: Option, + #[ts(as = "std::collections::HashMap::")] + pub auth_pubkeys: HashMap, + #[ts(as = "std::collections::BTreeMap::")] + pub gateways: OrdMap, pub wg: WgServer, - pub port_forwards: BTreeMap, + pub port_forwards: PortForwards, +} + +#[test] +fn export_bindings_tunnel_db() { + TunnelDatabase::export_all_to("bindings/tunnel").unwrap(); +} + +#[derive(Clone, Debug, Default, Deserialize, Serialize, TS)] +pub struct PortForwards(pub BTreeMap); +impl Map for PortForwards { + type Key = SocketAddrV4; + type Value = SocketAddrV4; + fn key_str(key: &Self::Key) -> Result, Error> { + Self::key_string(key) + } + fn key_string(key: &Self::Key) -> Result { + Ok(InternedString::from_display(key)) + } } pub fn db_api() -> ParentHandler { @@ -47,6 +77,12 @@ pub fn db_api() -> ParentHandler { .with_metadata("admin", Value::Bool(true)) .no_cli(), ) + .subcommand( + "subscribe", + from_fn_async(subscribe) + .with_metadata("get_session", Value::Bool(true)) + .no_cli(), + ) .subcommand( "apply", from_fn_async(cli_apply) @@ -195,3 +231,75 @@ pub async fn apply(ctx: TunnelContext, ApplyParams { expr, .. }: ApplyParams) -> .await .result } + +#[derive(Deserialize, Serialize, TS)] +#[serde(rename_all = "camelCase")] +pub struct SubscribeParams { + #[ts(type = "string | null")] + pointer: Option, + #[ts(skip)] + #[serde(rename = "__Auth_session")] + session: Option, +} + +#[derive(Deserialize, Serialize, TS)] +#[serde(rename_all = "camelCase")] +pub struct SubscribeRes { + #[ts(type = "{ id: number; value: unknown }")] + pub dump: Dump, + pub guid: Guid, +} + +pub async fn subscribe( + ctx: TunnelContext, + SubscribeParams { pointer, session }: SubscribeParams, +) -> Result { + let (dump, mut sub) = ctx + .db + .dump_and_sub(pointer.unwrap_or_else(|| ROOT.to_owned())) + .await; + let guid = Guid::new(); + ctx.rpc_continuations + .add( + guid.clone(), + RpcContinuation::ws_authed( + &ctx, + session, + |mut ws| async move { + if let Err(e) = async { + loop { + tokio::select! { + rev = sub.recv() => { + if let Some(rev) = rev { + ws.send(ws::Message::Text( + serde_json::to_string(&rev) + .with_kind(ErrorKind::Serialization)? + .into(), + )) + .await + .with_kind(ErrorKind::Network)?; + } else { + return ws.normal_close("complete").await; + } + } + msg = ws.recv() => { + if msg.transpose().with_kind(ErrorKind::Network)?.is_none() { + return Ok(()) + } + } + } + } + } + .await + { + tracing::error!("Error in db websocket: {e}"); + tracing::debug!("{e:?}"); + } + }, + Duration::from_secs(30), + ), + ) + .await; + + Ok(SubscribeRes { dump, guid }) +} diff --git a/core/startos/src/tunnel/forward.rs b/core/startos/src/tunnel/forward.rs deleted file mode 100644 index 3616db216..000000000 --- a/core/startos/src/tunnel/forward.rs +++ /dev/null @@ -1 +0,0 @@ -use crate::prelude::*; diff --git a/core/startos/src/tunnel/mod.rs b/core/startos/src/tunnel/mod.rs index 152526c01..778a3272a 100644 --- a/core/startos/src/tunnel/mod.rs +++ b/core/startos/src/tunnel/mod.rs @@ -1,82 +1,23 @@ -use axum::Router; -use futures::future::ready; -use rpc_toolkit::{Context, HandlerExt, ParentHandler, Server, from_fn_async}; +use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4}; -use crate::context::CliContext; -use crate::middleware::auth::Auth; -use crate::middleware::cors::Cors; -use crate::net::static_server::{bad_request, not_found, server_error}; -use crate::net::web_server::{Accept, WebServer}; -use crate::prelude::*; -use crate::rpc_continuations::Guid; +use axum::Router; + +use crate::net::static_server::ui_router; use crate::tunnel::context::TunnelContext; pub mod api; +pub mod auth; pub mod context; pub mod db; -pub mod forward; +pub mod web; pub mod wg; pub const TUNNEL_DEFAULT_PORT: u16 = 5960; +pub const TUNNEL_DEFAULT_LISTEN: SocketAddr = SocketAddr::V4(SocketAddrV4::new( + Ipv4Addr::new(127, 0, 59, 60), + TUNNEL_DEFAULT_PORT, +)); pub fn tunnel_router(ctx: TunnelContext) -> Router { - use axum::extract as x; - use axum::routing::{any, get}; - Router::new() - .route("/rpc/{*path}", { - let ctx = ctx.clone(); - any( - Server::new(move || ready(Ok(ctx.clone())), api::tunnel_api()) - .middleware(Cors::new()) - .middleware(Auth::new()) - ) - }) - .route( - "/ws/rpc/{*path}", - get({ - let ctx = ctx.clone(); - move |x::Path(path): x::Path, - ws: axum::extract::ws::WebSocketUpgrade| async move { - match Guid::from(&path) { - None => { - tracing::debug!("No Guid Path"); - bad_request() - } - Some(guid) => match ctx.rpc_continuations.get_ws_handler(&guid).await { - Some(cont) => ws.on_upgrade(cont), - _ => not_found(), - }, - } - } - }), - ) - .route( - "/rest/rpc/{*path}", - any({ - let ctx = ctx.clone(); - move |request: x::Request| async move { - let path = request - .uri() - .path() - .strip_prefix("/rest/rpc/") - .unwrap_or_default(); - match Guid::from(&path) { - None => { - tracing::debug!("No Guid Path"); - bad_request() - } - Some(guid) => match ctx.rpc_continuations.get_rest_handler(&guid).await { - None => not_found(), - Some(cont) => cont(request).await.unwrap_or_else(server_error), - }, - } - } - }), - ) -} - -impl WebServer { - pub fn serve_tunnel(&mut self, ctx: TunnelContext) { - self.serve_router(tunnel_router(ctx)) - } + ui_router(ctx) } diff --git a/core/startos/src/tunnel/web.rs b/core/startos/src/tunnel/web.rs new file mode 100644 index 000000000..6d77f4309 --- /dev/null +++ b/core/startos/src/tunnel/web.rs @@ -0,0 +1,688 @@ +use std::collections::VecDeque; +use std::net::{IpAddr, Ipv6Addr, SocketAddr}; +use std::sync::Arc; + +use clap::Parser; +use hickory_client::proto::rr::rdata::cert; +use imbl_value::{InternedString, json}; +use itertools::Itertools; +use openssl::pkey::{PKey, Private}; +use openssl::x509::X509; +use rpc_toolkit::{ + Context, Empty, HandlerArgs, HandlerExt, ParentHandler, from_fn_async, from_fn_async_local, +}; +use serde::{Deserialize, Serialize}; +use tokio::io::{AsyncBufReadExt, BufReader}; +use tokio_rustls::rustls::ServerConfig; +use tokio_rustls::rustls::crypto::CryptoProvider; +use tokio_rustls::rustls::pki_types::{CertificateDer, PrivateKeyDer, PrivatePkcs8KeyDer}; +use tokio_rustls::rustls::server::ClientHello; +use ts_rs::TS; + +use crate::context::CliContext; +use crate::net::ssl::SANInfo; +use crate::net::tls::TlsHandler; +use crate::net::web_server::Accept; +use crate::prelude::*; +use crate::tunnel::auth::SetPasswordParams; +use crate::tunnel::context::TunnelContext; +use crate::tunnel::db::TunnelDatabase; +use crate::util::serde::{HandlerExtSerde, Pem, display_serializable}; +use crate::util::tui::{choose, choose_custom_display, parse_as, prompt, prompt_multiline}; + +#[derive(Debug, Default, Deserialize, Serialize, HasModel, TS)] +#[serde(rename_all = "camelCase")] +#[model = "Model"] +pub struct WebserverInfo { + pub enabled: bool, + pub listen: Option, + pub certificate: Option, +} + +#[derive(Debug, Deserialize, Serialize, TS)] +#[serde(rename_all = "camelCase")] +pub struct TunnelCertData { + pub key: Pem>, + pub cert: Pem>, +} + +#[derive(Clone)] +pub struct TunnelCertHandler { + pub db: TypedPatchDb, + pub crypto_provider: Arc, +} +impl<'a, A> TlsHandler<'a, A> for TunnelCertHandler +where + A: Accept + 'a, + ::Metadata: Send + Sync, +{ + async fn get_config( + &'a mut self, + _: &'a ClientHello<'a>, + _: &'a ::Metadata, + ) -> Option { + let cert_info = self + .db + .peek() + .await + .as_webserver() + .as_certificate() + .de() + .log_err()??; + let cert_chain: Vec<_> = cert_info + .cert + .0 + .iter() + .map(|c| Ok::<_, Error>(CertificateDer::from(c.to_der()?))) + .collect::>() + .log_err()?; + let cert_key = cert_info.key.0.private_key_to_pkcs8().log_err()?; + + Some( + ServerConfig::builder_with_provider(self.crypto_provider.clone()) + .with_safe_default_protocol_versions() + .log_err()? + .with_no_client_auth() + .with_single_cert( + cert_chain, + PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from(cert_key)), + ) + .log_err()?, + ) + } +} + +pub fn web_api() -> ParentHandler { + ParentHandler::new() + .subcommand( + "init", + from_fn_async_local(init_web) + .no_display() + .with_about("Initialize the webserver"), + ) + .subcommand( + "set-listen", + from_fn_async(set_listen) + .no_display() + .with_about("Set the listen address for the webserver") + .with_call_remote::(), + ) + .subcommand( + "get-listen", + from_fn_async(get_listen) + .with_display_serializable() + .with_about("Get the listen address for the webserver") + .with_call_remote::(), + ) + .subcommand( + "get-available-ips", + from_fn_async(get_available_ips) + .with_display_serializable() + .with_about("Get available IP addresses to bind to") + .with_call_remote::(), + ) + .subcommand( + "import-certificate", + from_fn_async(import_certificate_rpc).no_cli(), + ) + .subcommand( + "import-certificate", + from_fn_async_local(import_certificate_cli) + .no_display() + .with_about("Import a certificate to use for the webserver"), + ) + .subcommand( + "generate-certificate", + from_fn_async(generate_certificate) + .with_about("Generate a self signed certificaet to use for the webserver") + .with_call_remote::(), + ) + .subcommand( + "get-certificate", + from_fn_async(get_certificate) + .with_display_serializable() + .with_custom_display_fn(|HandlerArgs { params, .. }, res| { + if let Some(format) = params.format { + return display_serializable(format, res); + } + if let Some(res) = res { + println!("{res}"); + } + Ok(()) + }) + .with_about("Get the certificate for the webserver") + .with_call_remote::(), + ) + .subcommand( + "enable", + from_fn_async(enable_web) + .with_about("Enable the webserver") + .no_display() + .with_call_remote::(), + ) + .subcommand( + "disable", + from_fn_async(disable_web) + .no_display() + .with_about("Disable the webserver") + .with_call_remote::(), + ) + .subcommand( + "reset", + from_fn_async(reset_web) + .no_display() + .with_about("Reset the webserver") + .with_call_remote::(), + ) +} + +pub async fn import_certificate_rpc( + ctx: TunnelContext, + cert_data: TunnelCertData, +) -> Result<(), Error> { + ctx.db + .mutate(|db| { + db.as_webserver_mut() + .as_certificate_mut() + .ser(&Some(cert_data)) + }) + .await + .result?; + Ok(()) +} + +pub async fn import_certificate_cli( + HandlerArgs { + context, + parent_method, + method, + .. + }: HandlerArgs, +) -> Result<(), Error> { + let mut key_string = String::new(); + let key: Pem> = + prompt_multiline("Please paste in your PEM encoded private key: ", |line| { + key_string.push_str(&line); + key_string.push_str("\n"); + if line.trim().starts_with("-----END") { + return key_string.parse().map(Some).map_err(|e| { + key_string.truncate(0); + e + }); + } + Ok(None) + }) + .await?; + + let mut chain = Vec::::new(); + let mut cert_string = String::new(); + prompt_multiline( + concat!( + "Please paste in your PEM encoded certificate", + " (or certificate chain):" + ), + |line| { + cert_string.push_str(&line); + cert_string.push_str("\n"); + if line.trim().starts_with("-----END") { + let cert = cert_string.parse::>(); + cert_string.truncate(0); + let cert = cert?; + + let pubkey = cert.0.public_key()?; + + if chain.is_empty() { + if !key.public_eq(&pubkey) { + return Err(Error::new( + eyre!("Certificate does not match key!"), + ErrorKind::InvalidSignature, + )); + } + } + + if let Some(prev) = chain.last() { + if !prev.verify(&pubkey)? { + return Err(Error::new( + eyre!(concat!( + "Invalid Fullchain: ", + "Previous cert was not signed by this certificate's key" + )), + ErrorKind::InvalidSignature, + )); + } + } + + let is_root = cert.0.verify(&pubkey)?; + + chain.push(cert.0); + + if is_root { Ok(Some(())) } else { Ok(None) } + } else { + Ok(None) + } + }, + ) + .await?; + + context + .call_remote::( + &parent_method.iter().chain(method.iter()).join("."), + to_value(&TunnelCertData { + key, + cert: Pem(chain), + })?, + ) + .await?; + + Ok(()) +} + +#[derive(Debug, Deserialize, Serialize, Parser)] +pub struct GenerateCertParams { + #[arg(help = "Subject Alternative Name(s)")] + pub subject: Vec, +} + +pub async fn generate_certificate( + ctx: TunnelContext, + GenerateCertParams { subject }: GenerateCertParams, +) -> Result, Error> { + let saninfo = SANInfo::new(&subject.into_iter().collect()); + + let key = crate::net::ssl::generate_key()?; + let cert = crate::net::ssl::make_self_signed((&key, &saninfo))?; + + ctx.db + .mutate(|db| { + db.as_webserver_mut() + .as_certificate_mut() + .ser(&Some(TunnelCertData { + key: Pem(key), + cert: Pem(vec![cert.clone()]), + })) + }) + .await + .result?; + + Ok(Pem(cert)) +} + +pub async fn get_certificate(ctx: TunnelContext) -> Result>>, Error> { + ctx.db + .peek() + .await + .as_webserver() + .as_certificate() + .de()? + .map(|cert_data| Ok(cert_data.cert)) + .transpose() +} + +#[derive(Debug, Deserialize, Serialize, Parser)] +#[serde(rename_all = "camelCase")] +pub struct SetListenParams { + pub listen: SocketAddr, +} + +pub async fn set_listen( + ctx: TunnelContext, + SetListenParams { listen }: SetListenParams, +) -> Result<(), Error> { + // Validate that the address is available to bind + tokio::net::TcpListener::bind(listen) + .await + .with_kind(ErrorKind::Network) + .with_ctx(|_| { + ( + ErrorKind::Network, + format!("{} is not available to bind to", listen), + ) + })?; + + ctx.db + .mutate(|db| { + db.as_webserver_mut().as_listen_mut().ser(&Some(listen))?; + + Ok(()) + }) + .await + .result +} + +pub async fn get_listen(ctx: TunnelContext) -> Result, Error> { + ctx.db.peek().await.as_webserver().as_listen().de() +} + +pub async fn get_available_ips(ctx: TunnelContext) -> Result, Error> { + let ips = ctx.net_iface.peek(|interfaces| { + interfaces + .values() + .flat_map(|info| { + info.ip_info + .iter() + .flat_map(|ip_info| ip_info.subnets.iter().map(|subnet| subnet.addr())) + }) + .collect::>() + }); + + Ok(ips) +} + +pub async fn enable_web(ctx: TunnelContext) -> Result<(), Error> { + ctx.db + .mutate(|db| { + if db.as_webserver().as_listen().transpose_ref().is_none() { + return Err(Error::new( + eyre!("Listen is not set"), + ErrorKind::ParseNetAddress, + )); + } + if db.as_webserver().as_certificate().transpose_ref().is_none() { + return Err(Error::new( + eyre!("Certificate is not set"), + ErrorKind::OpenSsl, + )); + } + if db.as_password().transpose_ref().is_none() { + return Err(Error::new( + eyre!("Password is not set"), + ErrorKind::Authorization, + )); + }; + db.as_webserver_mut().as_enabled_mut().ser(&true) + }) + .await + .result +} + +pub async fn disable_web(ctx: TunnelContext) -> Result<(), Error> { + ctx.db + .mutate(|db| db.as_webserver_mut().as_enabled_mut().ser(&false)) + .await + .result +} + +pub async fn reset_web(ctx: TunnelContext) -> Result<(), Error> { + ctx.db + .mutate(|db| { + db.as_webserver_mut().as_enabled_mut().ser(&false)?; + db.as_webserver_mut().as_listen_mut().ser(&None)?; + db.as_webserver_mut().as_certificate_mut().ser(&None)?; + db.as_password_mut().ser(&None)?; + Ok(()) + }) + .await + .result +} + +fn is_valid_domain(domain: &str) -> bool { + if domain.is_empty() || domain.len() > 253 || domain.starts_with('.') || domain.ends_with('.') { + return false; + } + + let labels: Vec<&str> = domain.split('.').collect(); + + for label in labels { + if label.is_empty() || label.len() > 63 { + return false; + } + + if !label.chars().all(|c| c.is_ascii_alphanumeric() || c == '-') { + return false; + } + + if label.chars().next().map_or(true, |c| c == '-') + || label.chars().next_back().map_or(true, |c| c == '-') + { + return false; + } + } + + true +} + +pub async fn init_web(ctx: CliContext) -> Result<(), Error> { + let mut password = None; + loop { + match ctx + .call_remote::("web.enable", json!({})) + .await + { + Ok(_) => { + let listen = from_value::( + ctx.call_remote::("web.get-listen", json!({})) + .await?, + )?; + + println!("✅ Success! ✅"); + println!( + "The webserver is running. Below is your URL{} and SSL certificate.", + if password.is_some() { + ", password," + } else { + "" + } + ); + println!(); + println!("🌐 URL"); + println!("https://{listen}"); + if listen.ip().is_unspecified() { + println!(concat!( + "Note: this is the unspecified address. ", + "This means you can use any IP address available to this device to connect. ", + "Using the above address as-is will only work from this device." + )); + } else if listen.ip().is_loopback() { + println!(concat!( + "Note: this is a loopback address. ", + "This is only recommended if you are planning to run a proxy in front of the web ui. ", + "Using the above address as-is will only work from this device." + )); + } + println!(); + + if let Some(password) = password { + println!("🔒 Password"); + println!("{password}"); + println!(); + println!(concat!( + "If you lose or forget your password, you can reset it using the command: ", + "start-tunnel auth reset-password" + )); + } else { + println!(concat!( + "Your password was set up previously. ", + "If you don't remember it, you can reset it using the command: ", + "start-tunnel auth reset-password" + )); + } + println!(); + + let cert = from_value::>>( + ctx.call_remote::("web.get-certificate", json!({})) + .await?, + )?; + println!("📝 SSL Certificate:"); + print!("{cert}"); + + println!(concat!( + "If you haven't already, ", + "trust the certificate in your system keychain and/or browser." + )); + + return Ok(()); + } + Err(e) if e.kind == ErrorKind::ParseNetAddress => { + println!("Select the IP address at which to host the web interface:"); + + let mut suggested_addrs = from_value::>( + ctx.call_remote::("web.get-available-ips", json!({})) + .await?, + )?; + + suggested_addrs.sort_by_cached_key(|a| match a { + IpAddr::V4(a) => { + if a.is_loopback() { + 3 + } else if a.is_private() { + 2 + } else { + 0 + } + } + IpAddr::V6(a) => { + if a.is_loopback() { + 5 + } else if a.is_unicast_link_local() { + 4 + } else { + 1 + } + } + }); + + let ip = if suggested_addrs.is_empty() { + prompt("Listen Address: ", parse_as::("IP Address"), None).await? + } else if suggested_addrs.len() > 16 { + prompt( + &format!("Listen Address [{}]: ", suggested_addrs[0]), + parse_as::("IP Address"), + Some(suggested_addrs[0]), + ) + .await? + } else { + *choose_custom_display("Listen Address:", &suggested_addrs, |a| match a { + a if a.is_loopback() => { + format!("{a} (Loopback Address: only use if planning to proxy traffic)") + } + IpAddr::V4(a) if a.is_private() => { + format!("{a} (Private Address: only available from Local Area Network)") + } + IpAddr::V6(a) if a.is_unicast_link_local() => { + format!( + "[{a}] (Private Address: only available from Local Area Network)" + ) + } + IpAddr::V6(a) => format!("[{a}]"), + a => a.to_string(), + }) + .await? + }; + + println!(concat!( + "Enter the port at which to host the web interface. ", + "The recommended default is 8443. ", + "If you change the default, choose an uncommon port to avoid conflicts: " + )); + let port = prompt("Port [8443]: ", parse_as::("port"), Some(8443)).await?; + + let listen = SocketAddr::new(ip, port); + + ctx.call_remote::( + "web.set-listen", + to_value(&SetListenParams { listen })?, + ) + .await?; + + println!(); + } + Err(e) if e.kind == ErrorKind::OpenSsl => { + enum Choice { + Generate, + Provide, + } + impl std::fmt::Display for Choice { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Generate => write!(f, "Generate a Self Signed Certificate"), + Self::Provide => write!(f, "Provide your own certificate and key"), + } + } + } + let options = vec![Choice::Generate, Choice::Provide]; + let choice = choose( + concat!( + "Select whether to autogenerate a self-signed SSL certificate ", + "or provide your own certificate and key:" + ), + &options, + ) + .await?; + + match choice { + Choice::Generate => { + let listen = from_value::>( + ctx.call_remote::("web.get-listen", json!({})) + .await?, + )? + .filter(|a| !a.ip().is_unspecified()); + + let default_prompt = if let Some(listen) = listen { + format!("Subject Alternative Name(s) [{}]: ", listen.ip()) + } else { + "Subject Alternative Name(s): ".to_string() + }; + + println!( + "List all IP addresses and domains for which to sign the certificate, separated by commas." + ); + let san_info = prompt( + &default_prompt, + |s| { + s.split(",") + .map(|s| { + let s = s.trim(); + if let Ok(ip) = s.parse::() { + Ok(InternedString::from_display(&ip)) + } else if is_valid_domain(s) { + Ok(s.into()) + } else { + Err(format!("{s} is not a valid ip address or domain")) + } + }) + .collect() + }, + listen.map(|l| vec![InternedString::from_display(&l.ip())]), + ) + .await?; + + ctx.call_remote::( + "web.generate-certificate", + to_value(&GenerateCertParams { subject: san_info })?, + ) + .await?; + } + Choice::Provide => { + import_certificate_cli(HandlerArgs { + context: ctx.clone(), + parent_method: vec!["web", "import-certificate"].into(), + method: VecDeque::new(), + params: Empty {}, + inherited_params: Empty {}, + raw_params: json!({}), + }) + .await?; + } + } + + println!(); + } + Err(e) if e.kind == ErrorKind::Authorization => { + println!("Generating a random password..."); + let params = SetPasswordParams { + password: base32::encode( + base32::Alphabet::Rfc4648Lower { padding: false }, + &rand::random::<[u8; 16]>(), + ), + }; + ctx.call_remote::("auth.set-password", to_value(¶ms)?) + .await?; + + password = Some(params.password); + + println!(); + } + Err(e) => return Err(e.into()), + } + } +} diff --git a/core/startos/src/tunnel/wg.rs b/core/startos/src/tunnel/wg.rs index 4f5277119..539a7438e 100644 --- a/core/startos/src/tunnel/wg.rs +++ b/core/startos/src/tunnel/wg.rs @@ -1,19 +1,22 @@ use std::collections::BTreeMap; -use std::net::{Ipv4Addr, SocketAddrV4}; +use std::net::{Ipv4Addr, SocketAddr}; -use ed25519_dalek::{SigningKey, VerifyingKey}; use imbl_value::InternedString; use ipnet::Ipv4Net; use itertools::Itertools; use serde::{Deserialize, Serialize}; use tokio::process::Command; +use ts_rs::TS; +use x25519_dalek::{PublicKey, StaticSecret}; use crate::prelude::*; use crate::util::Invoke; use crate::util::io::write_file_atomic; use crate::util::serde::Base64; -#[derive(Deserialize, Serialize, HasModel)] +pub const WIREGUARD_INTERFACE_NAME: &str = "wg-start-tunnel"; + +#[derive(Deserialize, Serialize, HasModel, TS)] #[serde(rename_all = "camelCase")] #[model = "Model"] pub struct WgServer { @@ -37,7 +40,7 @@ impl WgServer { pub async fn sync(&self) -> Result<(), Error> { Command::new("wg-quick") .arg("down") - .arg("wg0") + .arg(WIREGUARD_INTERFACE_NAME) .invoke(ErrorKind::Network) .await .or_else(|e| { @@ -49,21 +52,23 @@ impl WgServer { } })?; write_file_atomic( - "/etc/wireguard/wg0.conf", + const_format::formatcp!("/etc/wireguard/{WIREGUARD_INTERFACE_NAME}.conf"), self.server_config().to_string().as_bytes(), ) .await?; Command::new("wg-quick") .arg("up") - .arg("wg0") + .arg(WIREGUARD_INTERFACE_NAME) .invoke(ErrorKind::Network) .await?; Ok(()) } } -#[derive(Default, Deserialize, Serialize)] -pub struct WgSubnetMap(pub BTreeMap); +#[derive(Default, Deserialize, Serialize, TS)] +pub struct WgSubnetMap( + #[ts(as = "BTreeMap::")] pub BTreeMap, +); impl Map for WgSubnetMap { type Key = Ipv4Net; type Value = WgSubnetConfig; @@ -75,35 +80,41 @@ impl Map for WgSubnetMap { } } -#[derive(Default, Deserialize, Serialize, HasModel)] +#[derive(Default, Deserialize, Serialize, HasModel, TS)] #[serde(rename_all = "camelCase")] #[model = "Model"] pub struct WgSubnetConfig { - pub default_forward_target: Option, - pub clients: BTreeMap, + pub name: InternedString, + pub clients: WgSubnetClients, } impl WgSubnetConfig { - pub fn new() -> Self { - Self::default() - } - pub fn add_client<'a>( - &'a mut self, - subnet: Ipv4Net, - ) -> Result<(Ipv4Addr, &'a WgConfig), Error> { - let addr = subnet - .hosts() - .find(|a| !self.clients.contains_key(a)) - .ok_or_else(|| Error::new(eyre!("subnet exhausted"), ErrorKind::Network))?; - let config = self.clients.entry(addr).or_insert(WgConfig::generate()); - Ok((addr, config)) + pub fn new(name: InternedString) -> Self { + Self { + name, + ..Self::default() + } } } -pub struct WgKey(SigningKey); +#[derive(Default, Deserialize, Serialize, TS)] +pub struct WgSubnetClients(pub BTreeMap); +impl Map for WgSubnetClients { + type Key = Ipv4Addr; + type Value = WgConfig; + fn key_str(key: &Self::Key) -> Result, Error> { + Self::key_string(key) + } + fn key_string(key: &Self::Key) -> Result { + Ok(InternedString::from_display(key)) + } +} + +#[derive(Clone)] +pub struct WgKey(StaticSecret); impl WgKey { pub fn generate() -> Self { - Self(SigningKey::generate( - &mut ssh_key::rand_core::OsRng::default(), + Self(StaticSecret::random_from_rng( + ssh_key::rand_core::OsRng::default(), )) } } @@ -113,33 +124,39 @@ impl AsRef<[u8]> for WgKey { } } impl TryFrom> for WgKey { - type Error = ed25519_dalek::SignatureError; + type Error = Error; fn try_from(value: Vec) -> Result { - Ok(Self(value.as_slice().try_into()?)) + Ok(Self( + <[u8; 32]>::try_from(value) + .map_err(|_| Error::new(eyre!("invalid key length"), ErrorKind::Deserialization))? + .into(), + )) } } impl std::ops::Deref for WgKey { - type Target = SigningKey; + type Target = StaticSecret; fn deref(&self) -> &Self::Target { &self.0 } } impl Base64 { - pub fn verifying_key(&self) -> Base64 { - Base64(self.0.verifying_key()) + pub fn verifying_key(&self) -> Base64 { + Base64((&*self.0).into()) } } -#[derive(Deserialize, Serialize, HasModel)] +#[derive(Clone, Deserialize, Serialize, HasModel, TS)] #[serde(rename_all = "camelCase")] #[model = "Model"] pub struct WgConfig { + pub name: InternedString, pub key: Base64, pub psk: Base64<[u8; 32]>, } impl WgConfig { - pub fn generate() -> Self { + pub fn generate(name: InternedString) -> Self { Self { + name, key: Base64(WgKey::generate()), psk: Base64(rand::random()), } @@ -150,12 +167,12 @@ impl WgConfig { client_addr: addr, } } - pub fn client_config<'a>( - &'a self, + pub fn client_config( + self, addr: Ipv4Addr, - server_pubkey: Base64, - server_addr: SocketAddrV4, - ) -> ClientConfig<'a> { + server_pubkey: Base64, + server_addr: SocketAddr, + ) -> ClientConfig { ClientConfig { client_config: self, client_addr: addr, @@ -181,19 +198,33 @@ impl<'a> std::fmt::Display for ServerPeerConfig<'a> { } } -pub struct ClientConfig<'a> { - client_config: &'a WgConfig, - client_addr: Ipv4Addr, - server_pubkey: Base64, - server_addr: SocketAddrV4, +fn deserialize_verifying_key<'de, D>(deserializer: D) -> Result, D::Error> +where + D: serde::Deserializer<'de>, +{ + Base64::>::deserialize(deserializer).and_then(|b| { + Ok(Base64(PublicKey::from(<[u8; 32]>::try_from(b.0).map_err( + |e: Vec| serde::de::Error::invalid_length(e.len(), &"a 32 byte base64 string"), + )?))) + }) } -impl<'a> std::fmt::Display for ClientConfig<'a> { + +#[derive(Clone, Serialize, Deserialize)] +pub struct ClientConfig { + client_config: WgConfig, + client_addr: Ipv4Addr, + #[serde(deserialize_with = "deserialize_verifying_key")] + server_pubkey: Base64, + server_addr: SocketAddr, +} +impl std::fmt::Display for ClientConfig { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, include_str!("./client.conf.template"), + name = self.client_config.name, privkey = self.client_config.key.to_padded_string(), - psk = self.client_config.psk, + psk = self.client_config.psk.to_padded_string(), addr = self.client_addr, server_pubkey = self.server_pubkey.to_padded_string(), server_addr = self.server_addr, @@ -212,7 +243,7 @@ impl<'a> std::fmt::Display for ServerConfig<'a> { server_port = server.port, server_privkey = server.key.to_padded_string(), )?; - for (addr, peer) in server.subnets.0.values().flat_map(|s| &s.clients) { + for (addr, peer) in server.subnets.0.values().flat_map(|s| &s.clients.0) { write!(f, "{}", peer.server_peer_config(*addr))?; } Ok(()) diff --git a/core/startos/src/util/collections/mod.rs b/core/startos/src/util/collections/mod.rs index 2070343bd..0873b9da6 100644 --- a/core/startos/src/util/collections/mod.rs +++ b/core/startos/src/util/collections/mod.rs @@ -8,6 +8,30 @@ pub use eq_map::EqMap; pub use eq_set::EqSet; use imbl::OrdMap; +pub fn ordmap_retain bool>( + map: &mut OrdMap, + mut f: F, +) { + let mut prev = None; + loop { + let next = if let Some(k) = prev.take() { + map.range((Bound::Excluded(k), Bound::Unbounded)).next() + } else { + map.get_min().map(|(k, v)| (k, v)) + }; + let Some((k, _)) = next else { + break; + }; + let k = k.clone(); // hate that I have to do this but whatev + let v = map.get_mut(&k).unwrap(); + + if !f(&k, v) { + map.remove(&k); + } + prev = Some(k); + } +} + pub struct OrdMapIterMut<'a, K: 'a, V: 'a> { map: *mut OrdMap, prev: Option<&'a K>, diff --git a/core/startos/src/util/future.rs b/core/startos/src/util/future.rs index c690f9754..d9a8369e2 100644 --- a/core/startos/src/util/future.rs +++ b/core/startos/src/util/future.rs @@ -1,10 +1,13 @@ use std::pin::Pin; use std::task::{Context, Poll}; -use futures::future::{abortable, pending, BoxFuture, FusedFuture}; +use axum::middleware::FromFn; +use futures::future::{BoxFuture, FusedFuture, abortable, pending}; use futures::stream::{AbortHandle, Abortable, BoxStream}; use futures::{Future, FutureExt, Stream, StreamExt}; +use rpc_toolkit::from_fn_blocking; use tokio::sync::watch; +use tokio::task::LocalSet; use crate::prelude::*; @@ -158,6 +161,31 @@ impl<'a> Until<'a> { } } +pub async fn make_send(f: F) -> Result +where + F: FnOnce() -> Fut + Send + 'static, + Fut: Future> + 'static, + T: Send + 'static, +{ + tokio::task::spawn_blocking(move || { + let rt = tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap(); + + let local = LocalSet::new(); + + local.block_on(&rt, async move { f().await }) + }) + .await + .map_err(|e| { + Error::new( + eyre!("Task running non-Send future panicked: {}", e), + ErrorKind::Unknown, + ) + })? +} + #[tokio::test] async fn test_cancellable() { use std::sync::Arc; diff --git a/core/startos/src/util/io.rs b/core/startos/src/util/io.rs index c55b6f92e..5378f2003 100644 --- a/core/startos/src/util/io.rs +++ b/core/startos/src/util/io.rs @@ -6,15 +6,15 @@ use std::os::unix::prelude::MetadataExt; use std::path::{Path, PathBuf}; use std::pin::Pin; use std::str::FromStr; -use std::sync::atomic::AtomicU64; use std::sync::Arc; +use std::sync::atomic::AtomicU64; use std::task::{Poll, Waker}; use std::time::Duration; use bytes::{Buf, BytesMut}; use clap::builder::ValueParserFactory; use futures::future::{BoxFuture, Fuse}; -use futures::{AsyncSeek, FutureExt, Stream, StreamExt, TryStreamExt}; +use futures::{FutureExt, Stream, StreamExt, TryStreamExt}; use helpers::{AtomicFile, NonDetachingJoinHandle}; use inotify::{EventMask, EventStream, Inotify, WatchMask}; use models::FromStrParser; @@ -22,7 +22,8 @@ use nix::unistd::{Gid, Uid}; use serde::{Deserialize, Serialize}; use tokio::fs::{File, OpenOptions}; use tokio::io::{ - duplex, AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt, DuplexStream, ReadBuf, WriteHalf, + AsyncRead, AsyncReadExt, AsyncSeek, AsyncWrite, AsyncWriteExt, DuplexStream, ReadBuf, SeekFrom, + WriteHalf, duplex, }; use tokio::net::TcpStream; use tokio::sync::{Notify, OwnedMutexGuard}; diff --git a/core/startos/src/util/logger.rs b/core/startos/src/util/logger.rs index 9dfc8e412..c2dceed54 100644 --- a/core/startos/src/util/logger.rs +++ b/core/startos/src/util/logger.rs @@ -59,7 +59,7 @@ impl StartOSLogger { fn base_subscriber(logfile: LogFile) -> impl Subscriber { use tracing_error::ErrorLayer; use tracing_subscriber::prelude::*; - use tracing_subscriber::{fmt, EnvFilter}; + use tracing_subscriber::{EnvFilter, fmt}; let filter_layer = || { EnvFilter::builder() diff --git a/core/startos/src/util/mod.rs b/core/startos/src/util/mod.rs index 0f5496b28..61e1bcfb4 100644 --- a/core/startos/src/util/mod.rs +++ b/core/startos/src/util/mod.rs @@ -14,10 +14,10 @@ use ::serde::{Deserialize, Serialize}; use async_trait::async_trait; use color_eyre::eyre::{self, eyre}; use fd_lock_rs::FdLock; -use futures::future::BoxFuture; use futures::FutureExt; -use helpers::canonicalize; +use futures::future::BoxFuture; pub use helpers::NonDetachingJoinHandle; +use helpers::canonicalize; use imbl_value::InternedString; use lazy_static::lazy_static; pub use models::VersionString; @@ -25,7 +25,7 @@ use pin_project::pin_project; use sha2::Digest; use tokio::fs::File; use tokio::io::{AsyncRead, AsyncReadExt, BufReader}; -use tokio::sync::{oneshot, Mutex, OwnedMutexGuard, RwLock}; +use tokio::sync::{Mutex, OwnedMutexGuard, RwLock, oneshot}; use tracing::instrument; use ts_rs::TS; use url::Url; @@ -49,7 +49,9 @@ pub mod net; pub mod rpc; pub mod rpc_client; pub mod serde; +//pub mod squashfs; pub mod sync; +pub mod tui; #[derive(Clone, Copy, Debug, ::serde::Deserialize, ::serde::Serialize)] pub enum Never {} diff --git a/core/startos/src/util/serde.rs b/core/startos/src/util/serde.rs index e2d621daf..2b462e5fd 100644 --- a/core/startos/src/util/serde.rs +++ b/core/startos/src/util/serde.rs @@ -1055,7 +1055,11 @@ impl>> ValueParserFactory for Base64 { Self::Parser::new() } } -impl<'de, T: TryFrom>> Deserialize<'de> for Base64 { +impl<'de, T> Deserialize<'de> for Base64 +where + Base64: FromStr, + as FromStr>::Err: std::fmt::Display, +{ fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, @@ -1195,6 +1199,21 @@ impl PemEncoding for X509 { } } +impl PemEncoding for Vec { + fn from_pem(pem: &str) -> Result { + X509::stack_from_pem(pem.as_bytes()).map_err(E::custom) + } + fn to_pem(&self) -> Result { + self.iter() + .map(|x| x.to_pem()) + .try_fold(String::new(), |mut acc, x| { + acc.push_str(&x?); + acc.push_str("\n"); + Ok(acc) + }) + } +} + impl PemEncoding for PKey { fn from_pem(pem: &str) -> Result { Self::private_key_from_pem(pem.as_bytes()).map_err(E::custom) diff --git a/core/startos/src/util/squashfs.rs b/core/startos/src/util/squashfs.rs new file mode 100644 index 000000000..4f63e846a --- /dev/null +++ b/core/startos/src/util/squashfs.rs @@ -0,0 +1,1170 @@ +use std::io::{Seek, SeekFrom, Write}; +use std::task::Poll; + +use async_compression::codecs::{Encode, ZstdEncoder}; +use async_compression::core::util::PartialBuffer; +use futures::{TryStreamExt, ready}; +use tokio::io::{AsyncSeek, AsyncWrite}; +use visit_rs::{Visit, VisitAsync, VisitFields, VisitFieldsAsync, Visitor}; + +use crate::prelude::*; + +struct SquashfsSerializer { + writer: W, +} +impl Visitor for SquashfsSerializer { + type Result = Result<(), Error>; +} + +macro_rules! impl_visit_le { + ($($ty:ty),*) => { + $( + impl VisitAsync> for $ty { + async fn visit_async(&self, visitor: &mut SquashfsSerializer) -> Result<(), Error> { + use tokio::io::AsyncWriteExt; + visitor.writer.write_all(&self.to_le_bytes()).await?; + Ok(()) + } + } + impl Visit> for $ty { + fn visit(&self, visitor: &mut SquashfsSerializer) -> Result<(), Error> { + visitor.writer.write_all(&self.to_le_bytes())?; + Ok(()) + } + } + )* + }; +} + +impl_visit_le!(u8, u16, u32, u64, i8, i16, i32, i64, f32, f64); + +#[derive(VisitFields)] +struct Superblock { + magic: u32, // 0x73717368 + inode_count: u32, + modification_time: u32, // 0 + block_size: u32, + fragment_entry_count: u32, + compression_id: u16, // 6 = zstd + block_log: u16, // log2(block_size) + flags: u16, // 0x0440 + id_count: u16, + version_major: u16, // 4 + version_minor: u16, // 0 + root_inode_ref: u64, + bytes_used: u64, + id_table_start: u64, + xattr_id_table_start: u64, + inode_table_start: u64, + directory_table_start: u64, + fragment_table_start: u64, + export_table_start: u64, +} +impl Default for Superblock { + fn default() -> Self { + Self { + magic: 0x73717368, + inode_count: 0, + modification_time: 0, + block_size: 0, + fragment_entry_count: 0, + compression_id: 6, + block_log: 0, + flags: 0x0440, + id_count: 0, + version_major: 4, + version_minor: 0, + root_inode_ref: 0, + bytes_used: 0, + id_table_start: 0, + xattr_id_table_start: 0, + inode_table_start: 0, + directory_table_start: 0, + fragment_table_start: 0, + export_table_start: 0, + } + } +} +impl VisitAsync> for Superblock { + async fn visit_async(&self, visitor: &mut SquashfsSerializer) -> Result<(), Error> { + self.visit_fields_async(visitor).try_collect().await + } +} +impl Visit> for Superblock { + fn visit(&self, visitor: &mut SquashfsSerializer) -> Result<(), Error> { + self.visit_fields(visitor).collect() + } +} + +#[pin_project::pin_project] +pub struct MetadataBlocksWriter { + input: [u8; 8192], + size: usize, + size_addr: Option, + output: PartialBuffer<[u8; 8192]>, + output_flushed: usize, + zstd: Option, + seek_state: SeekState, + write_state: WriteState, + #[pin] + writer: W, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum SeekState { + Idle, + GettingPosition, + Seeking(u64), +} + +#[derive(Debug, Clone, PartialEq, Eq)] +enum WriteState { + Idle, + WritingSizeHeader(u16), + WritingOutput(Box), + EncodingInput, + FinishingCompression, + WritingFinalSizeHeader(u64, u64), + SeekingToEnd(u64), +} + +fn poll_seek_helper( + writer: std::pin::Pin<&mut W>, + seek_state: &mut SeekState, + cx: &mut std::task::Context<'_>, + pos: u64, +) -> std::task::Poll> { + match *seek_state { + SeekState::Idle => { + writer.start_seek(std::io::SeekFrom::Start(pos))?; + *seek_state = SeekState::Seeking(pos); + Poll::Pending + } + SeekState::Seeking(target) if target == pos => { + let result = ready!(writer.poll_complete(cx))?; + *seek_state = SeekState::Idle; + Poll::Ready(Ok(result)) + } + SeekState::Seeking(old_target) => { + tracing::warn!( + "poll_seek({}) called while seeking to {}, canceling previous seek", + pos, + old_target + ); + writer.start_seek(std::io::SeekFrom::Start(pos))?; + *seek_state = SeekState::Seeking(pos); + Poll::Pending + } + SeekState::GettingPosition => { + tracing::warn!( + "poll_seek({}) called while getting stream position, canceling", + pos + ); + writer.start_seek(std::io::SeekFrom::Start(pos))?; + *seek_state = SeekState::Seeking(pos); + Poll::Pending + } + } +} + +fn poll_stream_position_helper( + writer: std::pin::Pin<&mut W>, + seek_state: &mut SeekState, + cx: &mut std::task::Context<'_>, +) -> std::task::Poll> { + match *seek_state { + SeekState::Idle => { + writer.start_seek(std::io::SeekFrom::Current(0))?; + *seek_state = SeekState::GettingPosition; + Poll::Pending + } + SeekState::GettingPosition => { + let result = ready!(writer.poll_complete(cx))?; + *seek_state = SeekState::Idle; + Poll::Ready(Ok(result)) + } + SeekState::Seeking(target) => { + tracing::warn!( + "poll_stream_position called while seeking to {}, canceling", + target + ); + writer.start_seek(std::io::SeekFrom::Current(0))?; + *seek_state = SeekState::GettingPosition; + Poll::Pending + } + } +} + +impl Write for MetadataBlocksWriter { + fn write(&mut self, buf: &[u8]) -> std::io::Result { + let n = buf.len().min(self.input.len() - self.size); + self.input[self.size..self.size + n].copy_from_slice(&buf[..n]); + self.size += n; + if n < buf.len() { + self.flush()?; + } + Ok(n) + } + fn flush(&mut self) -> std::io::Result<()> { + loop { + match self.write_state { + WriteState::Idle => { + if self.size == 0 { + return Ok(()); + } + self.write_state = WriteState::WritingSizeHeader(0); + } + + WriteState::WritingSizeHeader(size) => { + let done = if let Some(size_addr) = self.size_addr { + self.writer.seek(SeekFrom::Start(size_addr))?; + Some(size_addr + size as u64) + } else { + self.size_addr = Some(self.writer.stream_position()?); + None + }; + self.output.unwritten_mut()[..2].copy_from_slice(&u16::to_le_bytes(size)[..]); + self.output.advance(2); + self.write_state = + WriteState::WritingOutput(Box::new(if let Some(end) = done { + WriteState::SeekingToEnd(end) + } else { + WriteState::EncodingInput + })); + } + + WriteState::WritingOutput(next) => { + if self.output.written().len() > self.output_flushed { + let n = self + .writer + .write(&self.output.written()[self.output_flushed..])?; + self.output_flushed += n; + } else { + self.output.reset(); + self.output_flushed = 0; + self.write_state = *next; + } + } + + WriteState::EncodingInput => { + let encoder = self.zstd.get_or_insert_with(|| ZstdEncoder::new(22)); + let mut input = PartialBuffer::new(&self.input[..self.size]); + while !self.output.unwritten().is_empty() && !input.unwritten().is_empty() { + encoder.encode(&mut input, &mut self.output)?; + } + while !encoder.flush(&mut self.output)? {} + while !encoder.finish(&mut self.output)? {} + if !self.output.unwritten().is_empty() { + let mut input = + PartialBuffer::new(&self.input[self.input_flushed..self.size]); + encoder.encode(&mut input, &mut self.output)?; + self.input_flushed += input.written().len(); + } + self.write_state = WriteState::WritingOutput(Box::new()); + continue; + } + + WriteState::FinishingCompression => { + if !self.output.unwritten().is_empty() { + if self.zstd.as_mut().unwrap().finish(&mut self.output)? { + self.zstd = None; + } + } + if self.output.written().len() > self.output_flushed { + self.write_state = WriteState::WritingOutput; + continue; + } + if self.zstd.is_none() && self.output.written().len() == self.output_flushed { + self.output_flushed = 0; + self.output.reset(); + let end_addr = self.writer.stream_position()?; + let size_addr = self.size_addr.ok_or_else(|| { + std::io::Error::new( + std::io::ErrorKind::InvalidData, + "size_addr not set when finishing compression", + ) + })?; + self.write_state = WriteState::WritingFinalSizeHeader(size_addr, end_addr); + continue; + } + return Ok(()); + } + + WriteState::WritingFinalSizeHeader(size_addr, end_addr) => { + if self.output.written().len() > self.output_flushed { + let n = self + .writer + .write(&self.output.written()[self.output_flushed..])?; + self.output_flushed += n; + continue; + } + self.writer.seek(std::io::SeekFrom::Start(size_addr))?; + self.output.unwritten_mut()[..2] + .copy_from_slice(&((end_addr - size_addr - 2) as u16).to_le_bytes()); + self.output.advance(2); + let n = self.writer.write(&self.output.written())?; + self.output_flushed = n; + if n == 2 { + self.output_flushed = 0; + self.output.reset(); + self.write_state = WriteState::SeekingToEnd(end_addr); + } + continue; + } + + WriteState::SeekingToEnd(end_addr) => { + self.writer.seek(std::io::SeekFrom::Start(end_addr))?; + self.input_flushed = 0; + self.size = 0; + self.size_addr = None; + self.write_state = WriteState::Idle; + return Ok(()); + } + } + } + } +} + +impl AsyncWrite for MetadataBlocksWriter { + fn poll_write( + mut self: std::pin::Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + buf: &[u8], + ) -> std::task::Poll> { + let this = self.as_mut().project(); + let n = buf.len().min(this.input.len() - *this.size); + this.input[*this.size..*this.size + n].copy_from_slice(&buf[..n]); + *this.size += n; + if n < buf.len() { + ready!(self.poll_flush(cx)?); + } + Poll::Ready(Ok(n)) + } + + fn poll_flush( + mut self: std::pin::Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> std::task::Poll> { + loop { + let mut this = self.as_mut().project(); + match *this.write_state { + WriteState::Idle => { + if *this.size == 0 { + return Poll::Ready(Ok(())); + } + if this.size_addr.is_none() { + let pos = ready!(poll_stream_position_helper( + this.writer.as_mut(), + this.seek_state, + cx + ))?; + *this.size_addr = Some(pos); + this.output.unwritten_mut()[..2].copy_from_slice(&[0; 2]); + this.output.advance(2); + } + *this.write_state = WriteState::WritingOutput; + continue; + } + + WriteState::WritingOutput => { + if this.output.written().len() > *this.output_flushed { + let n = ready!( + this.writer + .as_mut() + .poll_write(cx, &this.output.written()[*this.output_flushed..]) + )?; + *this.output_flushed += n; + continue; + } + if this.output.written().len() == *this.output_flushed { + *this.output_flushed = 0; + this.output.reset(); + } + if *this.input_flushed < *this.size { + if !this.output.unwritten().is_empty() { + let mut input = + PartialBuffer::new(&this.input[*this.input_flushed..*this.size]); + this.zstd + .get_or_insert_with(|| ZstdEncoder::new(22)) + .encode(&mut input, this.output)?; + *this.input_flushed += input.written().len(); + } + continue; + } else { + if !this.output.unwritten().is_empty() { + if this.zstd.as_mut().unwrap().finish(this.output)? { + *this.zstd = None; + } + continue; + } + if this.zstd.is_none() + && this.output.written().len() == *this.output_flushed + { + *this.output_flushed = 0; + this.output.reset(); + if let Some(size_addr) = *this.size_addr { + let end_addr = ready!(poll_stream_position_helper( + this.writer.as_mut(), + this.seek_state, + cx + ))?; + *this.write_state = + WriteState::WritingFinalSizeHeader(size_addr, end_addr); + ready!(poll_seek_helper( + this.writer.as_mut(), + this.seek_state, + cx, + size_addr + ))?; + this.output.unwritten_mut()[..2].copy_from_slice( + &((end_addr - size_addr - 2) as u16).to_le_bytes(), + ); + this.output.advance(2); + continue; + } + } + } + return Poll::Ready(Ok(())); + } + + WriteState::WritingSizeHeader(_size_addr) => { + *this.write_state = WriteState::WritingOutput; + continue; + } + + WriteState::EncodingInput => { + *this.write_state = WriteState::WritingOutput; + continue; + } + + WriteState::FinishingCompression => { + *this.write_state = WriteState::WritingOutput; + continue; + } + + WriteState::WritingFinalSizeHeader(_size_addr, end_addr) => { + if this.output.written().len() > *this.output_flushed { + let n = ready!( + this.writer + .as_mut() + .poll_write(cx, &this.output.written()[*this.output_flushed..]) + )?; + *this.output_flushed += n; + continue; + } + *this.output_flushed = 0; + this.output.reset(); + *this.write_state = WriteState::SeekingToEnd(end_addr); + continue; + } + + WriteState::SeekingToEnd(end_addr) => { + ready!(poll_seek_helper( + this.writer.as_mut(), + this.seek_state, + cx, + end_addr + ))?; + *this.size_addr = None; + *this.input_flushed = 0; + *this.size = 0; + *this.write_state = WriteState::Idle; + return Poll::Ready(Ok(())); + } + } + } + } + + fn poll_shutdown( + self: std::pin::Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> std::task::Poll> { + self.poll_flush(cx) + } +} + +impl MetadataBlocksWriter { + pub fn new(writer: W) -> Self { + Self { + input: [0; 8192], + input_flushed: 0, + size: 0, + size_addr: None, + output: PartialBuffer::new([0; 4096]), + output_flushed: 0, + zstd: None, + seek_state: SeekState::Idle, + write_state: WriteState::Idle, + writer, + } + } +} + +use async_compression::codecs::{Decode, ZstdDecoder}; +use tokio::io::AsyncRead; + +#[pin_project::pin_project] +pub struct MetadataBlocksReader { + #[pin] + reader: R, + size_buf: [u8; 2], + size_bytes_read: usize, + compressed: [u8; 8192], + compressed_size: usize, + compressed_pos: usize, + output: PartialBuffer<[u8; 8192]>, + output_pos: usize, + zstd: Option, + state: ReadState, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum ReadState { + ReadingSize, + ReadingData, + Decompressing, + Outputting, + Eof, +} + +impl MetadataBlocksReader { + pub fn new(reader: R) -> Self { + Self { + reader, + size_buf: [0; 2], + size_bytes_read: 0, + compressed: [0; 8192], + compressed_size: 0, + compressed_pos: 0, + output: PartialBuffer::new([0; 8192]), + output_pos: 0, + zstd: None, + state: ReadState::ReadingSize, + } + } +} + +use std::io::Read; + +impl Read for MetadataBlocksReader { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + loop { + match self.state { + ReadState::ReadingSize => { + let n = self + .reader + .read(&mut self.size_buf[self.size_bytes_read..])?; + if n == 0 { + if self.size_bytes_read == 0 { + self.state = ReadState::Eof; + return Ok(0); + } else { + return Err(std::io::Error::new( + std::io::ErrorKind::UnexpectedEof, + "Unexpected EOF reading size header", + )); + } + } + + self.size_bytes_read += n; + if self.size_bytes_read < 2 { + continue; + } + + let size_header = u16::from_le_bytes(self.size_buf); + let is_compressed = (size_header & 0x8000) == 0; + let size = (size_header & 0x7FFF) as usize; + + if !is_compressed { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "Uncompressed metadata blocks not supported", + )); + } + + if size == 0 || size > 8192 { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + format!("Invalid metadata block size: {}", size), + )); + } + + self.compressed_size = size; + self.compressed_pos = 0; + self.size_bytes_read = 0; + self.state = ReadState::ReadingData; + continue; + } + + ReadState::ReadingData => { + let n = self + .reader + .read(&mut self.compressed[self.compressed_pos..self.compressed_size])?; + if n == 0 { + return Err(std::io::Error::new( + std::io::ErrorKind::UnexpectedEof, + "Unexpected EOF reading compressed data", + )); + } + + self.compressed_pos += n; + if self.compressed_pos < self.compressed_size { + continue; + } + + self.zstd = Some(ZstdDecoder::new()); + self.output_pos = 0; + self.output.reset(); + self.state = ReadState::Decompressing; + continue; + } + + ReadState::Decompressing => { + if self.output.unwritten().is_empty() { + self.state = ReadState::Outputting; + continue; + } + + let mut input = PartialBuffer::new(&self.compressed[..self.compressed_size]); + let decoder = self.zstd.as_mut().unwrap(); + + if decoder.decode(&mut input, &mut self.output)? { + self.zstd = None; + self.state = ReadState::Outputting; + } + continue; + } + + ReadState::Outputting => { + let available = self.output.written().len() - self.output_pos; + if available == 0 { + if self.zstd.is_none() { + self.state = ReadState::ReadingSize; + continue; + } else { + self.output.reset(); + self.output_pos = 0; + self.state = ReadState::Decompressing; + continue; + } + } + + let to_copy = available.min(buf.len()); + buf[..to_copy].copy_from_slice( + &self.output.written()[self.output_pos..self.output_pos + to_copy], + ); + self.output_pos += to_copy; + return Ok(to_copy); + } + + ReadState::Eof => { + return Ok(0); + } + } + } + } +} + +impl AsyncRead for MetadataBlocksReader { + fn poll_read( + mut self: std::pin::Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + buf: &mut tokio::io::ReadBuf<'_>, + ) -> Poll> { + loop { + let mut this = self.as_mut().project(); + + match *this.state { + ReadState::ReadingSize => { + let mut read_buf = + tokio::io::ReadBuf::new(&mut this.size_buf[*this.size_bytes_read..]); + ready!(this.reader.as_mut().poll_read(cx, &mut read_buf))?; + + let n = read_buf.filled().len(); + if n == 0 { + if *this.size_bytes_read == 0 { + *this.state = ReadState::Eof; + return Poll::Ready(Ok(())); + } else { + return Poll::Ready(Err(std::io::Error::new( + std::io::ErrorKind::UnexpectedEof, + "Unexpected EOF reading size header", + ))); + } + } + + *this.size_bytes_read += n; + if *this.size_bytes_read < 2 { + continue; + } + + let size_header = u16::from_le_bytes(*this.size_buf); + let is_compressed = (size_header & 0x8000) == 0; + let size = (size_header & 0x7FFF) as usize; + + if !is_compressed { + return Poll::Ready(Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "Uncompressed metadata blocks not supported", + ))); + } + + if size == 0 || size > 8192 { + return Poll::Ready(Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + format!("Invalid metadata block size: {}", size), + ))); + } + + *this.compressed_size = size; + *this.compressed_pos = 0; + *this.size_bytes_read = 0; + *this.state = ReadState::ReadingData; + continue; + } + + ReadState::ReadingData => { + let mut read_buf = tokio::io::ReadBuf::new( + &mut this.compressed[*this.compressed_pos..*this.compressed_size], + ); + ready!(this.reader.as_mut().poll_read(cx, &mut read_buf))?; + + let n = read_buf.filled().len(); + if n == 0 { + return Poll::Ready(Err(std::io::Error::new( + std::io::ErrorKind::UnexpectedEof, + "Unexpected EOF reading compressed data", + ))); + } + + *this.compressed_pos += n; + if *this.compressed_pos < *this.compressed_size { + continue; + } + + *this.zstd = Some(ZstdDecoder::new()); + *this.output_pos = 0; + this.output.reset(); + *this.state = ReadState::Decompressing; + continue; + } + + ReadState::Decompressing => { + if this.output.unwritten().is_empty() { + *this.state = ReadState::Outputting; + continue; + } + + let mut input = PartialBuffer::new(&this.compressed[..*this.compressed_size]); + let decoder = this.zstd.as_mut().unwrap(); + + if decoder.decode(&mut input, this.output)? { + *this.zstd = None; + *this.state = ReadState::Outputting; + } + continue; + } + + ReadState::Outputting => { + let available = this.output.written().len() - *this.output_pos; + if available == 0 { + if this.zstd.is_none() { + *this.state = ReadState::ReadingSize; + continue; + } else { + this.output.reset(); + *this.output_pos = 0; + *this.state = ReadState::Decompressing; + continue; + } + } + + let to_copy = available.min(buf.remaining()); + buf.put_slice( + &this.output.written()[*this.output_pos..*this.output_pos + to_copy], + ); + *this.output_pos += to_copy; + return Poll::Ready(Ok(())); + } + + ReadState::Eof => { + return Poll::Ready(Ok(())); + } + } + } + } +} + +#[cfg(test)] +mod tests { + use std::io::{Cursor, Seek, SeekFrom}; + + use proptest::prelude::*; + + use super::*; + + #[test] + fn test_sync_roundtrip_empty() { + use std::io::{Read, Write}; + let mut buffer = Cursor::new(Vec::new()); + let mut writer = MetadataBlocksWriter::new(&mut buffer); + writer.flush().unwrap(); + + buffer.seek(SeekFrom::Start(0)).unwrap(); + let mut reader = MetadataBlocksReader::new(buffer); + let mut output = Vec::new(); + reader.read_to_end(&mut output).unwrap(); + + assert_eq!(output, Vec::::new()); + } + + #[test] + fn test_sync_roundtrip_small() { + use std::io::{Read, Write}; + let input = b"Hello, World!"; + let mut buffer = Cursor::new(Vec::new()); + let mut writer = MetadataBlocksWriter::new(&mut buffer); + writer.write_all(input).unwrap(); + writer.flush().unwrap(); + + buffer.seek(SeekFrom::Start(0)).unwrap(); + let mut reader = MetadataBlocksReader::new(buffer); + let mut output = Vec::new(); + reader.read_to_end(&mut output).unwrap(); + + assert_eq!(output, input); + } + + #[test] + fn test_sync_roundtrip_exact_block_size() { + use std::io::{Read, Write}; + let input = vec![0x42u8; 8192]; + let mut buffer = Cursor::new(Vec::new()); + let mut writer = MetadataBlocksWriter::new(&mut buffer); + writer.write_all(&input).unwrap(); + writer.flush().unwrap(); + + buffer.seek(SeekFrom::Start(0)).unwrap(); + let mut reader = MetadataBlocksReader::new(buffer); + let mut output = Vec::new(); + reader.read_to_end(&mut output).unwrap(); + + assert_eq!(output, input); + } + + #[test] + fn test_sync_roundtrip_larger_than_block() { + use std::io::{Read, Write}; + let input = vec![0x55u8; 16384]; + let mut buffer = Cursor::new(Vec::new()); + let mut writer = MetadataBlocksWriter::new(&mut buffer); + writer.write_all(&input).unwrap(); + writer.flush().unwrap(); + + buffer.seek(SeekFrom::Start(0)).unwrap(); + let mut reader = MetadataBlocksReader::new(buffer); + let mut output = Vec::new(); + reader.read_to_end(&mut output).unwrap(); + + assert_eq!(output, input); + } + + #[test] + fn test_sync_roundtrip_multiple_blocks() { + use std::io::{Read, Write}; + let input = vec![0xAAu8; 24576]; + let mut buffer = Cursor::new(Vec::new()); + let mut writer = MetadataBlocksWriter::new(&mut buffer); + writer.write_all(&input).unwrap(); + writer.flush().unwrap(); + + buffer.seek(SeekFrom::Start(0)).unwrap(); + let mut reader = MetadataBlocksReader::new(buffer); + let mut output = Vec::new(); + reader.read_to_end(&mut output).unwrap(); + + assert_eq!(output, input); + } + + #[test] + fn test_sync_roundtrip_incremental_writes() { + use std::io::{Read, Write}; + let input = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut buffer = Cursor::new(Vec::new()); + let mut writer = MetadataBlocksWriter::new(&mut buffer); + + for chunk in input.chunks(5) { + writer.write_all(chunk).unwrap(); + } + writer.flush().unwrap(); + + buffer.seek(SeekFrom::Start(0)).unwrap(); + let mut reader = MetadataBlocksReader::new(buffer); + let mut output = Vec::new(); + reader.read_to_end(&mut output).unwrap(); + + assert_eq!(output, input); + } + + #[tokio::test] + async fn test_async_roundtrip_empty() { + use tokio::io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt}; + let mut buffer = Cursor::new(Vec::new()); + let mut writer = MetadataBlocksWriter::new(&mut buffer); + AsyncWriteExt::flush(&mut writer).await.unwrap(); + + AsyncSeekExt::seek(&mut buffer, SeekFrom::Start(0)) + .await + .unwrap(); + let mut reader = MetadataBlocksReader::new(buffer); + let mut output = Vec::new(); + AsyncReadExt::read_to_end(&mut reader, &mut output) + .await + .unwrap(); + + assert_eq!(output, Vec::::new()); + } + + #[tokio::test] + async fn test_async_roundtrip_small() { + use tokio::io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt}; + let input = b"Hello, World!"; + let mut buffer = Cursor::new(Vec::new()); + let mut writer = MetadataBlocksWriter::new(&mut buffer); + AsyncWriteExt::write_all(&mut writer, input).await.unwrap(); + AsyncWriteExt::flush(&mut writer).await.unwrap(); + + AsyncSeekExt::seek(&mut buffer, SeekFrom::Start(0)) + .await + .unwrap(); + let mut reader = MetadataBlocksReader::new(buffer); + let mut output = Vec::new(); + AsyncReadExt::read_to_end(&mut reader, &mut output) + .await + .unwrap(); + + assert_eq!(output, input); + } + + #[tokio::test] + async fn test_async_roundtrip_exact_block_size() { + use tokio::io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt}; + let input = vec![0x42u8; 8192]; + let mut buffer = Cursor::new(Vec::new()); + let mut writer = MetadataBlocksWriter::new(&mut buffer); + AsyncWriteExt::write_all(&mut writer, &input).await.unwrap(); + AsyncWriteExt::flush(&mut writer).await.unwrap(); + + AsyncSeekExt::seek(&mut buffer, SeekFrom::Start(0)) + .await + .unwrap(); + let mut reader = MetadataBlocksReader::new(buffer); + let mut output = Vec::new(); + AsyncReadExt::read_to_end(&mut reader, &mut output) + .await + .unwrap(); + + assert_eq!(output, input); + } + + #[tokio::test] + async fn test_async_roundtrip_larger_than_block() { + use tokio::io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt}; + let input = vec![0x55u8; 16384]; + let mut buffer = Cursor::new(Vec::new()); + let mut writer = MetadataBlocksWriter::new(&mut buffer); + AsyncWriteExt::write_all(&mut writer, &input).await.unwrap(); + AsyncWriteExt::flush(&mut writer).await.unwrap(); + + AsyncSeekExt::seek(&mut buffer, SeekFrom::Start(0)) + .await + .unwrap(); + let mut reader = MetadataBlocksReader::new(buffer); + let mut output = Vec::new(); + AsyncReadExt::read_to_end(&mut reader, &mut output) + .await + .unwrap(); + + assert_eq!(output, input); + } + + #[tokio::test] + async fn test_async_roundtrip_multiple_blocks() { + use tokio::io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt}; + let input = vec![0xAAu8; 24576]; + let mut buffer = Cursor::new(Vec::new()); + let mut writer = MetadataBlocksWriter::new(&mut buffer); + AsyncWriteExt::write_all(&mut writer, &input).await.unwrap(); + AsyncWriteExt::flush(&mut writer).await.unwrap(); + + AsyncSeekExt::seek(&mut buffer, SeekFrom::Start(0)) + .await + .unwrap(); + let mut reader = MetadataBlocksReader::new(buffer); + let mut output = Vec::new(); + AsyncReadExt::read_to_end(&mut reader, &mut output) + .await + .unwrap(); + + assert_eq!(output, input); + } + + proptest! { + #[test] + fn test_sync_roundtrip_proptest(input in prop::collection::vec(any::(), 0..50000)) { + use std::io::{Read, Write}; + let mut buffer = Cursor::new(Vec::new()); + let mut writer = MetadataBlocksWriter::new(&mut buffer); + writer.write_all(&input).unwrap(); + writer.flush().unwrap(); + + buffer.seek(SeekFrom::Start(0)).unwrap(); + let mut reader = MetadataBlocksReader::new(buffer); + let mut output = Vec::new(); + reader.read_to_end(&mut output).unwrap(); + + prop_assert_eq!(output, input); + } + + #[test] + fn test_sync_roundtrip_chunked_writes( + input in prop::collection::vec(any::(), 0..50000), + chunk_size in 1usize..1000 + ) { + use std::io::{Read, Write}; + let mut buffer = Cursor::new(Vec::new()); + let mut writer = MetadataBlocksWriter::new(&mut buffer); + + for chunk in input.chunks(chunk_size) { + writer.write_all(chunk).unwrap(); + } + writer.flush().unwrap(); + + buffer.seek(SeekFrom::Start(0)).unwrap(); + let mut reader = MetadataBlocksReader::new(buffer); + let mut output = Vec::new(); + reader.read_to_end(&mut output).unwrap(); + + prop_assert_eq!(output, input); + } + + #[test] + fn test_sync_roundtrip_chunked_reads( + input in prop::collection::vec(any::(), 0..50000), + chunk_size in 1usize..1000 + ) { + use std::io::{Read, Write}; + let mut buffer = Cursor::new(Vec::new()); + let mut writer = MetadataBlocksWriter::new(&mut buffer); + writer.write_all(&input).unwrap(); + writer.flush().unwrap(); + + buffer.seek(SeekFrom::Start(0)).unwrap(); + let mut reader = MetadataBlocksReader::new(buffer); + let mut output = Vec::new(); + let mut chunk = vec![0u8; chunk_size]; + + loop { + let n = reader.read(&mut chunk).unwrap(); + if n == 0 { + break; + } + output.extend_from_slice(&chunk[..n]); + } + + prop_assert_eq!(output, input); + } + } + + #[test] + fn test_sync_multiple_flush_cycles() { + use std::io::{Read, Write}; + let input1 = b"First block of data"; + let input2 = b"Second block of data"; + let input3 = b"Third block of data"; + + let mut buffer = Cursor::new(Vec::new()); + let mut writer = MetadataBlocksWriter::new(&mut buffer); + + writer.write_all(input1).unwrap(); + writer.flush().unwrap(); + + writer.write_all(input2).unwrap(); + writer.flush().unwrap(); + + writer.write_all(input3).unwrap(); + writer.flush().unwrap(); + + buffer.seek(SeekFrom::Start(0)).unwrap(); + let mut reader = MetadataBlocksReader::new(buffer); + let mut output = Vec::new(); + reader.read_to_end(&mut output).unwrap(); + + let expected: Vec = input1 + .iter() + .chain(input2.iter()) + .chain(input3.iter()) + .copied() + .collect(); + assert_eq!(output, expected); + } + + #[tokio::test] + async fn test_async_multiple_flush_cycles() { + use tokio::io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt}; + let input1 = b"First block of data"; + let input2 = b"Second block of data"; + let input3 = b"Third block of data"; + + let mut buffer = Cursor::new(Vec::new()); + let mut writer = MetadataBlocksWriter::new(&mut buffer); + + AsyncWriteExt::write_all(&mut writer, input1).await.unwrap(); + AsyncWriteExt::flush(&mut writer).await.unwrap(); + + AsyncWriteExt::write_all(&mut writer, input2).await.unwrap(); + AsyncWriteExt::flush(&mut writer).await.unwrap(); + + AsyncWriteExt::write_all(&mut writer, input3).await.unwrap(); + AsyncWriteExt::flush(&mut writer).await.unwrap(); + + AsyncSeekExt::seek(&mut buffer, SeekFrom::Start(0)) + .await + .unwrap(); + let mut reader = MetadataBlocksReader::new(buffer); + let mut output = Vec::new(); + AsyncReadExt::read_to_end(&mut reader, &mut output) + .await + .unwrap(); + + let expected: Vec = input1 + .iter() + .chain(input2.iter()) + .chain(input3.iter()) + .copied() + .collect(); + assert_eq!(output, expected); + } + + #[test] + fn test_sync_size_header_format() { + use std::io::{Read, Write}; + let input = b"test"; + let mut buffer = Cursor::new(Vec::new()); + let mut writer = MetadataBlocksWriter::new(&mut buffer); + writer.write_all(input).unwrap(); + writer.flush().unwrap(); + + buffer.seek(SeekFrom::Start(0)).unwrap(); + let mut size_header = [0u8; 2]; + buffer.read_exact(&mut size_header).unwrap(); + + let size_value = u16::from_le_bytes(size_header); + let is_compressed = (size_value & 0x8000) == 0; + let size = size_value & 0x7FFF; + + assert!(is_compressed, "Data should be compressed"); + assert!(size > 0, "Compressed size should be greater than 0"); + assert!(size <= 8192, "Compressed size should not exceed 8192"); + } +} diff --git a/core/startos/src/util/sync.rs b/core/startos/src/util/sync.rs index e9d0251eb..98b24509d 100644 --- a/core/startos/src/util/sync.rs +++ b/core/startos/src/util/sync.rs @@ -5,8 +5,8 @@ use std::sync::atomic::AtomicUsize; use std::sync::{Arc, Weak}; use std::task::{Poll, Waker}; -use futures::stream::BoxStream; use futures::Stream; +use futures::stream::BoxStream; use crate::prelude::*; @@ -266,6 +266,9 @@ impl Watch { version: 0, } } + pub fn watcher_count(&self) -> usize { + Arc::strong_count(&self.shared) + } #[cfg_attr(feature = "unstable", inline(never))] pub fn poll_changed(&mut self, cx: &mut std::task::Context<'_>) -> Poll<()> { self.shared.mutate(|shared| { diff --git a/core/startos/src/util/tui.rs b/core/startos/src/util/tui.rs new file mode 100644 index 000000000..eb721c2bb --- /dev/null +++ b/core/startos/src/util/tui.rs @@ -0,0 +1,144 @@ +use std::io::Write; +use std::str::FromStr; + +use r3bl_tui::{DefaultIoDevices, ReadlineAsyncContext, ReadlineEvent}; + +use crate::prelude::*; + +fn map_miette(m: miette::Error) -> Error { + Error::new(eyre!("{m}"), ErrorKind::Filesystem) +} +fn noninteractive_err() -> Error { + Error::new( + eyre!("Terminal must be in interactive mode for this wizard"), + ErrorKind::Filesystem, + ) +} + +pub fn parse_as<'a, T>(what: &'a str) -> impl Fn(&str) -> Result + 'a +where + T: FromStr, +{ + move |s| { + s.parse::() + .map_err(|_| format!("Please enter a valid {what}.")) + } +} + +pub async fn prompt Result>( + prompt: &str, + mut parse: Parse, + default: Option, +) -> Result { + let mut rl_ctx = ReadlineAsyncContext::try_new(Some(prompt)) + .await + .map_err(map_miette)? + .ok_or_else(noninteractive_err)?; + let res = loop { + match rl_ctx.read_line().await.map_err(map_miette)? { + ReadlineEvent::Line(l) => { + let l = l.trim(); + if !l.is_empty() { + match parse(l) { + Ok(a) => break a, + Err(e) => { + writeln!(&mut rl_ctx.shared_writer, "{e}")?; + } + } + } else if let Some(default) = default { + break default; + } + } + ReadlineEvent::Eof | ReadlineEvent::Interrupted => { + return Err(Error::new(eyre!("Aborted"), ErrorKind::Cancelled)); + } + _ => (), + } + }; + + rl_ctx.request_shutdown(None).await.map_err(map_miette)?; + rl_ctx.await_shutdown().await; + + Ok(res) +} + +pub async fn prompt_multiline< + T, + E: std::fmt::Display, + HandleLine: FnMut(String) -> Result, E>, +>( + prompt: &str, + mut handle_line: HandleLine, +) -> Result { + println!("{prompt}"); + let mut rl_ctx = ReadlineAsyncContext::try_new(None::<&str>) + .await + .map_err(map_miette)? + .ok_or_else(noninteractive_err)?; + let res = loop { + match rl_ctx.read_line().await.map_err(map_miette)? { + ReadlineEvent::Line(l) => match handle_line(l) { + Ok(Some(a)) => break a, + Ok(None) => (), + Err(e) => writeln!(&mut rl_ctx.shared_writer, "{e}")?, + }, + ReadlineEvent::Eof | ReadlineEvent::Interrupted => { + return Err(Error::new(eyre!("Aborted"), ErrorKind::Cancelled)); + } + _ => (), + } + }; + + rl_ctx.request_shutdown(None).await.map_err(map_miette)?; + rl_ctx.await_shutdown().await; + + Ok(res) +} + +pub async fn choose_custom_display<'t, T: std::fmt::Display>( + prompt: &str, + choices: &'t [T], + mut display: impl FnMut(&T) -> String, +) -> Result<&'t T, Error> { + let mut io = DefaultIoDevices::default(); + let style = r3bl_tui::readline_async::StyleSheet::default(); + let string_choices = choices.into_iter().map(|c| display(c)).collect::>(); + let choice = r3bl_tui::readline_async::choose( + prompt, + string_choices.clone(), + None, + None, + r3bl_tui::HowToChoose::Single, + style, + ( + &mut io.output_device, + &mut io.input_device, + io.maybe_shared_writer, + ), + ) + .await + .map_err(map_miette)?; + if choice.len() < 1 { + return Err(Error::new(eyre!("Aborted"), ErrorKind::Cancelled)); + } + let (idx, _) = string_choices + .iter() + .enumerate() + .find(|(_, s)| s.as_str() == choice[0].as_str()) + .ok_or_else(|| { + Error::new( + eyre!("selected choice does not appear in input"), + ErrorKind::Incoherent, + ) + })?; + let choice = &choices[idx]; + println!("{prompt} {choice}"); + Ok(&choice) +} + +pub async fn choose<'t, T: std::fmt::Display>( + prompt: &str, + choices: &'t [T], +) -> Result<&'t T, Error> { + choose_custom_display(prompt, choices, |t| t.to_string()).await +} diff --git a/core/startos/src/version/mod.rs b/core/startos/src/version/mod.rs index 761a96952..6f8bae32a 100644 --- a/core/startos/src/version/mod.rs +++ b/core/startos/src/version/mod.rs @@ -5,14 +5,14 @@ use std::panic::{RefUnwindSafe, UnwindSafe}; use color_eyre::eyre::eyre; use futures::future::BoxFuture; use futures::{Future, FutureExt}; -use imbl_value::{to_value, InternedString}; +use imbl_value::{InternedString, to_value}; use patch_db::json_ptr::ROOT; +use crate::Error; use crate::context::RpcContext; use crate::db::model::Database; use crate::prelude::*; use crate::progress::PhaseProgressTrackerHandle; -use crate::Error; mod v0_3_5; mod v0_3_5_1; @@ -51,8 +51,9 @@ mod v0_4_0_alpha_9; mod v0_4_0_alpha_10; mod v0_4_0_alpha_11; +mod v0_4_0_alpha_12; -pub type Current = v0_4_0_alpha_11::Version; // VERSION_BUMP +pub type Current = v0_4_0_alpha_12::Version; // VERSION_BUMP impl Current { #[instrument(skip(self, db))] @@ -97,8 +98,8 @@ pub async fn post_init( .as_server_info() .as_post_init_migration_todos() .de()?; + progress.start(); if !todos.is_empty() { - progress.set_total(todos.len() as u64); while let Some((version, input)) = { peek = ctx.db.peek().await; peek.as_public() @@ -121,7 +122,6 @@ pub async fn post_init( }) .await .result?; - progress += 1; } } progress.complete(); @@ -166,7 +166,8 @@ enum Version { V0_4_0_alpha_8(Wrapper), V0_4_0_alpha_9(Wrapper), V0_4_0_alpha_10(Wrapper), - V0_4_0_alpha_11(Wrapper), // VERSION_BUMP + V0_4_0_alpha_11(Wrapper), + V0_4_0_alpha_12(Wrapper), // VERSION_BUMP Other(exver::Version), } @@ -220,7 +221,8 @@ impl Version { Self::V0_4_0_alpha_8(v) => DynVersion(Box::new(v.0)), Self::V0_4_0_alpha_9(v) => DynVersion(Box::new(v.0)), Self::V0_4_0_alpha_10(v) => DynVersion(Box::new(v.0)), - Self::V0_4_0_alpha_11(v) => DynVersion(Box::new(v.0)), // VERSION_BUMP + Self::V0_4_0_alpha_11(v) => DynVersion(Box::new(v.0)), + Self::V0_4_0_alpha_12(v) => DynVersion(Box::new(v.0)), // VERSION_BUMP Self::Other(v) => { return Err(Error::new( eyre!("unknown version {v}"), @@ -266,7 +268,8 @@ impl Version { Version::V0_4_0_alpha_8(Wrapper(x)) => x.semver(), Version::V0_4_0_alpha_9(Wrapper(x)) => x.semver(), Version::V0_4_0_alpha_10(Wrapper(x)) => x.semver(), - Version::V0_4_0_alpha_11(Wrapper(x)) => x.semver(), // VERSION_BUMP + Version::V0_4_0_alpha_11(Wrapper(x)) => x.semver(), + Version::V0_4_0_alpha_12(Wrapper(x)) => x.semver(), // VERSION_BUMP Version::Other(x) => x.clone(), } } diff --git a/core/startos/src/version/v0_3_6_alpha_0.rs b/core/startos/src/version/v0_3_6_alpha_0.rs index 0edc98677..d396e0c97 100644 --- a/core/startos/src/version/v0_3_6_alpha_0.rs +++ b/core/startos/src/version/v0_3_6_alpha_0.rs @@ -1,4 +1,4 @@ -use std::collections::BTreeMap; +use std::collections::{BTreeMap, BTreeSet}; use std::ffi::OsStr; use std::path::Path; @@ -7,7 +7,7 @@ use const_format::formatcp; use ed25519_dalek::SigningKey; use exver::{PreReleaseSegment, VersionRange}; use imbl_value::{InternedString, json}; -use models::{PackageId, ReplayId}; +use models::{HostId, Id, PackageId, ReplayId}; use openssl::pkey::PKey; use openssl::x509::X509; use sqlx::postgres::PgConnectOptions; @@ -24,8 +24,9 @@ use crate::disk::mount::filesystem::cifs::Cifs; use crate::disk::mount::util::unmount; use crate::hostname::Hostname; use crate::net::forward::AvailablePorts; +use crate::net::host::Host; use crate::net::keys::KeyStore; -use crate::net::tor::TorSecretKey; +use crate::net::tor::{OnionAddress, TorSecretKey}; use crate::notifications::Notifications; use crate::prelude::*; use crate::s9pk::merkle_archive::source::multi_cursor_file::MultiCursorFile; @@ -93,69 +94,6 @@ async fn init_postgres(datadir: impl AsRef) -> Result { crate::disk::mount::util::bind(&db_dir, "/var/lib/postgresql", false).await?; - let pg_version_string = pg_version.to_string(); - let pg_version_path = db_dir.join(&pg_version_string); - if exists - // maybe migrate - { - let incomplete_path = db_dir.join(format!("{pg_version}.migration.incomplete")); - if tokio::fs::metadata(&incomplete_path).await.is_ok() // previous migration was incomplete - && tokio::fs::metadata(&pg_version_path).await.is_ok() - { - tokio::fs::remove_dir_all(&pg_version_path).await?; - } - if tokio::fs::metadata(&pg_version_path).await.is_err() - // need to migrate - { - let conf_dir = Path::new("/etc/postgresql").join(pg_version.to_string()); - let conf_dir_tmp = { - let mut tmp = conf_dir.clone(); - tmp.set_extension("tmp"); - tmp - }; - if tokio::fs::metadata(&conf_dir).await.is_ok() { - Command::new("mv") - .arg(&conf_dir) - .arg(&conf_dir_tmp) - .invoke(ErrorKind::Filesystem) - .await?; - } - let mut old_version = pg_version; - while old_version > 13 - /* oldest pg version included in startos */ - { - old_version -= 1; - let old_datadir = db_dir.join(old_version.to_string()); - if tokio::fs::metadata(&old_datadir).await.is_ok() { - tokio::fs::File::create(&incomplete_path) - .await? - .sync_all() - .await?; - Command::new("pg_upgradecluster") - .arg(old_version.to_string()) - .arg("main") - .invoke(crate::ErrorKind::Database) - .await?; - break; - } - } - if tokio::fs::metadata(&conf_dir).await.is_ok() { - if tokio::fs::metadata(&conf_dir).await.is_ok() { - tokio::fs::remove_dir_all(&conf_dir).await?; - } - Command::new("mv") - .arg(&conf_dir_tmp) - .arg(&conf_dir) - .invoke(ErrorKind::Filesystem) - .await?; - } - tokio::fs::remove_file(&incomplete_path).await?; - } - if tokio::fs::metadata(&incomplete_path).await.is_ok() { - unreachable!() // paranoia - } - } - Command::new("systemctl") .arg("start") .arg(format!("postgresql@{pg_version}-main.service")) @@ -209,7 +147,12 @@ pub struct Version; impl VersionT for Version { type Previous = v0_3_5_2::Version; - type PreUpRes = (AccountInfo, SshKeys, CifsTargets); + type PreUpRes = ( + AccountInfo, + SshKeys, + CifsTargets, + BTreeMap>, + ); fn semver(self) -> exver::Version { V0_3_6_alpha_0.clone() } @@ -224,9 +167,15 @@ impl VersionT for Version { let cifs = previous_cifs(&pg).await?; - Ok((account, ssh_keys, cifs)) + let tor_keys = previous_tor_keys(&pg).await?; + + Ok((account, ssh_keys, cifs, tor_keys)) } - fn up(self, db: &mut Value, (account, ssh_keys, cifs): Self::PreUpRes) -> Result { + fn up( + self, + db: &mut Value, + (account, ssh_keys, cifs, tor_keys): Self::PreUpRes, + ) -> Result { let prev_package_data = db["package-data"].clone(); let wifi = json!({ @@ -288,9 +237,15 @@ impl VersionT for Version { "ui": db["ui"], }); + let mut keystore = KeyStore::new(&account)?; + for key in tor_keys.values().flat_map(|v| v.values()) { + assert!(key.is_valid()); + keystore.onion.insert(key.clone()); + } + let private = { let mut value = json!({}); - value["keyStore"] = to_value(&KeyStore::new(&account)?)?; + value["keyStore"] = crate::dbg!(to_value(&keystore)?); value["password"] = to_value(&account.password)?; value["compatS9pkKey"] = to_value(&crate::db::model::private::generate_developer_key())?; @@ -373,6 +328,20 @@ impl VersionT for Version { false }; + let onions = input[&*id]["installed"]["interface-addresses"] + .as_object() + .into_iter() + .flatten() + .filter_map(|(id, addrs)| { + addrs["tor-address"].as_str().map(|addr| { + Ok(( + HostId::from(Id::try_from(id.clone())?), + addr.parse::()?, + )) + }) + }) + .collect::, Error>>()?; + if let Err(e) = async { let package_s9pk = tokio::fs::File::open(path).await?; let file = MultiCursorFile::open(&package_s9pk).await?; @@ -390,19 +359,44 @@ impl VersionT for Version { .await? .await?; - if configured { - ctx.db - .mutate(|db| { - db.as_public_mut() - .as_package_data_mut() - .as_idx_mut(&id) - .or_not_found(&id)? + let to_sync = ctx + .db + .mutate(|db| { + let mut to_sync = BTreeSet::new(); + + let package = db + .as_public_mut() + .as_package_data_mut() + .as_idx_mut(&id) + .or_not_found(&id)?; + if configured { + package .as_tasks_mut() - .remove(&ReplayId::from("needs-config")) - }) - .await - .result?; + .remove(&ReplayId::from("needs-config"))?; + } + for (id, onion) in onions { + package + .as_hosts_mut() + .upsert(&id, || Ok(Host::new()))? + .as_onions_mut() + .mutate(|o| { + o.clear(); + o.insert(onion); + Ok(()) + })?; + to_sync.insert(id); + } + Ok(to_sync) + }) + .await + .result?; + + if let Some(service) = &*ctx.services.get(&id).await { + for host_id in to_sync { + service.sync_host(host_id.clone()).await?; + } } + Ok::<_, Error>(()) } .await @@ -470,14 +464,12 @@ async fn previous_account_info(pg: &sqlx::Pool) -> Result>, _>("tor_key") .with_ctx(|_| (ErrorKind::Database, "tor_key"))? { - <[u8; 64]>::try_from(bytes) - .map_err(|e| { - Error::new( - eyre!("expected vec of len 64, got len {}", e.len()), - ErrorKind::ParseDbField, - ) - }) - .with_ctx(|_| (ErrorKind::Database, "password.u8 64"))? + <[u8; 64]>::try_from(bytes).map_err(|e| { + Error::new( + eyre!("expected vec of len 64, got len {}", e.len()), + ErrorKind::ParseDbField, + ) + })? } else { ed25519_expand_key( &<[u8; 32]>::try_from( @@ -490,8 +482,7 @@ async fn previous_account_info(pg: &sqlx::Pool) -> Result) -> Result, +) -> Result>, Error> { + let mut res = BTreeMap::>::new(); + let net_key_query = sqlx::query(r#"SELECT * FROM network_keys"#) + .fetch_all(pg) + .await + .with_kind(ErrorKind::Database)?; + + for row in net_key_query { + let package_id: PackageId = row + .try_get::("package") + .with_ctx(|_| (ErrorKind::Database, "network_keys::package"))? + .parse()?; + let interface_id: HostId = row + .try_get::("interface") + .with_ctx(|_| (ErrorKind::Database, "network_keys::interface"))? + .parse()?; + let key = TorSecretKey::from_bytes(ed25519_expand_key( + &<[u8; 32]>::try_from( + row.try_get::, _>("key") + .with_ctx(|_| (ErrorKind::Database, "network_keys::key"))?, + ) + .map_err(|e| { + Error::new( + eyre!("expected vec of len 32, got len {}", e.len()), + ErrorKind::ParseDbField, + ) + })?, + ))?; + res.entry(package_id).or_default().insert(interface_id, key); + } + + let tor_key_query = sqlx::query(r#"SELECT * FROM tor"#) + .fetch_all(pg) + .await + .with_kind(ErrorKind::Database)?; + + for row in tor_key_query { + let package_id: PackageId = row + .try_get::("package") + .with_ctx(|_| (ErrorKind::Database, "tor::package"))? + .parse()?; + let interface_id: HostId = row + .try_get::("interface") + .with_ctx(|_| (ErrorKind::Database, "tor::interface"))? + .parse()?; + let key = TorSecretKey::from_bytes( + <[u8; 64]>::try_from( + row.try_get::, _>("key") + .with_ctx(|_| (ErrorKind::Database, "tor::key"))?, + ) + .map_err(|e| { + Error::new( + eyre!("expected vec of len 64, got len {}", e.len()), + ErrorKind::ParseDbField, + ) + })?, + )?; + res.entry(package_id).or_default().insert(interface_id, key); + } + + Ok(res) +} diff --git a/core/startos/src/version/v0_3_6_alpha_10.rs b/core/startos/src/version/v0_3_6_alpha_10.rs index 74fe17e89..7b514bbf9 100644 --- a/core/startos/src/version/v0_3_6_alpha_10.rs +++ b/core/startos/src/version/v0_3_6_alpha_10.rs @@ -6,7 +6,7 @@ use models::GatewayId; use serde::{Deserialize, Serialize}; use super::v0_3_5::V0_3_0_COMPAT; -use super::{v0_3_6_alpha_9, VersionT}; +use super::{VersionT, v0_3_6_alpha_9}; use crate::net::host::address::PublicDomainConfig; use crate::net::tor::OnionAddress; use crate::prelude::*; diff --git a/core/startos/src/version/v0_3_6_alpha_7.rs b/core/startos/src/version/v0_3_6_alpha_7.rs index 241404fd2..358ddaa49 100644 --- a/core/startos/src/version/v0_3_6_alpha_7.rs +++ b/core/startos/src/version/v0_3_6_alpha_7.rs @@ -50,10 +50,7 @@ impl VersionT for Version { async fn post_up(self, ctx: &RpcContext, _input: Value) -> Result<(), Error> { Command::new("systemd-firstboot") .arg("--root=/media/startos/config/overlay/") - .arg(format!( - "--hostname={}", - ctx.account.read().await.hostname.0 - )) + .arg(ctx.account.peek(|a| format!("--hostname={}", a.hostname.0))) .invoke(ErrorKind::ParseSysInfo) .await?; Ok(()) diff --git a/core/startos/src/version/v0_3_6_alpha_8.rs b/core/startos/src/version/v0_3_6_alpha_8.rs index 92f96b4c4..b58d9c9e6 100644 --- a/core/startos/src/version/v0_3_6_alpha_8.rs +++ b/core/startos/src/version/v0_3_6_alpha_8.rs @@ -115,7 +115,7 @@ impl VersionT for Version { let manifest: Manifest = from_value(manifest.clone())?; let id = manifest.id.clone(); let mut s9pk: S9pk<_> = S9pk::new_with_manifest(archive, None, manifest); - let s9pk_compat_key = ctx.account.read().await.developer_key.clone(); + let s9pk_compat_key = ctx.account.peek(|a| a.developer_key.clone()); s9pk.as_archive_mut() .set_signer(s9pk_compat_key, SIG_CONTEXT); s9pk.serialize(&mut tmp_file, true).await?; diff --git a/core/startos/src/version/v0_4_0_alpha_10.rs b/core/startos/src/version/v0_4_0_alpha_10.rs index ece6fcefc..2fb3f3e61 100644 --- a/core/startos/src/version/v0_4_0_alpha_10.rs +++ b/core/startos/src/version/v0_4_0_alpha_10.rs @@ -31,7 +31,7 @@ impl VersionT for Version { fn compat(self) -> &'static VersionRange { &V0_3_0_COMPAT } - #[instrument] + #[instrument(skip_all)] fn up(self, db: &mut Value, _: Self::PreUpRes) -> Result { let default_gateway = db["public"]["serverInfo"]["network"]["networkInterfaces"] .as_object() diff --git a/core/startos/src/version/v0_4_0_alpha_11.rs b/core/startos/src/version/v0_4_0_alpha_11.rs index 9f59f478a..ad078f63b 100644 --- a/core/startos/src/version/v0_4_0_alpha_11.rs +++ b/core/startos/src/version/v0_4_0_alpha_11.rs @@ -1,7 +1,7 @@ use exver::{PreReleaseSegment, VersionRange}; use super::v0_3_5::V0_3_0_COMPAT; -use super::{v0_4_0_alpha_10, VersionT}; +use super::{VersionT, v0_4_0_alpha_10}; use crate::prelude::*; lazy_static::lazy_static! { @@ -27,7 +27,7 @@ impl VersionT for Version { fn compat(self) -> &'static VersionRange { &V0_3_0_COMPAT } - #[instrument] + #[instrument(skip_all)] fn up(self, db: &mut Value, _: Self::PreUpRes) -> Result { Ok(Value::Null) } diff --git a/core/startos/src/version/v0_4_0_alpha_12.rs b/core/startos/src/version/v0_4_0_alpha_12.rs new file mode 100644 index 000000000..95b210ce9 --- /dev/null +++ b/core/startos/src/version/v0_4_0_alpha_12.rs @@ -0,0 +1,85 @@ +use std::collections::BTreeSet; + +use exver::{PreReleaseSegment, VersionRange}; +use imbl_value::InternedString; + +use super::v0_3_5::V0_3_0_COMPAT; +use super::{VersionT, v0_4_0_alpha_11}; +use crate::net::tor::TorSecretKey; +use crate::prelude::*; + +lazy_static::lazy_static! { + static ref V0_4_0_alpha_12: exver::Version = exver::Version::new( + [0, 4, 0], + [PreReleaseSegment::String("alpha".into()), 12.into()] + ); +} + +#[derive(Clone, Copy, Debug, Default)] +pub struct Version; + +impl VersionT for Version { + type Previous = v0_4_0_alpha_11::Version; + type PreUpRes = (); + + async fn pre_up(self) -> Result { + Ok(()) + } + fn semver(self) -> exver::Version { + V0_4_0_alpha_12.clone() + } + fn compat(self) -> &'static VersionRange { + &V0_3_0_COMPAT + } + #[instrument(skip_all)] + fn up(self, db: &mut Value, _: Self::PreUpRes) -> Result { + let mut err = None; + let onion_store = db["private"]["keyStore"]["onion"] + .as_object_mut() + .or_not_found("private.keyStore.onion")?; + onion_store.retain(|o, v| match from_value::(v.clone()) { + Ok(k) => k.is_valid() && &InternedString::from_display(&k.onion_address()) == o, + Err(e) => { + err = Some(e); + true + } + }); + if let Some(e) = err { + return Err(e); + } + let allowed_addresses = onion_store.keys().cloned().collect::>(); + let fix_host = |host: &mut Value| { + Ok::<_, Error>( + host["onions"] + .as_array_mut() + .or_not_found("host.onions")? + .retain(|addr| { + addr.as_str() + .map(|s| allowed_addresses.contains(s)) + .unwrap_or(false) + }), + ) + }; + for (_, pde) in db["public"]["packageData"] + .as_object_mut() + .or_not_found("public.packageData")? + .iter_mut() + { + for (_, host) in pde["hosts"] + .as_object_mut() + .or_not_found("public.packageData[].hosts")? + .iter_mut() + { + fix_host(host)?; + } + } + fix_host(&mut db["public"]["serverInfo"]["network"]["host"])?; + + db["private"]["keyStore"]["localCerts"] = db["private"]["keyStore"]["local_certs"].clone(); + + Ok(Value::Null) + } + fn down(self, _db: &mut Value) -> Result<(), Error> { + Ok(()) + } +} diff --git a/core/startos/src/version/v0_4_0_alpha_4.rs b/core/startos/src/version/v0_4_0_alpha_4.rs index ffc83fe65..55eea5115 100644 --- a/core/startos/src/version/v0_4_0_alpha_4.rs +++ b/core/startos/src/version/v0_4_0_alpha_4.rs @@ -29,7 +29,7 @@ impl VersionT for Version { fn compat(self) -> &'static VersionRange { &V0_3_0_COMPAT } - #[instrument] + #[instrument(skip_all)] fn up(self, db: &mut Value, _: Self::PreUpRes) -> Result { db["public"]["serverInfo"] .as_object_mut() diff --git a/core/startos/src/version/v0_4_0_alpha_5.rs b/core/startos/src/version/v0_4_0_alpha_5.rs index 4ff950e5e..a2d006ff3 100644 --- a/core/startos/src/version/v0_4_0_alpha_5.rs +++ b/core/startos/src/version/v0_4_0_alpha_5.rs @@ -27,7 +27,7 @@ impl VersionT for Version { fn compat(self) -> &'static VersionRange { &V0_3_0_COMPAT } - #[instrument] + #[instrument(skip_all)] fn up(self, _db: &mut Value, _: Self::PreUpRes) -> Result { Ok(Value::Null) } diff --git a/core/startos/src/version/v0_4_0_alpha_6.rs b/core/startos/src/version/v0_4_0_alpha_6.rs index d75aceb19..e4fb566fb 100644 --- a/core/startos/src/version/v0_4_0_alpha_6.rs +++ b/core/startos/src/version/v0_4_0_alpha_6.rs @@ -27,7 +27,7 @@ impl VersionT for Version { fn compat(self) -> &'static VersionRange { &V0_3_0_COMPAT } - #[instrument] + #[instrument(skip_all)] fn up(self, db: &mut Value, _: Self::PreUpRes) -> Result { let ui = db["public"]["ui"] .as_object_mut() diff --git a/core/startos/src/version/v0_4_0_alpha_7.rs b/core/startos/src/version/v0_4_0_alpha_7.rs index bd8a226e1..3cdf12694 100644 --- a/core/startos/src/version/v0_4_0_alpha_7.rs +++ b/core/startos/src/version/v0_4_0_alpha_7.rs @@ -27,7 +27,7 @@ impl VersionT for Version { fn compat(self) -> &'static VersionRange { &V0_3_0_COMPAT } - #[instrument] + #[instrument(skip_all)] fn up(self, _db: &mut Value, _: Self::PreUpRes) -> Result { Ok(Value::Null) } diff --git a/core/startos/src/version/v0_4_0_alpha_8.rs b/core/startos/src/version/v0_4_0_alpha_8.rs index fa2c87a0a..0e92ba544 100644 --- a/core/startos/src/version/v0_4_0_alpha_8.rs +++ b/core/startos/src/version/v0_4_0_alpha_8.rs @@ -27,7 +27,7 @@ impl VersionT for Version { fn compat(self) -> &'static VersionRange { &V0_3_0_COMPAT } - #[instrument] + #[instrument(skip_all)] fn up(self, _db: &mut Value, _: Self::PreUpRes) -> Result { Ok(Value::Null) } diff --git a/core/startos/src/version/v0_4_0_alpha_9.rs b/core/startos/src/version/v0_4_0_alpha_9.rs index ffb5ad5be..e23b561a5 100644 --- a/core/startos/src/version/v0_4_0_alpha_9.rs +++ b/core/startos/src/version/v0_4_0_alpha_9.rs @@ -38,7 +38,7 @@ impl VersionT for Version { fn compat(self) -> &'static VersionRange { &V0_3_0_COMPAT } - #[instrument] + #[instrument(skip_all)] fn up(self, db: &mut Value, _: Self::PreUpRes) -> Result { let mut res = InOMap::new(); let todos = db diff --git a/core/startos/registry.service b/core/startos/start-registryd.service similarity index 85% rename from core/startos/registry.service rename to core/startos/start-registryd.service index 63941a25e..e8e6390ba 100644 --- a/core/startos/registry.service +++ b/core/startos/start-registryd.service @@ -4,7 +4,7 @@ Description=StartOS Registry [Service] Type=simple Environment=RUST_LOG=startos=debug,patch_db=warn -ExecStart=/usr/local/bin/registry +ExecStart=/usr/bin/start-registryd Restart=always RestartSec=3 ManagedOOMPreference=avoid diff --git a/core/startos/start-tunneld.service b/core/startos/start-tunneld.service new file mode 100644 index 000000000..b0d0a2043 --- /dev/null +++ b/core/startos/start-tunneld.service @@ -0,0 +1,13 @@ +[Unit] +Description=StartTunnel + +[Service] +Type=simple +Environment=RUST_LOG=startos=debug,patch_db=warn +ExecStart=/usr/bin/start-tunneld +Restart=always +RestartSec=3 +ManagedOOMPreference=avoid + +[Install] +WantedBy=multi-user.target diff --git a/debian/start-registry/postinst b/debian/start-registry/postinst new file mode 100755 index 000000000..9994e3fe5 --- /dev/null +++ b/debian/start-registry/postinst @@ -0,0 +1,9 @@ +#!/bin/sh +set -e + +SYSTEMCTL=systemctl +if [ -n "$DPKG_MAINTSCRIPT_PACKAGE" ]; then + SYSTEMCTL=deb-systemd-helper +fi + +$SYSTEMCTL enable start-registryd.service diff --git a/debian/start-tunnel/postinst b/debian/start-tunnel/postinst new file mode 100755 index 000000000..a4b70bc89 --- /dev/null +++ b/debian/start-tunnel/postinst @@ -0,0 +1,10 @@ +#!/bin/sh +set -e + +SYSTEMCTL=systemctl +if [ -n "$DPKG_MAINTSCRIPT_PACKAGE" ]; then + SYSTEMCTL=deb-systemd-helper +fi + +$SYSTEMCTL enable start-tunneld.service +$SYSTEMCTL restart start-tunneld.service \ No newline at end of file diff --git a/debian/postinst b/debian/startos/postinst similarity index 92% rename from debian/postinst rename to debian/startos/postinst index a8d4ee729..cca71d3e8 100755 --- a/debian/postinst +++ b/debian/startos/postinst @@ -114,16 +114,6 @@ sed -i '/\(^\|#\)RootDistanceMaxSec=/c\RootDistanceMaxSec=10' /etc/systemd/times mkdir -p /etc/nginx/ssl -cat << EOF > /etc/tor/torrc -SocksPort 0.0.0.0:9050 -SocksPolicy accept 127.0.0.1 -SocksPolicy accept 172.18.0.0/16 -SocksPolicy accept 10.0.3.0/24 -SocksPolicy reject * -ControlPort 9051 -CookieAuthentication 1 -EOF - rm -rf /var/lib/tor/* ln -sf /usr/lib/startos/scripts/chroot-and-upgrade /usr/bin/chroot-and-upgrade ln -sf /usr/lib/startos/scripts/tor-check /usr/bin/tor-check @@ -132,11 +122,7 @@ ln -sf /usr/lib/startos/scripts/wireguard-vps-proxy-setup /usr/bin/wireguard-vps echo "fs.inotify.max_user_watches=1048576" > /etc/sysctl.d/97-startos.conf -# Old pi was set with this locale, because of pg we are now stuck with including that locale -locale-gen en_GB en_GB.UTF-8 -echo "locales locales/locales_to_be_generated multiselect en_GB.UTF-8 UTF-8" | debconf-set-selections -update-locale LANGUAGE -rm -f "/etc/locale.gen" +locale-gen en_US.UTF-8 dpkg-reconfigure --frontend noninteractive locales if ! getent group | grep '^startos:'; then diff --git a/dpkg-build.sh b/dpkg-build.sh index e8ffdb0ac..e9a539d10 100755 --- a/dpkg-build.sh +++ b/dpkg-build.sh @@ -4,8 +4,9 @@ set -e cd "$(dirname "${BASH_SOURCE[0]}")" -BASENAME=$(./basename.sh) -VERSION=$(cat ./VERSION.txt) +PROJECT=${PROJECT:-"startos"} +BASENAME=${BASENAME:-"$(./basename.sh)"} +VERSION=${VERSION:-$(cat ./VERSION.txt)} if [ "$PLATFORM" = "x86_64" ] || [ "$PLATFORM" = "x86_64-nonfree" ]; then DEB_ARCH=amd64 elif [ "$PLATFORM" = "aarch64" ] || [ "$PLATFORM" = "aarch64-nonfree" ] || [ "$PLATFORM" = "raspberrypi" ]; then @@ -17,14 +18,34 @@ fi rm -rf dpkg-workdir/$BASENAME mkdir -p dpkg-workdir/$BASENAME -make install DESTDIR=dpkg-workdir/$BASENAME +if [ "${PROJECT}" = "startos" ]; then + INSTALL_TARGET="install" +else + INSTALL_TARGET="install-${PROJECT#start-}" +fi +make "${INSTALL_TARGET}" DESTDIR=dpkg-workdir/$BASENAME -DEPENDS=$(cat dpkg-workdir/$BASENAME/usr/lib/startos/depends | tr $'\n' ',' | sed 's/,,\+/,/g' | sed 's/,$//') -CONFLICTS=$(cat dpkg-workdir/$BASENAME/usr/lib/startos/conflicts | tr $'\n' ',' | sed 's/,,\+/,/g' | sed 's/,$//') +if [ -f dpkg-workdir/$BASENAME/usr/lib/$PROJECT/depends ]; then + if [ -n "$DEPENDS" ]; then + DEPENDS="$DEPENDS," + fi + DEPENDS="${DEPENDS}$(cat dpkg-workdir/$BASENAME/usr/lib/$PROJECT/depends | tr $'\n' ',' | sed 's/,,\+/,/g' | sed 's/,$//')" +fi +if [ -f dpkg-workdir/$BASENAME/usr/lib/$PROJECT/conflicts ]; then + if [ -n "$CONFLICTS" ]; then + CONFLICTS="$CONFLICTS," + fi + CONFLICTS="${CONFLICTS}$(cat dpkg-workdir/$BASENAME/usr/lib/$PROJECT/conflicts | tr $'\n' ',' | sed 's/,,\+/,/g' | sed 's/,$//')" +fi +CONFLICTS=${CONFLICTS:-"$(cat dpkg-workdir/$BASENAME/usr/lib/startos/conflicts | tr $'\n' ',' | sed 's/,,\+/,/g' | sed 's/,$//')"} -cp -r debian dpkg-workdir/$BASENAME/DEBIAN +if [ -d debian/${PROJECT} ]; then + cp -r debian/${PROJECT} dpkg-workdir/$BASENAME/DEBIAN +else + mkdir -p dpkg-workdir/$BASENAME/DEBIAN +fi cat > dpkg-workdir/$BASENAME/DEBIAN/control << EOF -Package: startos +Package: ${PROJECT} Version: ${VERSION} Section: unknown Priority: required diff --git a/image-recipe/Dockerfile b/image-recipe/Dockerfile new file mode 100644 index 000000000..c53627214 --- /dev/null +++ b/image-recipe/Dockerfile @@ -0,0 +1,35 @@ +ARG SUITE=trixie + +FROM debian:${SUITE} + +ENV DEBIAN_FRONTEND=noninteractive +RUN apt-get update && \ + apt-get install -yq \ + live-build \ + procps \ + binfmt-support \ + qemu-utils \ + qemu-user-static \ + xorriso \ + isolinux \ + ca-certificates \ + curl \ + wget \ + gpg \ + git \ + fdisk \ + dosfstools \ + e2fsprogs \ + squashfs-tools \ + rsync \ + b3sum \ + dpkg-dev + + +COPY binary_grub-efi.patch /root/binary_grub-efi.patch +RUN patch /usr/lib/live/build/binary_grub-efi < /root/binary_grub-efi.patch && rm /root/binary_grub-efi.patch + +RUN echo 'retry_connrefused = on' > /etc/wgetrc && \ + echo 'tries = 100' >> /etc/wgetrc + +WORKDIR /root \ No newline at end of file diff --git a/image-recipe/binary_grub-efi.patch b/image-recipe/binary_grub-efi.patch new file mode 100644 index 000000000..e0c5af2eb --- /dev/null +++ b/image-recipe/binary_grub-efi.patch @@ -0,0 +1,47 @@ +--- /usr/lib/live/build/binary_grub-efi 2024-05-25 05:22:52.000000000 -0600 ++++ binary_grub-efi 2025-10-16 13:04:32.338740922 -0600 +@@ -54,6 +54,8 @@ + armhf) + Check_package chroot /usr/lib/grub/arm-efi/configfile.mod grub-efi-arm-bin + ;; ++ riscv64) ++ Check_package chroot /usr/lib/grub/riscv64-efi/configfile.mod grub-efi-riscv64-bin + esac + Check_package chroot /usr/bin/grub-mkimage grub-common + Check_package chroot /usr/bin/mcopy mtools +@@ -136,7 +138,7 @@ + esac + + # Cleanup files that we generate +-rm -rf binary/boot/efi.img binary/boot/grub/i386-efi/ binary/boot/grub/x86_64-efi binary/boot/grub/arm64-efi binary/boot/grub/arm-efi ++rm -rf binary/boot/efi.img binary/boot/grub/i386-efi/ binary/boot/grub/x86_64-efi binary/boot/grub/arm64-efi binary/boot/grub/arm-efi binary/boot/grub/riscv64-efi + + # This is workaround till both efi-image and grub-cpmodules are put into a binary package + case "${LB_BUILD_WITH_CHROOT}" in +@@ -243,6 +245,10 @@ + gen_efi_boot_img "arm-efi" "arm" "debian-live/arm" + PATH="\${PRE_EFI_IMAGE_PATH}" + ;; ++ riscv64) ++ gen_efi_boot_img "riscv64-efi" "riscv64" "debian-live/riscv64" ++ PATH="\${PRE_EFI_IMAGE_PATH}" ++ ;; + esac + + +@@ -324,6 +330,7 @@ + rm -f chroot/grub-efi-temp/bootnetx64.efi + rm -f chroot/grub-efi-temp/bootnetaa64.efi + rm -f chroot/grub-efi-temp/bootnetarm.efi ++rm -f chroot/grub-efi-temp/bootnetriscv64.efi + + mkdir -p binary + cp -a chroot/grub-efi-temp/* binary/ +@@ -331,6 +338,7 @@ + rm -rf chroot/grub-efi-temp-i386-efi + rm -rf chroot/grub-efi-temp-arm64-efi + rm -rf chroot/grub-efi-temp-arm-efi ++rm -rf chroot/grub-efi-temp-riscv64-efi + rm -rf chroot/grub-efi-temp-cfg + rm -rf chroot/grub-efi-temp + diff --git a/image-recipe/build.sh b/image-recipe/build.sh index abbb71127..179ca779f 100755 --- a/image-recipe/build.sh +++ b/image-recipe/build.sh @@ -1,39 +1,59 @@ #!/bin/bash set -e -MAX_IMG_SECTORS=7217792 # 4GB +MAX_IMG_LEN=$((4 * 1024 * 1024 * 1024)) # 4GB echo "==== StartOS Image Build ====" echo "Building for architecture: $IB_TARGET_ARCH" -base_dir="$(dirname "$(readlink -f "$0")")" +SOURCE_DIR="$(realpath $(dirname "${BASH_SOURCE[0]}"))" + +base_dir="$(pwd -P)" prep_results_dir="$base_dir/images-prep" -if systemd-detect-virt -qc; then - RESULTS_DIR="/srv/artifacts" -else - RESULTS_DIR="$base_dir/results" -fi +RESULTS_DIR="$base_dir/results" echo "Saving results in: $RESULTS_DIR" +DEB_PATH="$base_dir/$1" + +VERSION="$(dpkg-deb --fsys-tarfile $DEB_PATH | tar --to-stdout -xvf - ./usr/lib/startos/VERSION.txt)" +GIT_HASH="$(dpkg-deb --fsys-tarfile $DEB_PATH | tar --to-stdout -xvf - ./usr/lib/startos/GIT_HASH.txt)" +if [[ "$GIT_HASH" =~ ^@ ]]; then + GIT_HASH="unknown" +else + GIT_HASH="$(echo -n "$GIT_HASH" | head -c 7)" +fi +IB_OS_ENV="$(dpkg-deb --fsys-tarfile $DEB_PATH | tar --to-stdout -xvf - ./usr/lib/startos/ENVIRONMENT.txt)" +IB_TARGET_PLATFORM="$(dpkg-deb --fsys-tarfile $DEB_PATH | tar --to-stdout -xvf - ./usr/lib/startos/PLATFORM.txt)" + +VERSION_FULL="${VERSION}-${GIT_HASH}" +if [ -n "$IB_OS_ENV" ]; then + VERSION_FULL="$VERSION_FULL~${IB_OS_ENV}" +fi + IMAGE_BASENAME=startos-${VERSION_FULL}_${IB_TARGET_PLATFORM} -QEMU_ARCH=${IB_TARGET_ARCH} -BOOTLOADERS=grub-efi,syslinux -if [ "$QEMU_ARCH" = 'amd64' ]; then +BOOTLOADERS=grub-efi +if [ "$IB_TARGET_PLATFORM" = "x86_64" ] || [ "$IB_TARGET_PLATFORM" = "x86_64-nonfree" ]; then + IB_TARGET_ARCH=amd64 QEMU_ARCH=x86_64 -elif [ "$QEMU_ARCH" = 'arm64' ]; then + BOOTLOADERS=grub-efi,syslinux +elif [ "$IB_TARGET_PLATFORM" = "aarch64" ] || [ "$IB_TARGET_PLATFORM" = "aarch64-nonfree" ] || [ "$IB_TARGET_PLATFORM" = "raspberrypi" ] || [ "$IB_TARGET_PLATFORM" = "rockchip64" ]; then + IB_TARGET_ARCH=arm64 QEMU_ARCH=aarch64 - BOOTLOADERS=grub-efi +elif [ "$IB_TARGET_PLATFORM" = "riscv64" ]; then + IB_TARGET_ARCH=riscv64 + QEMU_ARCH=riscv64 +else + IB_TARGET_ARCH="$IB_TARGET_PLATFORM" + QEMU_ARCH="$IB_TARGET_PLATFORM" fi -# TODO: remove when util-linux is released at v2.39 -cd $base_dir -git clone --depth=1 --branch=v2.39.3 https://github.com/util-linux/util-linux.git -cd util-linux -./autogen.sh -CC=$QEMU_ARCH-linux-gnu-gcc ./configure --host=$QEMU_ARCH-linux-gnu --disable-all-programs --enable-mount --enable-libmount --enable-libblkid --enable-libuuid --enable-static-programs -CC=$QEMU_ARCH-linux-gnu-gcc make -j mount.static +QEMU_ARGS=() +if [ "$QEMU_ARCH" != $(uname -m) ]; then + QEMU_ARGS+=(--bootstrap-qemu-arch ${IB_TARGET_ARCH}) + QEMU_ARGS+=(--bootstrap-qemu-static /usr/bin/qemu-${QEMU_ARCH}-static) +fi mkdir -p $prep_results_dir @@ -52,7 +72,7 @@ ARCHIVE_AREAS="main contrib" if [ "$NON_FREE" = 1 ]; then if [ "$IB_SUITE" = "bullseye" ]; then ARCHIVE_AREAS="$ARCHIVE_AREAS non-free" - elif [ "$IB_SUITE" = "bookworm" ]; then + else ARCHIVE_AREAS="$ARCHIVE_AREAS non-free-firmware" fi fi @@ -61,7 +81,8 @@ PLATFORM_CONFIG_EXTRAS=() if [ "${IB_TARGET_PLATFORM}" = "raspberrypi" ]; then PLATFORM_CONFIG_EXTRAS+=( --firmware-binary false ) PLATFORM_CONFIG_EXTRAS+=( --firmware-chroot false ) - PLATFORM_CONFIG_EXTRAS+=( --linux-packages linux-image-6.12.47+rpt ) + RPI_KERNEL_VERSION=6.12.47+rpt + PLATFORM_CONFIG_EXTRAS+=( --linux-packages linux-image-$RPI_KERNEL_VERSION ) PLATFORM_CONFIG_EXTRAS+=( --linux-flavours "rpi-v8 rpi-2712" ) elif [ "${IB_TARGET_PLATFORM}" = "rockchip64" ]; then PLATFORM_CONFIG_EXTRAS+=( --linux-flavours rockchip64 ) @@ -80,27 +101,21 @@ lb config \ --backports true \ --bootappend-live "boot=live noautologin" \ --bootloaders $BOOTLOADERS \ + --cache false \ --mirror-bootstrap "https://deb.debian.org/debian/" \ --mirror-chroot "https://deb.debian.org/debian/" \ --mirror-chroot-security "https://security.debian.org/debian-security" \ -d ${IB_SUITE} \ -a ${IB_TARGET_ARCH} \ - --bootstrap-qemu-arch ${IB_TARGET_ARCH} \ - --bootstrap-qemu-static /usr/bin/qemu-${QEMU_ARCH}-static \ + ${QEMU_ARGS[@]} \ --archive-areas "${ARCHIVE_AREAS}" \ ${PLATFORM_CONFIG_EXTRAS[@]} # Overlays -mkdir -p config/includes.chroot/deb -cp $base_dir/deb/${IMAGE_BASENAME}.deb config/includes.chroot/deb/ - -mkdir -p config/includes.chroot/usr/local/bin -cp $base_dir/util-linux/mount.static config/includes.chroot/usr/local/bin/mount.next - -if [ "${IB_TARGET_PLATFORM}" = "raspberrypi" ]; then - cp -r $base_dir/raspberrypi/squashfs/* config/includes.chroot/ -fi +mkdir -p config/packages.chroot/ +cp $RESULTS_DIR/$IMAGE_BASENAME.deb config/packages.chroot/ +dpkg-name config/packages.chroot/*.deb mkdir -p config/includes.chroot/etc echo start > config/includes.chroot/etc/hostname @@ -111,6 +126,13 @@ ff02::1 ip6-allnodes ff02::2 ip6-allrouters EOT +if [ "${IB_TARGET_PLATFORM}" = "raspberrypi" ]; then + mkdir -p config/includes.chroot + git clone --depth=1 --branch=stable https://github.com/raspberrypi/rpi-firmware.git config/includes.chroot/boot + rm -rf config/includes.chroot/boot/.git config/includes.chroot/boot/modules + rsync -rLp $SOURCE_DIR/raspberrypi/squashfs/ config/includes.chroot/ +fi + # Bootloaders rm -rf config/bootloaders @@ -130,10 +152,9 @@ prompt 0 timeout 50 EOF -rm config/bootloaders/syslinux_common/splash.svg -cp $base_dir/splash.png config/bootloaders/syslinux_common/splash.png -cp $base_dir/splash.png config/bootloaders/isolinux/splash.png -cp $base_dir/splash.png config/bootloaders/grub-pc/splash.png +cp $SOURCE_DIR/splash.png config/bootloaders/syslinux_common/splash.png +cp $SOURCE_DIR/splash.png config/bootloaders/isolinux/splash.png +cp $SOURCE_DIR/splash.png config/bootloaders/grub-pc/splash.png sed -i -e '2i set timeout=5' config/bootloaders/grub-pc/config.cfg @@ -146,16 +167,6 @@ if [ "${IB_TARGET_PLATFORM}" = "raspberrypi" ]; then echo "deb [arch=${IB_TARGET_ARCH} signed-by=/etc/apt/trusted.gpg.d/raspi.key.gpg] https://archive.raspberrypi.com/debian/ ${IB_SUITE} main" > config/archives/raspi.list fi -cat > config/archives/backports.pref <<- EOF -Package: linux-image-* -Pin: release n=${IB_SUITE}-backports -Pin-Priority: 500 - -Package: linux-base -Pin: release n=${IB_SUITE}-backports -Pin-Priority: 500 -EOF - if [ "${IB_TARGET_PLATFORM}" = "rockchip64" ]; then curl -fsSL https://apt.armbian.com/armbian.key | gpg --dearmor -o config/archives/armbian.key echo "deb https://apt.armbian.com/ ${IB_SUITE} main" > config/archives/armbian.list @@ -163,49 +174,32 @@ fi # Dependencies -## Base dependencies -dpkg-deb --fsys-tarfile $base_dir/deb/${IMAGE_BASENAME}.deb | tar --to-stdout -xvf - ./usr/lib/startos/depends > config/package-lists/startos-depends.list.chroot - ## Firmware if [ "$NON_FREE" = 1 ]; then echo 'firmware-iwlwifi firmware-misc-nonfree firmware-brcm80211 firmware-realtek firmware-atheros firmware-libertas firmware-amd-graphics' > config/package-lists/nonfree.list.chroot fi -if [ "${IB_TARGET_PLATFORM}" = "raspberrypi" ]; then - echo 'raspberrypi-net-mods raspberrypi-sys-mods raspi-config raspi-firmware raspi-gpio raspi-utils rpi-eeprom rpi-update rpi.gpio-common parted' > config/package-lists/bootloader.list.chroot -else - echo 'grub-efi grub2-common' > config/package-lists/bootloader.list.chroot -fi -if [ "${IB_TARGET_ARCH}" = "amd64" ] || [ "${IB_TARGET_ARCH}" = "i386" ]; then - echo 'grub-pc-bin' >> config/package-lists/bootloader.list.chroot -fi - cat > config/hooks/normal/9000-install-startos.hook.chroot << EOF #!/bin/bash set -e -apt-get install -y /deb/${IMAGE_BASENAME}.deb -rm -rf /deb +cp /etc/resolv.conf /etc/resolv.conf.bak -if [ "${IB_SUITE}" = bookworm ]; then - echo 'deb https://deb.debian.org/debian/ bullseye main' > /etc/apt/sources.list.d/bullseye.list +if [ "${IB_SUITE}" = trixie ] && [ "${IB_PLATFORM}" != riscv64 ]; then + echo 'deb https://deb.debian.org/debian/ bookworm main' > /etc/apt/sources.list.d/bookworm.list apt-get update - apt-get install -y postgresql-13 - rm /etc/apt/sources.list.d/bullseye.list + apt-get install -y postgresql-15 + rm /etc/apt/sources.list.d/bookworm.list apt-get update + systemctl mask postgresql fi if [ "${IB_TARGET_PLATFORM}" = "raspberrypi" ]; then ln -sf /usr/bin/pi-beep /usr/local/bin/beep - SKIP_WARNING=1 SKIP_BOOTLOADER=1 SKIP_CHECK_PARTITION=1 WANT_64BIT=1 WANT_PI4=1 WANT_PI5=1 BOOT_PART=/boot rpi-update stable - for f in /usr/lib/modules/*; do - v=\${f#/usr/lib/modules/} - echo "Configuring raspi kernel '\$v'" - extract-ikconfig "/usr/lib/modules/\$v/kernel/kernel/configs.ko.xz" > /boot/config-\$v - done - mkinitramfs -c gzip -o /boot/initramfs8 6.12.47-v8+ - mkinitramfs -c gzip -o /boot/initramfs_2712 6.12.47-v8-16k+ + KERNEL_VERSION=${RPI_KERNEL_VERSION} sh /boot/config.sh > /boot/config.txt + mkinitramfs -c gzip -o initrd.img-${RPI_KERNEL_VERSION}-rpi-v8 ${RPI_KERNEL_VERSION}-rpi-v8 + mkinitramfs -c gzip -o initrd.img-${RPI_KERNEL_VERSION}-rpi-2712 ${RPI_KERNEL_VERSION}-rpi-2712 fi useradd --shell /bin/bash -G startos -m start9 @@ -231,8 +225,7 @@ lb chroot lb installer lb binary_chroot lb chroot_prep install all mode-apt-install-binary mode-archives-chroot -echo "nameserver 127.0.0.1" > chroot/chroot/etc/resolv.conf -echo "nameserver 1.1.1.1" >> chroot/chroot/etc/resolv.conf # Cloudflare DNS Fallback +mv chroot/chroot/etc/resolv.conf.bak chroot/chroot/etc/resolv.conf lb binary_rootfs cp $prep_results_dir/binary/live/filesystem.squashfs $RESULTS_DIR/$IMAGE_BASENAME.squashfs @@ -268,49 +261,38 @@ if [ "${IMAGE_TYPE}" = iso ]; then elif [ "${IMAGE_TYPE}" = img ]; then - function partition_for () { - if [[ "$1" =~ [0-9]+$ ]]; then - echo "$1p$2" - else - echo "$1$2" - fi - } + SECTOR_LEN=512 + BOOT_START=$((1024 * 1024)) # 1MiB + BOOT_LEN=$((512 * 1024 * 1024)) # 512MiB + BOOT_END=$((BOOT_START + BOOT_LEN - 1)) + ROOT_START=$((BOOT_END + 1)) + ROOT_LEN=$((MAX_IMG_LEN - ROOT_START)) + ROOT_END=$((MAX_IMG_LEN - 1)) - ROOT_PART_END=$MAX_IMG_SECTORS TARGET_NAME=$prep_results_dir/${IMAGE_BASENAME}.img - TARGET_SIZE=$[($ROOT_PART_END+1)*512] - truncate -s $TARGET_SIZE $TARGET_NAME - ( - echo o - echo x - echo i - echo "0xcb15ae4d" - echo r - echo n - echo p - echo 1 - echo 2048 - echo 526335 - echo t - echo c - echo n - echo p - echo 2 - echo 526336 - echo $ROOT_PART_END - echo a - echo 1 - echo w - ) | fdisk $TARGET_NAME - OUTPUT_DEVICE=$(losetup --show -fP $TARGET_NAME) - mkfs.ext4 `partition_for ${OUTPUT_DEVICE} 2` - mkfs.vfat `partition_for ${OUTPUT_DEVICE} 1` + truncate -s $MAX_IMG_LEN $TARGET_NAME + + sfdisk $TARGET_NAME <<-EOF + label: dos + label-id: 0xcb15ae4d + unit: sectors + sector-size: 512 + + ${TARGET_NAME}1 : start=$((BOOT_START / SECTOR_LEN)), size=$((BOOT_LEN / SECTOR_LEN)), type=c, bootable + ${TARGET_NAME}2 : start=$((ROOT_START / SECTOR_LEN)), size=$((ROOT_LEN / SECTOR_LEN)), type=83 + EOF + + BOOT_DEV=$(losetup --show -f --offset $BOOT_START --sizelimit $BOOT_LEN $TARGET_NAME) + ROOT_DEV=$(losetup --show -f --offset $ROOT_START --sizelimit $ROOT_LEN $TARGET_NAME) + + mkfs.vfat -F32 $BOOT_DEV + mkfs.ext4 $ROOT_DEV TMPDIR=$(mktemp -d) - mkdir -p $TMPDIR/boot $TMPDIR/root - mount `partition_for ${OUTPUT_DEVICE} 2` $TMPDIR/root - mount `partition_for ${OUTPUT_DEVICE} 1` $TMPDIR/boot + mkdir -p $TMPDIR/boot $TMPDIR/root + mount $ROOT_DEV $TMPDIR/root + mount $BOOT_DEV $TMPDIR/boot unsquashfs -n -f -d $TMPDIR $prep_results_dir/binary/live/filesystem.squashfs boot mkdir $TMPDIR/root/images $TMPDIR/root/config @@ -325,7 +307,7 @@ elif [ "${IMAGE_TYPE}" = img ]; then if [ "${IB_TARGET_PLATFORM}" = "raspberrypi" ]; then sed -i 's| boot=startos| boot=startos init=/usr/lib/startos/scripts/init_resize\.sh|' $TMPDIR/boot/cmdline.txt - rsync -a $base_dir/raspberrypi/img/ $TMPDIR/next/ + rsync -a $SOURCE_DIR/raspberrypi/img/ $TMPDIR/next/ fi umount $TMPDIR/next @@ -334,30 +316,33 @@ elif [ "${IMAGE_TYPE}" = img ]; then umount $TMPDIR/boot umount $TMPDIR/root - e2fsck -fy `partition_for ${OUTPUT_DEVICE} 2` - resize2fs -M `partition_for ${OUTPUT_DEVICE} 2` - BLOCK_COUNT=$(dumpe2fs -h `partition_for ${OUTPUT_DEVICE} 2` | awk '/^Block count:/ { print $3 }') - BLOCK_SIZE=$(dumpe2fs -h `partition_for ${OUTPUT_DEVICE} 2` | awk '/^Block size:/ { print $3 }') - SECTOR_LEN=$[$BLOCK_COUNT*$BLOCK_SIZE/512] + e2fsck -fy $ROOT_DEV + resize2fs -M $ROOT_DEV - losetup -d $OUTPUT_DEVICE + BLOCK_COUNT=$(dumpe2fs -h $ROOT_DEV | awk '/^Block count:/ { print $3 }') + BLOCK_SIZE=$(dumpe2fs -h $ROOT_DEV | awk '/^Block size:/ { print $3 }') + ROOT_LEN=$((BLOCK_COUNT * BLOCK_SIZE)) - ( - echo d - echo 2 - echo n - echo p - echo 2 - echo 526336 - echo +$SECTOR_LEN - echo w - ) | fdisk $TARGET_NAME + losetup -d $ROOT_DEV + losetup -d $BOOT_DEV - ROOT_PART_END=$[526336+$SECTOR_LEN] - TARGET_SIZE=$[($ROOT_PART_END+1)*512] + # Recreate partition 2 with the new size using sfdisk + sfdisk $TARGET_NAME <<-EOF + label: dos + label-id: 0xcb15ae4d + unit: sectors + sector-size: 512 + + ${TARGET_NAME}1 : start=$((BOOT_START / SECTOR_LEN)), size=$((BOOT_LEN / SECTOR_LEN)), type=c, bootable + ${TARGET_NAME}2 : start=$((ROOT_START / SECTOR_LEN)), size=$((ROOT_LEN / SECTOR_LEN)), type=83 + EOF + + TARGET_SIZE=$((ROOT_START + ROOT_LEN)) truncate -s $TARGET_SIZE $TARGET_NAME mv $TARGET_NAME $RESULTS_DIR/$IMAGE_BASENAME.img fi + +chown $IB_UID:$IB_UID $RESULTS_DIR/$IMAGE_BASENAME.* \ No newline at end of file diff --git a/image-recipe/prepare.sh b/image-recipe/prepare.sh deleted file mode 100755 index c31f6ada0..000000000 --- a/image-recipe/prepare.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/sh -set -e -set -x - -export DEBIAN_FRONTEND=noninteractive -apt-get install -yq \ - live-build \ - procps \ - systemd \ - binfmt-support \ - qemu-utils \ - qemu-user-static \ - qemu-system-x86 \ - qemu-system-aarch64 \ - xorriso \ - isolinux \ - ca-certificates \ - curl \ - gpg \ - fdisk \ - dosfstools \ - e2fsprogs \ - squashfs-tools \ - rsync \ - b3sum -# TODO: remove when util-linux is released at v2.39.3 -apt-get install -yq \ - git \ - build-essential \ - crossbuild-essential-arm64 \ - crossbuild-essential-amd64 \ - automake \ - autoconf \ - gettext \ - libtool \ - pkg-config \ - autopoint \ - bison \ No newline at end of file diff --git a/image-recipe/raspberrypi/squashfs/boot/config.sh b/image-recipe/raspberrypi/squashfs/boot/config.sh new file mode 100644 index 000000000..1c74bc1b2 --- /dev/null +++ b/image-recipe/raspberrypi/squashfs/boot/config.sh @@ -0,0 +1,46 @@ +#!/bin/sh + +cat << EOF + +# Enable audio (loads snd_bcm2835) +dtparam=audio=on + +# Automatically load overlays for detected cameras +camera_auto_detect=1 + +# Automatically load overlays for detected DSI displays +display_auto_detect=1 + +# Enable DRM VC4 V3D driver +dtoverlay=vc4-kms-v3d +max_framebuffers=2 + +# Run in 64-bit mode +arm_64bit=1 + +# Disable compensation for displays with overscan +disable_overscan=1 + +[cm4] +# Enable host mode on the 2711 built-in XHCI USB controller. +# This line should be removed if the legacy DWC2 controller is required +# (e.g. for USB device mode) or if USB support is not required. +otg_mode=1 + +[all] + +[pi4] +# Run as fast as firmware / board allows +arm_boost=1 +kernel=vmlinuz-${KERNEL_VERSION}-rpi-v8 +initramfs initrd.img-${KERNEL_VERSION}-rpi-v8 followkernel + +[pi5] +kernel=vmlinuz-${KERNEL_VERSION}-rpi-2712 +initramfs initrd.img-${KERNEL_VERSION}-rpi-2712 followkernel + +[all] +gpu_mem=16 +dtoverlay=pwm-2chan,disable-bt + +EOF \ No newline at end of file diff --git a/image-recipe/run-local-build.sh b/image-recipe/run-local-build.sh index e5cf7645c..307f065d0 100755 --- a/image-recipe/run-local-build.sh +++ b/image-recipe/run-local-build.sh @@ -1,85 +1,22 @@ #!/bin/bash set -e -DEB_PATH="$(realpath $1)" - cd "$(dirname "${BASH_SOURCE[0]}")"/.. BASEDIR="$(pwd -P)" -VERSION="$(dpkg-deb --fsys-tarfile $DEB_PATH | tar --to-stdout -xvf - ./usr/lib/startos/VERSION.txt)" -GIT_HASH="$(dpkg-deb --fsys-tarfile $DEB_PATH | tar --to-stdout -xvf - ./usr/lib/startos/GIT_HASH.txt)" -if [[ "$GIT_HASH" =~ ^@ ]]; then - GIT_HASH="unknown" -else - GIT_HASH="$(echo -n "$GIT_HASH" | head -c 7)" -fi -STARTOS_ENV="$(dpkg-deb --fsys-tarfile $DEB_PATH | tar --to-stdout -xvf - ./usr/lib/startos/ENVIRONMENT.txt)" -PLATFORM="$(dpkg-deb --fsys-tarfile $DEB_PATH | tar --to-stdout -xvf - ./usr/lib/startos/PLATFORM.txt)" +SUITE=trixie -if [ "$PLATFORM" = "x86_64" ] || [ "$PLATFORM" = "x86_64-nonfree" ]; then - ARCH=amd64 - QEMU_ARCH=x86_64 -elif [ "$PLATFORM" = "aarch64" ] || [ "$PLATFORM" = "aarch64-nonfree" ] || [ "$PLATFORM" = "raspberrypi" ] || [ "$PLATFORM" = "rockchip64" ]; then - ARCH=arm64 - QEMU_ARCH=aarch64 -else - ARCH="$PLATFORM" - QEMU_ARCH="$PLATFORM" +dockerfile_hash=$(sha256sum ${BASEDIR}/image-recipe/Dockerfile | head -c 7) + +docker_img_name="startos_build:${SUITE}-${dockerfile_hash}" + +if [ -z "$(docker images -q "${docker_img_name}")" ]; then + docker build --build-arg=SUITE=${SUITE} -t "${docker_img_name}" ./image-recipe fi -SUITE=bookworm - -debspawn list | grep $SUITE || debspawn create $SUITE - -VERSION_FULL="${VERSION}-${GIT_HASH}" -if [ -n "$STARTOS_ENV" ]; then - VERSION_FULL="$VERSION_FULL~${STARTOS_ENV}" -fi - -if [ -z "$DSNAME" ]; then - DSNAME="$SUITE" -fi - -if [ "$QEMU_ARCH" != "$(uname -m)" ]; then - sudo update-binfmts --import qemu-$QEMU_ARCH -fi - -imgbuild_fname="$(mktemp /tmp/exec-mkimage.XXXXXX)" -cat > $imgbuild_fname < - keys: Array -} +export type SignerInfo = { name: string } diff --git a/sdk/base/lib/osBindings/TestSmtpParams.ts b/sdk/base/lib/osBindings/TestSmtpParams.ts index 06b218a34..e2d175f36 100644 --- a/sdk/base/lib/osBindings/TestSmtpParams.ts +++ b/sdk/base/lib/osBindings/TestSmtpParams.ts @@ -6,5 +6,5 @@ export type TestSmtpParams = { from: string to: string login: string - password: string | null + password: string } diff --git a/sdk/base/lib/osBindings/tunnel/AnyVerifyingKey.ts b/sdk/base/lib/osBindings/tunnel/AnyVerifyingKey.ts new file mode 100644 index 000000000..58a45aaa7 --- /dev/null +++ b/sdk/base/lib/osBindings/tunnel/AnyVerifyingKey.ts @@ -0,0 +1,3 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type AnyVerifyingKey = string diff --git a/sdk/base/lib/osBindings/tunnel/Base64.ts b/sdk/base/lib/osBindings/tunnel/Base64.ts new file mode 100644 index 000000000..597227fc9 --- /dev/null +++ b/sdk/base/lib/osBindings/tunnel/Base64.ts @@ -0,0 +1,3 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type Base64 = string diff --git a/sdk/base/lib/osBindings/tunnel/Pem.ts b/sdk/base/lib/osBindings/tunnel/Pem.ts new file mode 100644 index 000000000..1ec1cd375 --- /dev/null +++ b/sdk/base/lib/osBindings/tunnel/Pem.ts @@ -0,0 +1,3 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type Pem = string diff --git a/sdk/base/lib/osBindings/tunnel/PortForwards.ts b/sdk/base/lib/osBindings/tunnel/PortForwards.ts new file mode 100644 index 000000000..aa9991452 --- /dev/null +++ b/sdk/base/lib/osBindings/tunnel/PortForwards.ts @@ -0,0 +1,3 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type PortForwards = { [key: string]: string } diff --git a/sdk/base/lib/osBindings/tunnel/Session.ts b/sdk/base/lib/osBindings/tunnel/Session.ts new file mode 100644 index 000000000..36ebd2766 --- /dev/null +++ b/sdk/base/lib/osBindings/tunnel/Session.ts @@ -0,0 +1,7 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type Session = { + loggedIn: string + lastActive: string + userAgent: string | null +} diff --git a/sdk/base/lib/osBindings/tunnel/Sessions.ts b/sdk/base/lib/osBindings/tunnel/Sessions.ts new file mode 100644 index 000000000..6a15449e2 --- /dev/null +++ b/sdk/base/lib/osBindings/tunnel/Sessions.ts @@ -0,0 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { Session } from "./Session" + +export type Sessions = { [key: string]: Session } diff --git a/sdk/base/lib/osBindings/tunnel/SignerInfo.ts b/sdk/base/lib/osBindings/tunnel/SignerInfo.ts new file mode 100644 index 000000000..76cbdafce --- /dev/null +++ b/sdk/base/lib/osBindings/tunnel/SignerInfo.ts @@ -0,0 +1,3 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type SignerInfo = { name: string } diff --git a/sdk/base/lib/osBindings/tunnel/TunnelCertData.ts b/sdk/base/lib/osBindings/tunnel/TunnelCertData.ts new file mode 100644 index 000000000..7a6aa0d13 --- /dev/null +++ b/sdk/base/lib/osBindings/tunnel/TunnelCertData.ts @@ -0,0 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { Pem } from "./Pem" + +export type TunnelCertData = { key: Pem; cert: Pem } diff --git a/sdk/base/lib/osBindings/tunnel/TunnelDatabase.ts b/sdk/base/lib/osBindings/tunnel/TunnelDatabase.ts new file mode 100644 index 000000000..813b4996f --- /dev/null +++ b/sdk/base/lib/osBindings/tunnel/TunnelDatabase.ts @@ -0,0 +1,17 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { AnyVerifyingKey } from "./AnyVerifyingKey" +import type { PortForwards } from "./PortForwards" +import type { Sessions } from "./Sessions" +import type { SignerInfo } from "./SignerInfo" +import type { WebserverInfo } from "./WebserverInfo" +import type { WgServer } from "./WgServer" + +export type TunnelDatabase = { + webserver: WebserverInfo + sessions: Sessions + password: string | null + authPubkeys: { [key: AnyVerifyingKey]: SignerInfo } + gateways: { [key: AnyVerifyingKey]: SignerInfo } + wg: WgServer + portForwards: PortForwards +} diff --git a/sdk/base/lib/osBindings/tunnel/WebserverInfo.ts b/sdk/base/lib/osBindings/tunnel/WebserverInfo.ts new file mode 100644 index 000000000..9eea3361f --- /dev/null +++ b/sdk/base/lib/osBindings/tunnel/WebserverInfo.ts @@ -0,0 +1,8 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { TunnelCertData } from "./TunnelCertData" + +export type WebserverInfo = { + enabled: boolean + listen: string | null + certificate: TunnelCertData | null +} diff --git a/sdk/base/lib/osBindings/tunnel/WgConfig.ts b/sdk/base/lib/osBindings/tunnel/WgConfig.ts new file mode 100644 index 000000000..441177578 --- /dev/null +++ b/sdk/base/lib/osBindings/tunnel/WgConfig.ts @@ -0,0 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { Base64 } from "./Base64" + +export type WgConfig = { name: string; key: Base64; psk: Base64 } diff --git a/sdk/base/lib/osBindings/tunnel/WgServer.ts b/sdk/base/lib/osBindings/tunnel/WgServer.ts new file mode 100644 index 000000000..b56e310bb --- /dev/null +++ b/sdk/base/lib/osBindings/tunnel/WgServer.ts @@ -0,0 +1,5 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { Base64 } from "./Base64" +import type { WgSubnetMap } from "./WgSubnetMap" + +export type WgServer = { port: number; key: Base64; subnets: WgSubnetMap } diff --git a/sdk/base/lib/osBindings/tunnel/WgSubnetClients.ts b/sdk/base/lib/osBindings/tunnel/WgSubnetClients.ts new file mode 100644 index 000000000..608b52b14 --- /dev/null +++ b/sdk/base/lib/osBindings/tunnel/WgSubnetClients.ts @@ -0,0 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { WgConfig } from "./WgConfig" + +export type WgSubnetClients = { [key: string]: WgConfig } diff --git a/sdk/base/lib/osBindings/tunnel/WgSubnetConfig.ts b/sdk/base/lib/osBindings/tunnel/WgSubnetConfig.ts new file mode 100644 index 000000000..adfd68110 --- /dev/null +++ b/sdk/base/lib/osBindings/tunnel/WgSubnetConfig.ts @@ -0,0 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { WgSubnetClients } from "./WgSubnetClients" + +export type WgSubnetConfig = { name: string; clients: WgSubnetClients } diff --git a/sdk/base/lib/osBindings/tunnel/WgSubnetMap.ts b/sdk/base/lib/osBindings/tunnel/WgSubnetMap.ts new file mode 100644 index 000000000..a38e09650 --- /dev/null +++ b/sdk/base/lib/osBindings/tunnel/WgSubnetMap.ts @@ -0,0 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { WgSubnetConfig } from "./WgSubnetConfig" + +export type WgSubnetMap = { [key: string]: WgSubnetConfig } diff --git a/sdk/base/lib/util/getServiceInterface.ts b/sdk/base/lib/util/getServiceInterface.ts index e38ad2828..8106843fa 100644 --- a/sdk/base/lib/util/getServiceInterface.ts +++ b/sdk/base/lib/util/getServiceInterface.ts @@ -168,12 +168,12 @@ export const addressHostToUrl = ( }${hostname}${excludePort ? "" : `:${port}`}${suffix}` } let url = null - if (hostname.hostname.sslPort !== null) { - url = fmt(sslScheme, hostname, hostname.hostname.sslPort) + if (hostname.hostname.port !== null) { + url = fmt(scheme, hostname, hostname.hostname.port) } let sslUrl = null - if (hostname.hostname.port !== null) { - sslUrl = fmt(scheme, hostname, hostname.hostname.port) + if (hostname.hostname.sslPort !== null) { + sslUrl = fmt(sslScheme, hostname, hostname.hostname.sslPort) } return { url, sslUrl } diff --git a/sdk/base/lib/util/ip.ts b/sdk/base/lib/util/ip.ts index a631b6b23..026bdd3cc 100644 --- a/sdk/base/lib/util/ip.ts +++ b/sdk/base/lib/util/ip.ts @@ -1,15 +1,19 @@ export class IpAddress { - readonly octets: number[] - constructor(readonly address: string) { + protected constructor( + readonly octets: number[], + readonly address: string, + ) {} + static parse(address: string): IpAddress { + let octets if (address.includes(":")) { - this.octets = new Array(16).fill(0) + octets = new Array(16).fill(0) const segs = address.split(":") let idx = 0 let octIdx = 0 while (segs[idx]) { const num = parseInt(segs[idx], 16) - this.octets[octIdx++] = num >> 8 - this.octets[octIdx++] = num & 255 + octets[octIdx++] = num >> 8 + octets[octIdx++] = num & 255 idx += 1 } const lastSegIdx = segs.length - 1 @@ -18,21 +22,46 @@ export class IpAddress { octIdx = 15 while (segs[idx]) { const num = parseInt(segs[idx], 16) - this.octets[octIdx--] = num & 255 - this.octets[octIdx--] = num >> 8 + octets[octIdx--] = num & 255 + octets[octIdx--] = num >> 8 idx -= 1 } } } else { - this.octets = address.split(".").map(Number) - if (this.octets.length !== 4) throw new Error("invalid ipv4 address") + octets = address.split(".").map(Number) + if (octets.length !== 4) throw new Error("invalid ipv4 address") } - if (this.octets.some((o) => o >= 256)) { + if (octets.some((o) => isNaN(o) || o > 255)) { throw new Error("invalid ip address") } + return new IpAddress(octets, address) } - static parse(address: string): IpAddress { - return new IpAddress(address) + static fromOctets(octets: number[]) { + if (octets.length == 4) { + if (octets.some((o) => o > 255)) { + throw new Error("invalid ip address") + } + return new IpAddress(octets, octets.join(".")) + } else if (octets.length == 16) { + if (octets.some((o) => o > 255)) { + throw new Error("invalid ip address") + } + let pre = octets.slice(0, 8) + while (pre[pre.length - 1] == 0) { + pre.pop() + } + let post = octets.slice(8) + while (post[0] == 0) { + post.unshift() + } + if (pre.length + post.length == 16) { + return new IpAddress(octets, octets.join(":")) + } else { + return new IpAddress(octets, pre.join(":") + "::" + post.join(":")) + } + } else { + throw new Error("invalid ip address") + } } isIpv4(): boolean { return this.octets.length === 4 @@ -43,20 +72,79 @@ export class IpAddress { isPublic(): boolean { return this.isIpv4() && !PRIVATE_IPV4_RANGES.some((r) => r.contains(this)) } + add(n: number): IpAddress { + let octets = [...this.octets] + n = Math.floor(n) + for (let i = octets.length - 1; i >= 0; i--) { + octets[i] += n + if (octets[i] > 255) { + n = octets[i] >> 8 + octets[i] &= 255 + } else { + break + } + } + if (octets[0] > 255) { + throw new Error("overflow incrementing ip") + } + return IpAddress.fromOctets(octets) + } + sub(n: number): IpAddress { + let octets = [...this.octets] + n = Math.floor(n) + for (let i = octets.length - 1; i >= 0; i--) { + octets[i] -= n + if (octets[i] < 0) { + n = Math.ceil(Math.abs(octets[i]) / 256) + octets[i] = ((octets[i] % 256) + 256) % 256 + } else { + break + } + } + if (octets[0] < 0) { + throw new Error("underflow decrementing ip") + } + return IpAddress.fromOctets(octets) + } + cmp(other: string | IpAddress): -1 | 0 | 1 { + if (typeof other === "string") other = IpAddress.parse(other) + const len = Math.max(this.octets.length, other.octets.length) + for (let i = 0; i < len; i++) { + const left = this.octets[i] || 0 + const right = other.octets[i] || 0 + if (left > right) { + return 1 + } else if (left < right) { + return -1 + } + } + return 0 + } } export class IpNet extends IpAddress { - readonly prefix - constructor(readonly ipnet: string) { - const [address, prefixStr] = ipnet.split("/", 2) - super(address) - this.prefix = Number(prefixStr) + private constructor( + octets: number[], + readonly prefix: number, + address: string, + readonly ipnet: string, + ) { + super(octets, address) + } + static fromIpPrefix(ip: IpAddress, prefix: number): IpNet { + if (prefix > ip.octets.length * 8) { + throw new Error("invalid prefix") + } + return new IpNet(ip.octets, prefix, ip.address, `${ip.address}/${prefix}`) } static parse(ipnet: string): IpNet { - return new IpNet(ipnet) + const [address, prefixStr] = ipnet.split("/", 2) + const ip = IpAddress.parse(address) + const prefix = Number(prefixStr) + return IpNet.fromIpPrefix(ip, prefix) } contains(address: string | IpAddress): boolean { - if (typeof address === "string") address = new IpAddress(address) + if (typeof address === "string") address = IpAddress.parse(address) if (this.octets.length !== address.octets.length) return false let prefix = this.prefix let idx = 0 @@ -68,18 +156,52 @@ export class IpNet extends IpAddress { prefix -= 8 } if (prefix === 0 || idx >= this.octets.length) return true - const mask = 255 << prefix + const mask = 255 ^ (255 >> prefix) return (this.octets[idx] & mask) === (address.octets[idx] & mask) } + zero(): IpAddress { + let octets: number[] = [] + let prefix = this.prefix + for (let idx = 0; idx < this.octets.length; idx++) { + if (prefix >= 8) { + octets[idx] = this.octets[idx] + prefix -= 8 + } else { + const mask = 255 ^ (255 >> prefix) + octets[idx] = this.octets[idx] & mask + prefix = 0 + } + } + + return IpAddress.fromOctets(octets) + } + broadcast(): IpAddress { + let octets: number[] = [] + let prefix = this.prefix + for (let idx = 0; idx < this.octets.length; idx++) { + if (prefix >= 8) { + octets[idx] = this.octets[idx] + prefix -= 8 + } else { + const mask = 255 >> prefix + octets[idx] = this.octets[idx] | mask + prefix = 0 + } + } + + return IpAddress.fromOctets(octets) + } } export const PRIVATE_IPV4_RANGES = [ - new IpNet("127.0.0.0/8"), - new IpNet("10.0.0.0/8"), - new IpNet("172.16.0.0/12"), - new IpNet("192.168.0.0/16"), + IpNet.parse("127.0.0.0/8"), + IpNet.parse("10.0.0.0/8"), + IpNet.parse("172.16.0.0/12"), + IpNet.parse("192.168.0.0/16"), ] -export const IPV6_LINK_LOCAL = new IpNet("fe80::/10") +export const IPV4_LOOPBACK = IpNet.parse("127.0.0.0/8") +export const IPV6_LOOPBACK = IpNet.parse("::1/128") +export const IPV6_LINK_LOCAL = IpNet.parse("fe80::/10") -export const CGNAT = new IpNet("100.64.0.0/10") +export const CGNAT = IpNet.parse("100.64.0.0/10") diff --git a/sdk/package/lib/StartSdk.ts b/sdk/package/lib/StartSdk.ts index 41c069726..f5e9a41fa 100644 --- a/sdk/package/lib/StartSdk.ts +++ b/sdk/package/lib/StartSdk.ts @@ -61,7 +61,7 @@ import { } from "../../base/lib/inits" import { DropGenerator } from "../../base/lib/util/Drop" -export const OSVersion = testTypeVersion("0.4.0-alpha.11") +export const OSVersion = testTypeVersion("0.4.0-alpha.12") // prettier-ignore type AnyNeverCond = diff --git a/sdk/package/lib/util/SubContainer.ts b/sdk/package/lib/util/SubContainer.ts index 31a691baa..afa7cc14a 100644 --- a/sdk/package/lib/util/SubContainer.ts +++ b/sdk/package/lib/util/SubContainer.ts @@ -616,6 +616,7 @@ export class SubContainerRc< return this.subcontainer.guid } private destroyed = false + private destroying: Promise | null = null public constructor( private readonly subcontainer: SubContainerOwned, ) { @@ -695,14 +696,16 @@ export class SubContainerRc< get destroy() { return async () => { - if (!this.destroyed) { + if (!this.destroyed && !this.destroying) { const rcs = --this.subcontainer.rcs if (rcs <= 0) { - await this.subcontainer.destroy() + this.destroying = this.subcontainer.destroy() if (rcs < 0) console.error(new Error("UNREACHABLE: rcs < 0").stack) } - this.destroyed = true } + await this.destroying + this.destroyed = true + this.destroying = null return null } } diff --git a/sdk/package/lib/util/fileHelper.ts b/sdk/package/lib/util/fileHelper.ts index 25c4bc12e..1bf2766b9 100644 --- a/sdk/package/lib/util/fileHelper.ts +++ b/sdk/package/lib/util/fileHelper.ts @@ -573,23 +573,23 @@ export class FileHelper { /** * Create a File Helper for a .toml file */ - static toml( + static toml>( path: ToPath, - shape: Validator, + shape: Validator, A>, ): FileHelper - static toml( + static toml>( path: ToPath, shape: Validator, - transformers: Transformers, + transformers: Transformers, Transformed>, ): FileHelper - static toml( + static toml>( path: ToPath, shape: Validator, - transformers?: Transformers, + transformers?: Transformers, Transformed>, ) { - return FileHelper.rawTransformed( + return FileHelper.rawTransformed, Transformed>( path, - (inData) => TOML.stringify(inData), + (inData) => TOML.stringify(inData as TOML.JsonMap), (inString) => TOML.parse(inString), (data) => shape.unsafeCast(data), transformers, diff --git a/sdk/package/package-lock.json b/sdk/package/package-lock.json index 8b8f8b0ac..6f02a18fd 100644 --- a/sdk/package/package-lock.json +++ b/sdk/package/package-lock.json @@ -1,12 +1,12 @@ { "name": "@start9labs/start-sdk", - "version": "0.4.0-beta.41", + "version": "0.4.0-beta.42", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@start9labs/start-sdk", - "version": "0.4.0-beta.41", + "version": "0.4.0-beta.42", "license": "MIT", "dependencies": { "@iarna/toml": "^3.0.0", diff --git a/sdk/package/package.json b/sdk/package/package.json index 57ca30ffd..1c09a1f13 100644 --- a/sdk/package/package.json +++ b/sdk/package/package.json @@ -1,6 +1,6 @@ { "name": "@start9labs/start-sdk", - "version": "0.4.0-beta.41", + "version": "0.4.0-beta.42", "description": "Software development kit to facilitate packaging services for StartOS", "main": "./package/lib/index.js", "types": "./package/lib/index.d.ts", diff --git a/web/angular.json b/web/angular.json index a90d5c00a..862ea8cf1 100644 --- a/web/angular.json +++ b/web/angular.json @@ -334,6 +334,105 @@ } } }, + "start-tunnel": { + "projectType": "application", + "schematics": {}, + "root": "projects/start-tunnel", + "sourceRoot": "projects/start-tunnel/src", + "prefix": "app", + "architect": { + "build": { + "builder": "@angular/build:application", + "options": { + "outputPath": { + "base": "dist/raw/start-tunnel", + "browser": "" + }, + "index": "projects/start-tunnel/src/index.html", + "browser": "projects/start-tunnel/src/main.ts", + "polyfills": [], + "tsConfig": "projects/start-tunnel/tsconfig.json", + "inlineStyleLanguage": "scss", + "assets": [ + { + "glob": "**/*", + "input": "projects/shared/assets", + "output": "assets" + }, + { + "glob": "**/*", + "input": "node_modules/@taiga-ui/icons/src", + "output": "assets/taiga-ui/icons" + } + ], + "styles": [ + "node_modules/@taiga-ui/core/styles/taiga-ui-theme.less", + "node_modules/@taiga-ui/core/styles/taiga-ui-fonts.less", + "projects/shared/styles/shared.scss", + "projects/start-tunnel/src/styles.scss" + ], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kB", + "maximumError": "5MB" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "4kB", + "maximumError": "8kB" + } + ], + "outputHashing": "all" + }, + "development": { + "optimization": false, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + }, + "ci": { + "progress": false + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "builder": "@angular/build:dev-server", + "configurations": { + "production": { + "buildTarget": "start-tunnel:build:production" + }, + "development": { + "buildTarget": "start-tunnel:build:development" + } + }, + "defaultConfiguration": "development", + "options": { + "port": 8100 + } + }, + "extract-i18n": { + "builder": "@angular/build:extract-i18n", + "options": { + "buildTarget": "start-tunnel:build" + } + }, + "lint": { + "builder": "@angular-eslint/builder:lint", + "options": { + "lintFilePatterns": [ + "projects/start-tunnel/src/**/*.ts", + "projects/start-tunnel/src/**/*.html" + ] + } + } + } + }, "marketplace": { "projectType": "library", "root": "projects/marketplace", diff --git a/web/lint-staged.config.js b/web/lint-staged.config.js index de03fa870..e351c9ce0 100644 --- a/web/lint-staged.config.js +++ b/web/lint-staged.config.js @@ -6,4 +6,5 @@ module.exports = { 'projects/marketplace/**/*.ts': () => 'npm run check:marketplace', 'projects/install-wizard/**/*.ts': () => 'npm run check:install', 'projects/setup-wizard/**/*.ts': () => 'npm run check:setup', + 'projects/start-tunnel/**/*.ts': () => 'npm run check:tunnel', } diff --git a/web/package-lock.json b/web/package-lock.json index d3b9c7fab..e5198c0cb 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -1,42 +1,42 @@ { "name": "startos-ui", - "version": "0.4.0-alpha.11", + "version": "0.4.0-alpha.12", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "startos-ui", - "version": "0.4.0-alpha.11", + "version": "0.4.0-alpha.12", "license": "MIT", "dependencies": { - "@angular/animations": "^20.1.0", + "@angular/animations": "^20.3.0", "@angular/cdk": "^20.1.0", - "@angular/common": "^20.1.0", - "@angular/compiler": "^20.1.0", - "@angular/core": "^20.1.0", - "@angular/forms": "^20.1.0", - "@angular/platform-browser": "^20.1.0", + "@angular/common": "^20.3.0", + "@angular/compiler": "^20.3.0", + "@angular/core": "^20.3.0", + "@angular/forms": "^20.3.0", + "@angular/platform-browser": "^20.3.0", "@angular/platform-browser-dynamic": "^20.1.0", - "@angular/pwa": "^20.1.0", - "@angular/router": "^20.1.0", - "@angular/service-worker": "^20.1.0", + "@angular/pwa": "^20.3.0", + "@angular/router": "^20.3.0", + "@angular/service-worker": "^20.3.0", "@materia-ui/ngx-monaco-editor": "^6.0.0", "@noble/curves": "^1.4.0", "@noble/hashes": "^1.4.0", "@start9labs/argon2": "^0.3.0", "@start9labs/start-sdk": "file:../sdk/baseDist", - "@taiga-ui/addon-charts": "4.52.0", - "@taiga-ui/addon-commerce": "4.52.0", - "@taiga-ui/addon-mobile": "4.52.0", - "@taiga-ui/addon-table": "4.52.0", - "@taiga-ui/cdk": "4.52.0", - "@taiga-ui/core": "4.52.0", + "@taiga-ui/addon-charts": "4.55.0", + "@taiga-ui/addon-commerce": "4.55.0", + "@taiga-ui/addon-mobile": "4.55.0", + "@taiga-ui/addon-table": "4.55.0", + "@taiga-ui/cdk": "4.55.0", + "@taiga-ui/core": "4.55.0", "@taiga-ui/dompurify": "4.1.11", "@taiga-ui/event-plugins": "4.7.0", - "@taiga-ui/experimental": "4.52.0", - "@taiga-ui/icons": "4.52.0", - "@taiga-ui/kit": "4.52.0", - "@taiga-ui/layout": "4.52.0", + "@taiga-ui/experimental": "4.55.0", + "@taiga-ui/icons": "4.55.0", + "@taiga-ui/kit": "4.55.0", + "@taiga-ui/layout": "4.55.0", "@taiga-ui/polymorpheus": "4.9.0", "ansi-to-html": "^0.7.2", "base64-js": "^1.5.1", @@ -116,1586 +116,6 @@ "rxjs": ">=7.0.0" } }, - "../patch-db/client/node_modules/@babel/code-frame": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.27.1", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "../patch-db/client/node_modules/@babel/helper-validator-identifier": { - "version": "7.27.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "../patch-db/client/node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" - } - }, - "../patch-db/client/node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "../patch-db/client/node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "dev": true, - "license": "MIT" - }, - "../patch-db/client/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "../patch-db/client/node_modules/@tsconfig/node10": { - "version": "1.0.11", - "dev": true, - "license": "MIT" - }, - "../patch-db/client/node_modules/@tsconfig/node12": { - "version": "1.0.11", - "dev": true, - "license": "MIT" - }, - "../patch-db/client/node_modules/@tsconfig/node14": { - "version": "1.0.3", - "dev": true, - "license": "MIT" - }, - "../patch-db/client/node_modules/@tsconfig/node16": { - "version": "1.0.4", - "dev": true, - "license": "MIT" - }, - "../patch-db/client/node_modules/@types/node": { - "version": "22.15.19", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.21.0" - } - }, - "../patch-db/client/node_modules/@types/parse-json": { - "version": "4.0.2", - "dev": true, - "license": "MIT" - }, - "../patch-db/client/node_modules/@types/uuid": { - "version": "8.3.1", - "dev": true, - "license": "MIT" - }, - "../patch-db/client/node_modules/acorn": { - "version": "8.14.1", - "dev": true, - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "../patch-db/client/node_modules/acorn-walk": { - "version": "8.3.4", - "dev": true, - "license": "MIT", - "dependencies": { - "acorn": "^8.11.0" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "../patch-db/client/node_modules/ansi-escapes": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "type-fest": "^1.0.2" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "../patch-db/client/node_modules/ansi-regex": { - "version": "6.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "../patch-db/client/node_modules/ansi-styles": { - "version": "4.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "../patch-db/client/node_modules/arg": { - "version": "4.1.3", - "dev": true, - "license": "MIT" - }, - "../patch-db/client/node_modules/argparse": { - "version": "1.0.10", - "dev": true, - "license": "MIT", - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "../patch-db/client/node_modules/balanced-match": { - "version": "1.0.2", - "dev": true, - "license": "MIT" - }, - "../patch-db/client/node_modules/brace-expansion": { - "version": "1.1.11", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "../patch-db/client/node_modules/braces": { - "version": "3.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "../patch-db/client/node_modules/builtin-modules": { - "version": "1.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "../patch-db/client/node_modules/callsites": { - "version": "3.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "../patch-db/client/node_modules/chalk": { - "version": "4.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "../patch-db/client/node_modules/ci-info": { - "version": "2.0.0", - "dev": true, - "license": "MIT" - }, - "../patch-db/client/node_modules/cli-cursor": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "restore-cursor": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "../patch-db/client/node_modules/cli-truncate": { - "version": "3.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "slice-ansi": "^5.0.0", - "string-width": "^5.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "../patch-db/client/node_modules/color-convert": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "../patch-db/client/node_modules/color-name": { - "version": "1.1.4", - "dev": true, - "license": "MIT" - }, - "../patch-db/client/node_modules/colorette": { - "version": "2.0.20", - "dev": true, - "license": "MIT" - }, - "../patch-db/client/node_modules/commander": { - "version": "11.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=16" - } - }, - "../patch-db/client/node_modules/compare-versions": { - "version": "3.6.0", - "dev": true, - "license": "MIT" - }, - "../patch-db/client/node_modules/concat-map": { - "version": "0.0.1", - "dev": true, - "license": "MIT" - }, - "../patch-db/client/node_modules/cosmiconfig": { - "version": "7.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" - }, - "engines": { - "node": ">=10" - } - }, - "../patch-db/client/node_modules/create-require": { - "version": "1.1.1", - "dev": true, - "license": "MIT" - }, - "../patch-db/client/node_modules/cross-spawn": { - "version": "7.0.6", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "../patch-db/client/node_modules/debug": { - "version": "4.3.4", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "../patch-db/client/node_modules/diff": { - "version": "4.0.2", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, - "../patch-db/client/node_modules/eastasianwidth": { - "version": "0.2.0", - "dev": true, - "license": "MIT" - }, - "../patch-db/client/node_modules/emoji-regex": { - "version": "9.2.2", - "dev": true, - "license": "MIT" - }, - "../patch-db/client/node_modules/error-ex": { - "version": "1.3.2", - "dev": true, - "license": "MIT", - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "../patch-db/client/node_modules/escape-string-regexp": { - "version": "1.0.5", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, - "../patch-db/client/node_modules/esprima": { - "version": "4.0.1", - "dev": true, - "license": "BSD-2-Clause", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "../patch-db/client/node_modules/eventemitter3": { - "version": "5.0.1", - "dev": true, - "license": "MIT" - }, - "../patch-db/client/node_modules/execa": { - "version": "7.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.1", - "human-signals": "^4.3.0", - "is-stream": "^3.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^5.1.0", - "onetime": "^6.0.0", - "signal-exit": "^3.0.7", - "strip-final-newline": "^3.0.0" - }, - "engines": { - "node": "^14.18.0 || ^16.14.0 || >=18.0.0" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "../patch-db/client/node_modules/fill-range": { - "version": "7.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "../patch-db/client/node_modules/find-up": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "../patch-db/client/node_modules/find-versions": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "semver-regex": "^3.1.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "../patch-db/client/node_modules/fs.realpath": { - "version": "1.0.0", - "dev": true, - "license": "ISC" - }, - "../patch-db/client/node_modules/function-bind": { - "version": "1.1.2", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "../patch-db/client/node_modules/get-stream": { - "version": "6.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "../patch-db/client/node_modules/glob": { - "version": "7.2.3", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "../patch-db/client/node_modules/has-flag": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "../patch-db/client/node_modules/hasown": { - "version": "2.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "../patch-db/client/node_modules/human-signals": { - "version": "4.3.1", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=14.18.0" - } - }, - "../patch-db/client/node_modules/husky": { - "version": "4.3.8", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.0.0", - "ci-info": "^2.0.0", - "compare-versions": "^3.6.0", - "cosmiconfig": "^7.0.0", - "find-versions": "^4.0.0", - "opencollective-postinstall": "^2.0.2", - "pkg-dir": "^5.0.0", - "please-upgrade-node": "^3.2.0", - "slash": "^3.0.0", - "which-pm-runs": "^1.0.0" - }, - "bin": { - "husky-run": "bin/run.js", - "husky-upgrade": "lib/upgrader/bin.js" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/husky" - } - }, - "../patch-db/client/node_modules/import-fresh": { - "version": "3.3.1", - "dev": true, - "license": "MIT", - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "../patch-db/client/node_modules/inflight": { - "version": "1.0.6", - "dev": true, - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "../patch-db/client/node_modules/inherits": { - "version": "2.0.4", - "dev": true, - "license": "ISC" - }, - "../patch-db/client/node_modules/is-arrayish": { - "version": "0.2.1", - "dev": true, - "license": "MIT" - }, - "../patch-db/client/node_modules/is-core-module": { - "version": "2.16.1", - "dev": true, - "license": "MIT", - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "../patch-db/client/node_modules/is-fullwidth-code-point": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "../patch-db/client/node_modules/is-number": { - "version": "7.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "../patch-db/client/node_modules/is-stream": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "../patch-db/client/node_modules/isexe": { - "version": "2.0.0", - "dev": true, - "license": "ISC" - }, - "../patch-db/client/node_modules/js-tokens": { - "version": "4.0.0", - "dev": true, - "license": "MIT" - }, - "../patch-db/client/node_modules/js-yaml": { - "version": "3.14.1", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "../patch-db/client/node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "dev": true, - "license": "MIT" - }, - "../patch-db/client/node_modules/lilconfig": { - "version": "2.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "../patch-db/client/node_modules/lines-and-columns": { - "version": "1.2.4", - "dev": true, - "license": "MIT" - }, - "../patch-db/client/node_modules/lint-staged": { - "version": "13.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "5.3.0", - "commander": "11.0.0", - "debug": "4.3.4", - "execa": "7.2.0", - "lilconfig": "2.1.0", - "listr2": "6.6.1", - "micromatch": "4.0.5", - "pidtree": "0.6.0", - "string-argv": "0.3.2", - "yaml": "2.3.1" - }, - "bin": { - "lint-staged": "bin/lint-staged.js" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - }, - "funding": { - "url": "https://opencollective.com/lint-staged" - } - }, - "../patch-db/client/node_modules/lint-staged/node_modules/chalk": { - "version": "5.3.0", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "../patch-db/client/node_modules/lint-staged/node_modules/yaml": { - "version": "2.3.1", - "dev": true, - "license": "ISC", - "engines": { - "node": ">= 14" - } - }, - "../patch-db/client/node_modules/listr2": { - "version": "6.6.1", - "dev": true, - "license": "MIT", - "dependencies": { - "cli-truncate": "^3.1.0", - "colorette": "^2.0.20", - "eventemitter3": "^5.0.1", - "log-update": "^5.0.1", - "rfdc": "^1.3.0", - "wrap-ansi": "^8.1.0" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "enquirer": ">= 2.3.0 < 3" - }, - "peerDependenciesMeta": { - "enquirer": { - "optional": true - } - } - }, - "../patch-db/client/node_modules/locate-path": { - "version": "6.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "../patch-db/client/node_modules/log-update": { - "version": "5.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-escapes": "^5.0.0", - "cli-cursor": "^4.0.0", - "slice-ansi": "^5.0.0", - "strip-ansi": "^7.0.1", - "wrap-ansi": "^8.0.1" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "../patch-db/client/node_modules/make-error": { - "version": "1.3.6", - "dev": true, - "license": "ISC" - }, - "../patch-db/client/node_modules/merge-stream": { - "version": "2.0.0", - "dev": true, - "license": "MIT" - }, - "../patch-db/client/node_modules/micromatch": { - "version": "4.0.5", - "dev": true, - "license": "MIT", - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "../patch-db/client/node_modules/mimic-fn": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "../patch-db/client/node_modules/minimatch": { - "version": "3.1.2", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "../patch-db/client/node_modules/minimist": { - "version": "1.2.8", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "../patch-db/client/node_modules/mkdirp": { - "version": "0.5.6", - "dev": true, - "license": "MIT", - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "../patch-db/client/node_modules/ms": { - "version": "2.1.2", - "dev": true, - "license": "MIT" - }, - "../patch-db/client/node_modules/npm-run-path": { - "version": "5.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "../patch-db/client/node_modules/npm-run-path/node_modules/path-key": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "../patch-db/client/node_modules/once": { - "version": "1.4.0", - "dev": true, - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "../patch-db/client/node_modules/onetime": { - "version": "6.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-fn": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "../patch-db/client/node_modules/opencollective-postinstall": { - "version": "2.0.3", - "dev": true, - "license": "MIT", - "bin": { - "opencollective-postinstall": "index.js" - } - }, - "../patch-db/client/node_modules/p-limit": { - "version": "3.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "../patch-db/client/node_modules/p-locate": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "../patch-db/client/node_modules/parent-module": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "../patch-db/client/node_modules/parse-json": { - "version": "5.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "../patch-db/client/node_modules/path-exists": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "../patch-db/client/node_modules/path-is-absolute": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "../patch-db/client/node_modules/path-key": { - "version": "3.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "../patch-db/client/node_modules/path-parse": { - "version": "1.0.7", - "dev": true, - "license": "MIT" - }, - "../patch-db/client/node_modules/path-type": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "../patch-db/client/node_modules/picocolors": { - "version": "1.1.1", - "dev": true, - "license": "ISC" - }, - "../patch-db/client/node_modules/picomatch": { - "version": "2.3.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "../patch-db/client/node_modules/pidtree": { - "version": "0.6.0", - "dev": true, - "license": "MIT", - "bin": { - "pidtree": "bin/pidtree.js" - }, - "engines": { - "node": ">=0.10" - } - }, - "../patch-db/client/node_modules/pkg-dir": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "find-up": "^5.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "../patch-db/client/node_modules/please-upgrade-node": { - "version": "3.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "semver-compare": "^1.0.0" - } - }, - "../patch-db/client/node_modules/prettier": { - "version": "3.5.3", - "dev": true, - "license": "MIT", - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "../patch-db/client/node_modules/resolve": { - "version": "1.22.10", - "dev": true, - "license": "MIT", - "dependencies": { - "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" - } - }, - "../patch-db/client/node_modules/resolve-from": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "../patch-db/client/node_modules/restore-cursor": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "../patch-db/client/node_modules/restore-cursor/node_modules/mimic-fn": { - "version": "2.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "../patch-db/client/node_modules/restore-cursor/node_modules/onetime": { - "version": "5.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "../patch-db/client/node_modules/rfdc": { - "version": "1.4.1", - "dev": true, - "license": "MIT" - }, - "../patch-db/client/node_modules/rxjs": { - "version": "7.8.2", - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "tslib": "^2.1.0" - } - }, - "../patch-db/client/node_modules/semver": { - "version": "5.7.2", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver" - } - }, - "../patch-db/client/node_modules/semver-compare": { - "version": "1.0.0", - "dev": true, - "license": "MIT" - }, - "../patch-db/client/node_modules/semver-regex": { - "version": "3.1.4", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "../patch-db/client/node_modules/shebang-command": { - "version": "2.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "../patch-db/client/node_modules/shebang-regex": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "../patch-db/client/node_modules/signal-exit": { - "version": "3.0.7", - "dev": true, - "license": "ISC" - }, - "../patch-db/client/node_modules/slash": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "../patch-db/client/node_modules/slice-ansi": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.0.0", - "is-fullwidth-code-point": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "../patch-db/client/node_modules/slice-ansi/node_modules/ansi-styles": { - "version": "6.2.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "../patch-db/client/node_modules/sorted-btree": { - "version": "1.5.0", - "license": "MIT" - }, - "../patch-db/client/node_modules/sprintf-js": { - "version": "1.0.3", - "dev": true, - "license": "BSD-3-Clause" - }, - "../patch-db/client/node_modules/string-argv": { - "version": "0.3.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.6.19" - } - }, - "../patch-db/client/node_modules/string-width": { - "version": "5.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "../patch-db/client/node_modules/strip-ansi": { - "version": "7.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "../patch-db/client/node_modules/strip-final-newline": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "../patch-db/client/node_modules/supports-color": { - "version": "7.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "../patch-db/client/node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "../patch-db/client/node_modules/to-regex-range": { - "version": "5.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "../patch-db/client/node_modules/ts-node": { - "version": "10.9.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "../patch-db/client/node_modules/tslib": { - "version": "2.8.1", - "license": "0BSD", - "peer": true - }, - "../patch-db/client/node_modules/tslint": { - "version": "6.1.3", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@babel/code-frame": "^7.0.0", - "builtin-modules": "^1.1.1", - "chalk": "^2.3.0", - "commander": "^2.12.1", - "diff": "^4.0.1", - "glob": "^7.1.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.3", - "resolve": "^1.3.2", - "semver": "^5.3.0", - "tslib": "^1.13.0", - "tsutils": "^2.29.0" - }, - "bin": { - "tslint": "bin/tslint" - }, - "engines": { - "node": ">=4.8.0" - }, - "peerDependencies": { - "typescript": ">=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >=3.0.0-dev || >= 3.1.0-dev || >= 3.2.0-dev || >= 4.0.0-dev" - } - }, - "../patch-db/client/node_modules/tslint/node_modules/ansi-styles": { - "version": "3.2.1", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "../patch-db/client/node_modules/tslint/node_modules/chalk": { - "version": "2.4.2", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "../patch-db/client/node_modules/tslint/node_modules/color-convert": { - "version": "1.9.3", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "1.1.3" - } - }, - "../patch-db/client/node_modules/tslint/node_modules/color-name": { - "version": "1.1.3", - "dev": true, - "license": "MIT" - }, - "../patch-db/client/node_modules/tslint/node_modules/commander": { - "version": "2.20.3", - "dev": true, - "license": "MIT" - }, - "../patch-db/client/node_modules/tslint/node_modules/has-flag": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "../patch-db/client/node_modules/tslint/node_modules/supports-color": { - "version": "5.5.0", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "../patch-db/client/node_modules/tslint/node_modules/tslib": { - "version": "1.14.1", - "dev": true, - "license": "0BSD" - }, - "../patch-db/client/node_modules/tsutils": { - "version": "2.29.0", - "dev": true, - "license": "MIT", - "dependencies": { - "tslib": "^1.8.1" - }, - "peerDependencies": { - "typescript": ">=2.1.0 || >=2.1.0-dev || >=2.2.0-dev || >=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >= 3.0.0-dev || >= 3.1.0-dev" - } - }, - "../patch-db/client/node_modules/tsutils/node_modules/tslib": { - "version": "1.14.1", - "dev": true, - "license": "0BSD" - }, - "../patch-db/client/node_modules/type-fest": { - "version": "1.4.0", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "../patch-db/client/node_modules/typescript": { - "version": "5.8.3", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "../patch-db/client/node_modules/undici-types": { - "version": "6.21.0", - "dev": true, - "license": "MIT" - }, - "../patch-db/client/node_modules/uuid": { - "version": "8.3.2", - "license": "MIT", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "../patch-db/client/node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "dev": true, - "license": "MIT" - }, - "../patch-db/client/node_modules/which": { - "version": "2.0.2", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "../patch-db/client/node_modules/which-pm-runs": { - "version": "1.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "../patch-db/client/node_modules/wrap-ansi": { - "version": "8.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "../patch-db/client/node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "6.2.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "../patch-db/client/node_modules/wrappy": { - "version": "1.0.2", - "dev": true, - "license": "ISC" - }, - "../patch-db/client/node_modules/yaml": { - "version": "1.10.2", - "dev": true, - "license": "ISC", - "engines": { - "node": ">= 6" - } - }, - "../patch-db/client/node_modules/yn": { - "version": "3.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "../patch-db/client/node_modules/yocto-queue": { - "version": "0.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "../sdk/baseDist": { "name": "@start9labs/start-sdk-base", "license": "MIT", @@ -1722,3893 +142,10 @@ "typescript": "^5.7.3" } }, - "../sdk/baseDist/node_modules/@ampproject/remapping": { - "version": "2.3.0", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "../sdk/baseDist/node_modules/@babel/code-frame": { - "version": "7.26.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.25.9", - "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "../sdk/baseDist/node_modules/@babel/compat-data": { - "version": "7.26.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "../sdk/baseDist/node_modules/@babel/core": { - "version": "7.26.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.26.0", - "@babel/generator": "^7.26.0", - "@babel/helper-compilation-targets": "^7.25.9", - "@babel/helper-module-transforms": "^7.26.0", - "@babel/helpers": "^7.26.0", - "@babel/parser": "^7.26.0", - "@babel/template": "^7.25.9", - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.26.0", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "../sdk/baseDist/node_modules/@babel/generator": { - "version": "7.26.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.26.2", - "@babel/types": "^7.26.0", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^3.0.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "../sdk/baseDist/node_modules/@babel/helper-compilation-targets": { - "version": "7.25.9", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.25.9", - "@babel/helper-validator-option": "^7.25.9", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "../sdk/baseDist/node_modules/@babel/helper-module-imports": { - "version": "7.25.9", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "../sdk/baseDist/node_modules/@babel/helper-module-transforms": { - "version": "7.26.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9", - "@babel/traverse": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "../sdk/baseDist/node_modules/@babel/helper-plugin-utils": { - "version": "7.25.9", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "../sdk/baseDist/node_modules/@babel/helper-string-parser": { - "version": "7.25.9", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "../sdk/baseDist/node_modules/@babel/helper-validator-identifier": { - "version": "7.25.9", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "../sdk/baseDist/node_modules/@babel/helper-validator-option": { - "version": "7.25.9", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "../sdk/baseDist/node_modules/@babel/helpers": { - "version": "7.26.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.25.9", - "@babel/types": "^7.26.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "../sdk/baseDist/node_modules/@babel/parser": { - "version": "7.26.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.26.0" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "../sdk/baseDist/node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../sdk/baseDist/node_modules/@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../sdk/baseDist/node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../sdk/baseDist/node_modules/@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../sdk/baseDist/node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.26.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../sdk/baseDist/node_modules/@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../sdk/baseDist/node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../sdk/baseDist/node_modules/@babel/plugin-syntax-jsx": { - "version": "7.25.9", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../sdk/baseDist/node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../sdk/baseDist/node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../sdk/baseDist/node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../sdk/baseDist/node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../sdk/baseDist/node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../sdk/baseDist/node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../sdk/baseDist/node_modules/@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../sdk/baseDist/node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../sdk/baseDist/node_modules/@babel/plugin-syntax-typescript": { - "version": "7.25.9", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "../sdk/baseDist/node_modules/@babel/template": { - "version": "7.25.9", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.25.9", - "@babel/parser": "^7.25.9", - "@babel/types": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "../sdk/baseDist/node_modules/@babel/traverse": { - "version": "7.25.9", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.25.9", - "@babel/generator": "^7.25.9", - "@babel/parser": "^7.25.9", - "@babel/template": "^7.25.9", - "@babel/types": "^7.25.9", - "debug": "^4.3.1", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "../sdk/baseDist/node_modules/@babel/types": { - "version": "7.26.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "../sdk/baseDist/node_modules/@bcoe/v8-coverage": { - "version": "0.2.3", - "dev": true, - "license": "MIT" - }, - "../sdk/baseDist/node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" - } - }, - "../sdk/baseDist/node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "../sdk/baseDist/node_modules/@esbuild/linux-x64": { - "version": "0.23.1", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "../sdk/baseDist/node_modules/@iarna/toml": { - "version": "3.0.0", - "license": "ISC" - }, - "../sdk/baseDist/node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "dev": true, - "license": "ISC", - "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "../sdk/baseDist/node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "../sdk/baseDist/node_modules/@jest/console": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "../sdk/baseDist/node_modules/@jest/core": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/console": "^29.7.0", - "@jest/reporters": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-changed-files": "^29.7.0", - "jest-config": "^29.7.0", - "jest-haste-map": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.7.0", - "jest-resolve-dependencies": "^29.7.0", - "jest-runner": "^29.7.0", - "jest-runtime": "^29.7.0", - "jest-snapshot": "^29.7.0", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "jest-watcher": "^29.7.0", - "micromatch": "^4.0.4", - "pretty-format": "^29.7.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "../sdk/baseDist/node_modules/@jest/environment": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/fake-timers": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "jest-mock": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "../sdk/baseDist/node_modules/@jest/expect": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "expect": "^29.7.0", - "jest-snapshot": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "../sdk/baseDist/node_modules/@jest/expect-utils": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "jest-get-type": "^29.6.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "../sdk/baseDist/node_modules/@jest/fake-timers": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "@sinonjs/fake-timers": "^10.0.2", - "@types/node": "*", - "jest-message-util": "^29.7.0", - "jest-mock": "^29.7.0", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "../sdk/baseDist/node_modules/@jest/globals": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/expect": "^29.7.0", - "@jest/types": "^29.6.3", - "jest-mock": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "../sdk/baseDist/node_modules/@jest/reporters": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@jridgewell/trace-mapping": "^0.3.18", - "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^6.0.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.1.3", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0", - "jest-worker": "^29.7.0", - "slash": "^3.0.0", - "string-length": "^4.0.1", - "strip-ansi": "^6.0.0", - "v8-to-istanbul": "^9.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "../sdk/baseDist/node_modules/@jest/schemas": { - "version": "29.6.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@sinclair/typebox": "^0.27.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "../sdk/baseDist/node_modules/@jest/source-map": { - "version": "29.6.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.18", - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "../sdk/baseDist/node_modules/@jest/test-result": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/console": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "../sdk/baseDist/node_modules/@jest/test-sequencer": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/test-result": "^29.7.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "../sdk/baseDist/node_modules/@jest/transform": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.6.3", - "@jridgewell/trace-mapping": "^0.3.18", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^2.0.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "jest-regex-util": "^29.6.3", - "jest-util": "^29.7.0", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "../sdk/baseDist/node_modules/@jest/types": { - "version": "29.6.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "../sdk/baseDist/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "../sdk/baseDist/node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "../sdk/baseDist/node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "../sdk/baseDist/node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "dev": true, - "license": "MIT" - }, - "../sdk/baseDist/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "../sdk/baseDist/node_modules/@noble/curves": { - "version": "1.8.2", - "license": "MIT", - "dependencies": { - "@noble/hashes": "1.7.2" - }, - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "../sdk/baseDist/node_modules/@noble/hashes": { - "version": "1.7.2", - "license": "MIT", - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "../sdk/baseDist/node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "../sdk/baseDist/node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "../sdk/baseDist/node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "../sdk/baseDist/node_modules/@sinclair/typebox": { - "version": "0.27.8", - "dev": true, - "license": "MIT" - }, - "../sdk/baseDist/node_modules/@sinonjs/commons": { - "version": "3.0.1", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "type-detect": "4.0.8" - } - }, - "../sdk/baseDist/node_modules/@sinonjs/fake-timers": { - "version": "10.3.0", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@sinonjs/commons": "^3.0.0" - } - }, - "../sdk/baseDist/node_modules/@ts-morph/common": { - "version": "0.19.0", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-glob": "^3.2.12", - "minimatch": "^7.4.3", - "mkdirp": "^2.1.6", - "path-browserify": "^1.0.1" - } - }, - "../sdk/baseDist/node_modules/@ts-morph/common/node_modules/brace-expansion": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "../sdk/baseDist/node_modules/@ts-morph/common/node_modules/minimatch": { - "version": "7.4.6", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "../sdk/baseDist/node_modules/@tsconfig/node10": { - "version": "1.0.11", - "dev": true, - "license": "MIT" - }, - "../sdk/baseDist/node_modules/@tsconfig/node12": { - "version": "1.0.11", - "dev": true, - "license": "MIT" - }, - "../sdk/baseDist/node_modules/@tsconfig/node14": { - "version": "1.0.3", - "dev": true, - "license": "MIT" - }, - "../sdk/baseDist/node_modules/@tsconfig/node16": { - "version": "1.0.4", - "dev": true, - "license": "MIT" - }, - "../sdk/baseDist/node_modules/@types/babel__core": { - "version": "7.20.5", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "../sdk/baseDist/node_modules/@types/babel__generator": { - "version": "7.6.8", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "../sdk/baseDist/node_modules/@types/babel__template": { - "version": "7.4.4", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "../sdk/baseDist/node_modules/@types/babel__traverse": { - "version": "7.20.6", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.20.7" - } - }, - "../sdk/baseDist/node_modules/@types/graceful-fs": { - "version": "4.1.9", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "../sdk/baseDist/node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.6", - "dev": true, - "license": "MIT" - }, - "../sdk/baseDist/node_modules/@types/istanbul-lib-report": { - "version": "3.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/istanbul-lib-coverage": "*" - } - }, - "../sdk/baseDist/node_modules/@types/istanbul-reports": { - "version": "3.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "../sdk/baseDist/node_modules/@types/jest": { - "version": "29.5.14", - "dev": true, - "license": "MIT", - "dependencies": { - "expect": "^29.0.0", - "pretty-format": "^29.0.0" - } - }, - "../sdk/baseDist/node_modules/@types/lodash": { - "version": "4.17.13", - "dev": true, - "license": "MIT" - }, - "../sdk/baseDist/node_modules/@types/lodash.merge": { - "version": "4.6.9", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/lodash": "*" - } - }, - "../sdk/baseDist/node_modules/@types/node": { - "version": "22.10.0", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.20.0" - } - }, - "../sdk/baseDist/node_modules/@types/stack-utils": { - "version": "2.0.3", - "dev": true, - "license": "MIT" - }, - "../sdk/baseDist/node_modules/@types/yargs": { - "version": "17.0.33", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "../sdk/baseDist/node_modules/@types/yargs-parser": { - "version": "21.0.3", - "dev": true, - "license": "MIT" - }, - "../sdk/baseDist/node_modules/acorn": { - "version": "8.14.0", - "dev": true, - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "../sdk/baseDist/node_modules/acorn-walk": { - "version": "8.3.4", - "dev": true, - "license": "MIT", - "dependencies": { - "acorn": "^8.11.0" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "../sdk/baseDist/node_modules/ansi-escapes": { - "version": "4.3.2", - "dev": true, - "license": "MIT", - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "../sdk/baseDist/node_modules/ansi-regex": { - "version": "5.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "../sdk/baseDist/node_modules/ansi-styles": { - "version": "4.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "../sdk/baseDist/node_modules/anymatch": { - "version": "3.1.3", - "dev": true, - "license": "ISC", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "../sdk/baseDist/node_modules/arg": { - "version": "4.1.3", - "dev": true, - "license": "MIT" - }, - "../sdk/baseDist/node_modules/argparse": { - "version": "1.0.10", - "dev": true, - "license": "MIT", - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "../sdk/baseDist/node_modules/async": { - "version": "3.2.6", - "dev": true, - "license": "MIT" - }, - "../sdk/baseDist/node_modules/babel-jest": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/transform": "^29.7.0", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^29.6.3", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.8.0" - } - }, - "../sdk/baseDist/node_modules/babel-plugin-istanbul": { - "version": "6.1.1", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "../sdk/baseDist/node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { - "version": "5.2.1", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "../sdk/baseDist/node_modules/babel-plugin-jest-hoist": { - "version": "29.6.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.1.14", - "@types/babel__traverse": "^7.0.6" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "../sdk/baseDist/node_modules/babel-preset-current-node-syntax": { - "version": "1.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-import-attributes": "^7.24.7", - "@babel/plugin-syntax-import-meta": "^7.10.4", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "../sdk/baseDist/node_modules/babel-preset-jest": { - "version": "29.6.3", - "dev": true, - "license": "MIT", - "dependencies": { - "babel-plugin-jest-hoist": "^29.6.3", - "babel-preset-current-node-syntax": "^1.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "../sdk/baseDist/node_modules/balanced-match": { - "version": "1.0.2", - "dev": true, - "license": "MIT" - }, - "../sdk/baseDist/node_modules/brace-expansion": { - "version": "1.1.11", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "../sdk/baseDist/node_modules/braces": { - "version": "3.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "../sdk/baseDist/node_modules/browserslist": { - "version": "4.24.2", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "caniuse-lite": "^1.0.30001669", - "electron-to-chromium": "^1.5.41", - "node-releases": "^2.0.18", - "update-browserslist-db": "^1.1.1" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "../sdk/baseDist/node_modules/bs-logger": { - "version": "0.2.6", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-json-stable-stringify": "2.x" - }, - "engines": { - "node": ">= 6" - } - }, - "../sdk/baseDist/node_modules/bser": { - "version": "2.1.1", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "node-int64": "^0.4.0" - } - }, - "../sdk/baseDist/node_modules/buffer-from": { - "version": "1.1.2", - "dev": true, - "license": "MIT" - }, - "../sdk/baseDist/node_modules/callsites": { - "version": "3.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "../sdk/baseDist/node_modules/camelcase": { - "version": "5.3.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "../sdk/baseDist/node_modules/caniuse-lite": { - "version": "1.0.30001684", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" - }, - "../sdk/baseDist/node_modules/chalk": { - "version": "4.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "../sdk/baseDist/node_modules/char-regex": { - "version": "1.0.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "../sdk/baseDist/node_modules/ci-info": { - "version": "3.9.0", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "../sdk/baseDist/node_modules/cjs-module-lexer": { - "version": "1.4.1", - "dev": true, - "license": "MIT" - }, - "../sdk/baseDist/node_modules/cliui": { - "version": "8.0.1", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "../sdk/baseDist/node_modules/co": { - "version": "4.6.0", - "dev": true, - "license": "MIT", - "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.0" - } - }, - "../sdk/baseDist/node_modules/code-block-writer": { - "version": "12.0.0", - "dev": true, - "license": "MIT" - }, - "../sdk/baseDist/node_modules/collect-v8-coverage": { - "version": "1.0.2", - "dev": true, - "license": "MIT" - }, - "../sdk/baseDist/node_modules/color-convert": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "../sdk/baseDist/node_modules/color-name": { - "version": "1.1.4", - "dev": true, - "license": "MIT" - }, - "../sdk/baseDist/node_modules/commander": { - "version": "10.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14" - } - }, - "../sdk/baseDist/node_modules/concat-map": { - "version": "0.0.1", - "dev": true, - "license": "MIT" - }, - "../sdk/baseDist/node_modules/convert-source-map": { - "version": "2.0.0", - "dev": true, - "license": "MIT" - }, - "../sdk/baseDist/node_modules/create-jest": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-config": "^29.7.0", - "jest-util": "^29.7.0", - "prompts": "^2.0.1" - }, - "bin": { - "create-jest": "bin/create-jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "../sdk/baseDist/node_modules/create-require": { - "version": "1.1.1", - "dev": true, - "license": "MIT" - }, - "../sdk/baseDist/node_modules/cross-spawn": { - "version": "7.0.6", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "../sdk/baseDist/node_modules/debug": { - "version": "4.3.7", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "../sdk/baseDist/node_modules/dedent": { - "version": "1.5.3", - "dev": true, - "license": "MIT", - "peerDependencies": { - "babel-plugin-macros": "^3.1.0" - }, - "peerDependenciesMeta": { - "babel-plugin-macros": { - "optional": true - } - } - }, - "../sdk/baseDist/node_modules/deep-equality-data-structures": { - "version": "1.5.1", - "license": "MIT", - "dependencies": { - "object-hash": "^3.0.0" - } - }, - "../sdk/baseDist/node_modules/deepmerge": { - "version": "4.3.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "../sdk/baseDist/node_modules/detect-newline": { - "version": "3.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "../sdk/baseDist/node_modules/diff": { - "version": "4.0.2", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, - "../sdk/baseDist/node_modules/diff-sequences": { - "version": "29.6.3", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "../sdk/baseDist/node_modules/ejs": { - "version": "3.1.10", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "jake": "^10.8.5" - }, - "bin": { - "ejs": "bin/cli.js" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "../sdk/baseDist/node_modules/electron-to-chromium": { - "version": "1.5.65", - "dev": true, - "license": "ISC" - }, - "../sdk/baseDist/node_modules/emittery": { - "version": "0.13.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sindresorhus/emittery?sponsor=1" - } - }, - "../sdk/baseDist/node_modules/emoji-regex": { - "version": "8.0.0", - "dev": true, - "license": "MIT" - }, - "../sdk/baseDist/node_modules/error-ex": { - "version": "1.3.2", - "dev": true, - "license": "MIT", - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "../sdk/baseDist/node_modules/esbuild": { - "version": "0.23.1", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.23.1", - "@esbuild/android-arm": "0.23.1", - "@esbuild/android-arm64": "0.23.1", - "@esbuild/android-x64": "0.23.1", - "@esbuild/darwin-arm64": "0.23.1", - "@esbuild/darwin-x64": "0.23.1", - "@esbuild/freebsd-arm64": "0.23.1", - "@esbuild/freebsd-x64": "0.23.1", - "@esbuild/linux-arm": "0.23.1", - "@esbuild/linux-arm64": "0.23.1", - "@esbuild/linux-ia32": "0.23.1", - "@esbuild/linux-loong64": "0.23.1", - "@esbuild/linux-mips64el": "0.23.1", - "@esbuild/linux-ppc64": "0.23.1", - "@esbuild/linux-riscv64": "0.23.1", - "@esbuild/linux-s390x": "0.23.1", - "@esbuild/linux-x64": "0.23.1", - "@esbuild/netbsd-x64": "0.23.1", - "@esbuild/openbsd-arm64": "0.23.1", - "@esbuild/openbsd-x64": "0.23.1", - "@esbuild/sunos-x64": "0.23.1", - "@esbuild/win32-arm64": "0.23.1", - "@esbuild/win32-ia32": "0.23.1", - "@esbuild/win32-x64": "0.23.1" - } - }, - "../sdk/baseDist/node_modules/escalade": { - "version": "3.2.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "../sdk/baseDist/node_modules/escape-string-regexp": { - "version": "2.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "../sdk/baseDist/node_modules/esprima": { - "version": "4.0.1", - "dev": true, - "license": "BSD-2-Clause", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "../sdk/baseDist/node_modules/execa": { - "version": "5.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "../sdk/baseDist/node_modules/exit": { - "version": "0.1.2", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "../sdk/baseDist/node_modules/expect": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/expect-utils": "^29.7.0", - "jest-get-type": "^29.6.3", - "jest-matcher-utils": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "../sdk/baseDist/node_modules/fast-glob": { - "version": "3.3.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "../sdk/baseDist/node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "dev": true, - "license": "MIT" - }, - "../sdk/baseDist/node_modules/fastq": { - "version": "1.17.1", - "dev": true, - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "../sdk/baseDist/node_modules/fb-watchman": { - "version": "2.0.2", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "bser": "2.1.1" - } - }, - "../sdk/baseDist/node_modules/filelist": { - "version": "1.0.4", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "minimatch": "^5.0.1" - } - }, - "../sdk/baseDist/node_modules/filelist/node_modules/brace-expansion": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "../sdk/baseDist/node_modules/filelist/node_modules/minimatch": { - "version": "5.1.6", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "../sdk/baseDist/node_modules/fill-range": { - "version": "7.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "../sdk/baseDist/node_modules/find-up": { - "version": "4.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "../sdk/baseDist/node_modules/fs.realpath": { - "version": "1.0.0", - "dev": true, - "license": "ISC" - }, - "../sdk/baseDist/node_modules/function-bind": { - "version": "1.1.2", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "../sdk/baseDist/node_modules/gensync": { - "version": "1.0.0-beta.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "../sdk/baseDist/node_modules/get-caller-file": { - "version": "2.0.5", - "dev": true, - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "../sdk/baseDist/node_modules/get-package-type": { - "version": "0.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.0.0" - } - }, - "../sdk/baseDist/node_modules/get-stream": { - "version": "6.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "../sdk/baseDist/node_modules/get-tsconfig": { - "version": "4.8.1", - "dev": true, - "license": "MIT", - "dependencies": { - "resolve-pkg-maps": "^1.0.0" - }, - "funding": { - "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" - } - }, - "../sdk/baseDist/node_modules/glob": { - "version": "7.2.3", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "../sdk/baseDist/node_modules/glob-parent": { - "version": "5.1.2", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "../sdk/baseDist/node_modules/globals": { - "version": "11.12.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "../sdk/baseDist/node_modules/graceful-fs": { - "version": "4.2.11", - "dev": true, - "license": "ISC" - }, - "../sdk/baseDist/node_modules/has-flag": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "../sdk/baseDist/node_modules/hasown": { - "version": "2.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "../sdk/baseDist/node_modules/html-escaper": { - "version": "2.0.2", - "dev": true, - "license": "MIT" - }, - "../sdk/baseDist/node_modules/human-signals": { - "version": "2.1.0", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=10.17.0" - } - }, - "../sdk/baseDist/node_modules/import-local": { - "version": "3.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "../sdk/baseDist/node_modules/imurmurhash": { - "version": "0.1.4", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, - "../sdk/baseDist/node_modules/inflight": { - "version": "1.0.6", - "dev": true, - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "../sdk/baseDist/node_modules/inherits": { - "version": "2.0.4", - "dev": true, - "license": "ISC" - }, - "../sdk/baseDist/node_modules/is-arrayish": { - "version": "0.2.1", - "dev": true, - "license": "MIT" - }, - "../sdk/baseDist/node_modules/is-core-module": { - "version": "2.15.1", - "dev": true, - "license": "MIT", - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "../sdk/baseDist/node_modules/is-extglob": { - "version": "2.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "../sdk/baseDist/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "../sdk/baseDist/node_modules/is-generator-fn": { - "version": "2.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "../sdk/baseDist/node_modules/is-glob": { - "version": "4.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "../sdk/baseDist/node_modules/is-number": { - "version": "7.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "../sdk/baseDist/node_modules/is-stream": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "../sdk/baseDist/node_modules/isexe": { - "version": "2.0.0", - "dev": true, - "license": "ISC" - }, - "../sdk/baseDist/node_modules/isomorphic-fetch": { - "version": "3.0.0", - "license": "MIT", - "dependencies": { - "node-fetch": "^2.6.1", - "whatwg-fetch": "^3.4.1" - } - }, - "../sdk/baseDist/node_modules/istanbul-lib-coverage": { - "version": "3.2.2", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=8" - } - }, - "../sdk/baseDist/node_modules/istanbul-lib-instrument": { - "version": "6.0.3", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@babel/core": "^7.23.9", - "@babel/parser": "^7.23.9", - "@istanbuljs/schema": "^0.1.3", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^7.5.4" - }, - "engines": { - "node": ">=10" - } - }, - "../sdk/baseDist/node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "7.6.3", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "../sdk/baseDist/node_modules/istanbul-lib-report": { - "version": "3.0.1", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^4.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "../sdk/baseDist/node_modules/istanbul-lib-source-maps": { - "version": "4.0.1", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=10" - } - }, - "../sdk/baseDist/node_modules/istanbul-reports": { - "version": "3.1.7", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "../sdk/baseDist/node_modules/jake": { - "version": "10.9.2", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "async": "^3.2.3", - "chalk": "^4.0.2", - "filelist": "^1.0.4", - "minimatch": "^3.1.2" - }, - "bin": { - "jake": "bin/cli.js" - }, - "engines": { - "node": ">=10" - } - }, - "../sdk/baseDist/node_modules/jest": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/core": "^29.7.0", - "@jest/types": "^29.6.3", - "import-local": "^3.0.2", - "jest-cli": "^29.7.0" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "../sdk/baseDist/node_modules/jest-changed-files": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "execa": "^5.0.0", - "jest-util": "^29.7.0", - "p-limit": "^3.1.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "../sdk/baseDist/node_modules/jest-circus": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/expect": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^1.0.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^29.7.0", - "jest-matcher-utils": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-runtime": "^29.7.0", - "jest-snapshot": "^29.7.0", - "jest-util": "^29.7.0", - "p-limit": "^3.1.0", - "pretty-format": "^29.7.0", - "pure-rand": "^6.0.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "../sdk/baseDist/node_modules/jest-cli": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/core": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/types": "^29.6.3", - "chalk": "^4.0.0", - "create-jest": "^29.7.0", - "exit": "^0.1.2", - "import-local": "^3.0.2", - "jest-config": "^29.7.0", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "yargs": "^17.3.1" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "../sdk/baseDist/node_modules/jest-config": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^29.7.0", - "@jest/types": "^29.6.3", - "babel-jest": "^29.7.0", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-circus": "^29.7.0", - "jest-environment-node": "^29.7.0", - "jest-get-type": "^29.6.3", - "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.7.0", - "jest-runner": "^29.7.0", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "micromatch": "^4.0.4", - "parse-json": "^5.2.0", - "pretty-format": "^29.7.0", - "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@types/node": "*", - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "ts-node": { - "optional": true - } - } - }, - "../sdk/baseDist/node_modules/jest-diff": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^29.6.3", - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "../sdk/baseDist/node_modules/jest-docblock": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "detect-newline": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "../sdk/baseDist/node_modules/jest-each": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "chalk": "^4.0.0", - "jest-get-type": "^29.6.3", - "jest-util": "^29.7.0", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "../sdk/baseDist/node_modules/jest-environment-node": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/fake-timers": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "jest-mock": "^29.7.0", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "../sdk/baseDist/node_modules/jest-get-type": { - "version": "29.6.3", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "../sdk/baseDist/node_modules/jest-haste-map": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.6.3", - "jest-util": "^29.7.0", - "jest-worker": "^29.7.0", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - } - }, - "../sdk/baseDist/node_modules/jest-leak-detector": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "../sdk/baseDist/node_modules/jest-matcher-utils": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^29.7.0", - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "../sdk/baseDist/node_modules/jest-message-util": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.6.3", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^29.7.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "../sdk/baseDist/node_modules/jest-mock": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "@types/node": "*", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "../sdk/baseDist/node_modules/jest-pnp-resolver": { - "version": "1.2.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - }, - "peerDependencies": { - "jest-resolve": "*" - }, - "peerDependenciesMeta": { - "jest-resolve": { - "optional": true - } - } - }, - "../sdk/baseDist/node_modules/jest-regex-util": { - "version": "29.6.3", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "../sdk/baseDist/node_modules/jest-resolve": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "resolve": "^1.20.0", - "resolve.exports": "^2.0.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "../sdk/baseDist/node_modules/jest-resolve-dependencies": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "jest-regex-util": "^29.6.3", - "jest-snapshot": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "../sdk/baseDist/node_modules/jest-runner": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/console": "^29.7.0", - "@jest/environment": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "graceful-fs": "^4.2.9", - "jest-docblock": "^29.7.0", - "jest-environment-node": "^29.7.0", - "jest-haste-map": "^29.7.0", - "jest-leak-detector": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-resolve": "^29.7.0", - "jest-runtime": "^29.7.0", - "jest-util": "^29.7.0", - "jest-watcher": "^29.7.0", - "jest-worker": "^29.7.0", - "p-limit": "^3.1.0", - "source-map-support": "0.5.13" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "../sdk/baseDist/node_modules/jest-runtime": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/fake-timers": "^29.7.0", - "@jest/globals": "^29.7.0", - "@jest/source-map": "^29.6.3", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-mock": "^29.7.0", - "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.7.0", - "jest-snapshot": "^29.7.0", - "jest-util": "^29.7.0", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "../sdk/baseDist/node_modules/jest-snapshot": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.11.6", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-jsx": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/types": "^7.3.3", - "@jest/expect-utils": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^29.7.0", - "graceful-fs": "^4.2.9", - "jest-diff": "^29.7.0", - "jest-get-type": "^29.6.3", - "jest-matcher-utils": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0", - "natural-compare": "^1.4.0", - "pretty-format": "^29.7.0", - "semver": "^7.5.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "../sdk/baseDist/node_modules/jest-snapshot/node_modules/semver": { - "version": "7.6.3", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "../sdk/baseDist/node_modules/jest-util": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "../sdk/baseDist/node_modules/jest-validate": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.6.3", - "leven": "^3.1.0", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "../sdk/baseDist/node_modules/jest-validate/node_modules/camelcase": { - "version": "6.3.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "../sdk/baseDist/node_modules/jest-watcher": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/test-result": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "jest-util": "^29.7.0", - "string-length": "^4.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "../sdk/baseDist/node_modules/jest-worker": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*", - "jest-util": "^29.7.0", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "../sdk/baseDist/node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "../sdk/baseDist/node_modules/js-tokens": { - "version": "4.0.0", - "dev": true, - "license": "MIT" - }, - "../sdk/baseDist/node_modules/js-yaml": { - "version": "3.14.1", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "../sdk/baseDist/node_modules/jsesc": { - "version": "3.0.2", - "dev": true, - "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" - } - }, - "../sdk/baseDist/node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "dev": true, - "license": "MIT" - }, - "../sdk/baseDist/node_modules/json5": { - "version": "2.2.3", - "dev": true, - "license": "MIT", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "../sdk/baseDist/node_modules/kleur": { - "version": "3.0.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "../sdk/baseDist/node_modules/leven": { - "version": "3.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "../sdk/baseDist/node_modules/lines-and-columns": { - "version": "1.2.4", - "dev": true, - "license": "MIT" - }, - "../sdk/baseDist/node_modules/locate-path": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "../sdk/baseDist/node_modules/lodash.memoize": { - "version": "4.1.2", - "dev": true, - "license": "MIT" - }, - "../sdk/baseDist/node_modules/lru-cache": { - "version": "5.1.1", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" - } - }, - "../sdk/baseDist/node_modules/make-dir": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "../sdk/baseDist/node_modules/make-dir/node_modules/semver": { - "version": "7.6.3", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "../sdk/baseDist/node_modules/make-error": { - "version": "1.3.6", - "dev": true, - "license": "ISC" - }, - "../sdk/baseDist/node_modules/makeerror": { - "version": "1.0.12", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "tmpl": "1.0.5" - } - }, - "../sdk/baseDist/node_modules/merge-stream": { - "version": "2.0.0", - "dev": true, - "license": "MIT" - }, - "../sdk/baseDist/node_modules/merge2": { - "version": "1.4.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "../sdk/baseDist/node_modules/micromatch": { - "version": "4.0.8", - "dev": true, - "license": "MIT", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "../sdk/baseDist/node_modules/mime": { - "version": "4.0.7", - "funding": [ - "https://github.com/sponsors/broofa" - ], - "license": "MIT", - "bin": { - "mime": "bin/cli.js" - }, - "engines": { - "node": ">=16" - } - }, - "../sdk/baseDist/node_modules/mimic-fn": { - "version": "2.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "../sdk/baseDist/node_modules/minimatch": { - "version": "3.1.2", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "../sdk/baseDist/node_modules/mkdirp": { - "version": "2.1.6", - "dev": true, - "license": "MIT", - "bin": { - "mkdirp": "dist/cjs/src/bin.js" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "../sdk/baseDist/node_modules/ms": { - "version": "2.1.3", - "dev": true, - "license": "MIT" - }, - "../sdk/baseDist/node_modules/natural-compare": { - "version": "1.4.0", - "dev": true, - "license": "MIT" - }, - "../sdk/baseDist/node_modules/node-fetch": { - "version": "2.7.0", - "license": "MIT", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "../sdk/baseDist/node_modules/node-int64": { - "version": "0.4.0", - "dev": true, - "license": "MIT" - }, - "../sdk/baseDist/node_modules/node-releases": { - "version": "2.0.18", - "dev": true, - "license": "MIT" - }, - "../sdk/baseDist/node_modules/normalize-path": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "../sdk/baseDist/node_modules/npm-run-path": { - "version": "4.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "../sdk/baseDist/node_modules/object-hash": { - "version": "3.0.0", - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "../sdk/baseDist/node_modules/once": { - "version": "1.4.0", - "dev": true, - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "../sdk/baseDist/node_modules/onetime": { - "version": "5.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "../sdk/baseDist/node_modules/p-limit": { - "version": "3.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "../sdk/baseDist/node_modules/p-locate": { - "version": "4.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "../sdk/baseDist/node_modules/p-locate/node_modules/p-limit": { - "version": "2.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "../sdk/baseDist/node_modules/p-try": { - "version": "2.2.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "../sdk/baseDist/node_modules/parse-json": { - "version": "5.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "../sdk/baseDist/node_modules/path-browserify": { - "version": "1.0.1", - "dev": true, - "license": "MIT" - }, - "../sdk/baseDist/node_modules/path-exists": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "../sdk/baseDist/node_modules/path-is-absolute": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "../sdk/baseDist/node_modules/path-key": { - "version": "3.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "../sdk/baseDist/node_modules/path-parse": { - "version": "1.0.7", - "dev": true, - "license": "MIT" - }, - "../sdk/baseDist/node_modules/peggy": { - "version": "3.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "commander": "^10.0.0", - "source-map-generator": "0.8.0" - }, - "bin": { - "peggy": "bin/peggy.js" - }, - "engines": { - "node": ">=14" - } - }, - "../sdk/baseDist/node_modules/picocolors": { - "version": "1.1.1", - "dev": true, - "license": "ISC" - }, - "../sdk/baseDist/node_modules/picomatch": { - "version": "2.3.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "../sdk/baseDist/node_modules/pirates": { - "version": "4.0.6", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "../sdk/baseDist/node_modules/pkg-dir": { - "version": "4.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "../sdk/baseDist/node_modules/prettier": { - "version": "3.4.0", - "dev": true, - "license": "MIT", - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "../sdk/baseDist/node_modules/pretty-format": { - "version": "29.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "../sdk/baseDist/node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "../sdk/baseDist/node_modules/prompts": { - "version": "2.4.2", - "dev": true, - "license": "MIT", - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" - } - }, - "../sdk/baseDist/node_modules/pure-rand": { - "version": "6.1.0", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/dubzzz" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fast-check" - } - ], - "license": "MIT" - }, - "../sdk/baseDist/node_modules/queue-microtask": { - "version": "1.2.3", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "../sdk/baseDist/node_modules/react-is": { - "version": "18.3.1", - "dev": true, - "license": "MIT" - }, - "../sdk/baseDist/node_modules/require-directory": { - "version": "2.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "../sdk/baseDist/node_modules/resolve": { - "version": "1.22.8", - "dev": true, - "license": "MIT", - "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "../sdk/baseDist/node_modules/resolve-cwd": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "../sdk/baseDist/node_modules/resolve-from": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "../sdk/baseDist/node_modules/resolve-pkg-maps": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" - } - }, - "../sdk/baseDist/node_modules/resolve.exports": { - "version": "2.0.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "../sdk/baseDist/node_modules/reusify": { - "version": "1.0.4", - "dev": true, - "license": "MIT", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "../sdk/baseDist/node_modules/run-parallel": { - "version": "1.2.0", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "../sdk/baseDist/node_modules/semver": { - "version": "6.3.1", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "../sdk/baseDist/node_modules/shebang-command": { - "version": "2.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "../sdk/baseDist/node_modules/shebang-regex": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "../sdk/baseDist/node_modules/signal-exit": { - "version": "3.0.7", - "dev": true, - "license": "ISC" - }, - "../sdk/baseDist/node_modules/sisteransi": { - "version": "1.0.5", - "dev": true, - "license": "MIT" - }, - "../sdk/baseDist/node_modules/slash": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "../sdk/baseDist/node_modules/source-map": { - "version": "0.6.1", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "../sdk/baseDist/node_modules/source-map-generator": { - "version": "0.8.0", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">= 10" - } - }, - "../sdk/baseDist/node_modules/source-map-support": { - "version": "0.5.13", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "../sdk/baseDist/node_modules/sprintf-js": { - "version": "1.0.3", - "dev": true, - "license": "BSD-3-Clause" - }, - "../sdk/baseDist/node_modules/stack-utils": { - "version": "2.0.6", - "dev": true, - "license": "MIT", - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "../sdk/baseDist/node_modules/string-length": { - "version": "4.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "../sdk/baseDist/node_modules/string-width": { - "version": "4.2.3", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "../sdk/baseDist/node_modules/strip-ansi": { - "version": "6.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "../sdk/baseDist/node_modules/strip-bom": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "../sdk/baseDist/node_modules/strip-final-newline": { - "version": "2.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "../sdk/baseDist/node_modules/strip-json-comments": { - "version": "3.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "../sdk/baseDist/node_modules/supports-color": { - "version": "7.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "../sdk/baseDist/node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "../sdk/baseDist/node_modules/test-exclude": { - "version": "6.0.0", - "dev": true, - "license": "ISC", - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "../sdk/baseDist/node_modules/tmpl": { - "version": "1.0.5", - "dev": true, - "license": "BSD-3-Clause" - }, - "../sdk/baseDist/node_modules/to-regex-range": { - "version": "5.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "../sdk/baseDist/node_modules/tr46": { - "version": "0.0.3", - "license": "MIT" - }, - "../sdk/baseDist/node_modules/ts-jest": { - "version": "29.2.5", - "dev": true, - "license": "MIT", - "dependencies": { - "bs-logger": "^0.2.6", - "ejs": "^3.1.10", - "fast-json-stable-stringify": "^2.1.0", - "jest-util": "^29.0.0", - "json5": "^2.2.3", - "lodash.memoize": "^4.1.2", - "make-error": "^1.3.6", - "semver": "^7.6.3", - "yargs-parser": "^21.1.1" - }, - "bin": { - "ts-jest": "cli.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" - }, - "peerDependencies": { - "@babel/core": ">=7.0.0-beta.0 <8", - "@jest/transform": "^29.0.0", - "@jest/types": "^29.0.0", - "babel-jest": "^29.0.0", - "jest": "^29.0.0", - "typescript": ">=4.3 <6" - }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - }, - "@jest/transform": { - "optional": true - }, - "@jest/types": { - "optional": true - }, - "babel-jest": { - "optional": true - }, - "esbuild": { - "optional": true - } - } - }, - "../sdk/baseDist/node_modules/ts-jest/node_modules/semver": { - "version": "7.6.3", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "../sdk/baseDist/node_modules/ts-matches": { - "version": "6.3.2", - "license": "MIT" - }, - "../sdk/baseDist/node_modules/ts-morph": { - "version": "18.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@ts-morph/common": "~0.19.0", - "code-block-writer": "^12.0.0" - } - }, - "../sdk/baseDist/node_modules/ts-node": { - "version": "10.9.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "../sdk/baseDist/node_modules/ts-pegjs": { - "version": "4.2.1", - "dev": true, - "license": "MIT", - "dependencies": { - "prettier": "^2.8.8", - "ts-morph": "^18.0.0" - }, - "bin": { - "tspegjs": "dist/cli.mjs" - }, - "peerDependencies": { - "peggy": "^3.0.2" - } - }, - "../sdk/baseDist/node_modules/ts-pegjs/node_modules/prettier": { - "version": "2.8.8", - "dev": true, - "license": "MIT", - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "../sdk/baseDist/node_modules/tsx": { - "version": "4.19.2", - "dev": true, - "license": "MIT", - "dependencies": { - "esbuild": "~0.23.0", - "get-tsconfig": "^4.7.5" - }, - "bin": { - "tsx": "dist/cli.mjs" - }, - "engines": { - "node": ">=18.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - } - }, - "../sdk/baseDist/node_modules/type-detect": { - "version": "4.0.8", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "../sdk/baseDist/node_modules/type-fest": { - "version": "0.21.3", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "../sdk/baseDist/node_modules/typescript": { - "version": "5.7.3", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "../sdk/baseDist/node_modules/undici-types": { - "version": "6.20.0", - "dev": true, - "license": "MIT" - }, - "../sdk/baseDist/node_modules/update-browserslist-db": { - "version": "1.1.1", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "escalade": "^3.2.0", - "picocolors": "^1.1.0" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "../sdk/baseDist/node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "dev": true, - "license": "MIT" - }, - "../sdk/baseDist/node_modules/v8-to-istanbul": { - "version": "9.3.0", - "dev": true, - "license": "ISC", - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.12", - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^2.0.0" - }, - "engines": { - "node": ">=10.12.0" - } - }, - "../sdk/baseDist/node_modules/walker": { - "version": "1.0.8", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "makeerror": "1.0.12" - } - }, - "../sdk/baseDist/node_modules/webidl-conversions": { - "version": "3.0.1", - "license": "BSD-2-Clause" - }, - "../sdk/baseDist/node_modules/whatwg-fetch": { - "version": "3.6.20", - "license": "MIT" - }, - "../sdk/baseDist/node_modules/whatwg-url": { - "version": "5.0.0", - "license": "MIT", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "../sdk/baseDist/node_modules/which": { - "version": "2.0.2", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "../sdk/baseDist/node_modules/wrap-ansi": { - "version": "7.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "../sdk/baseDist/node_modules/wrappy": { - "version": "1.0.2", - "dev": true, - "license": "ISC" - }, - "../sdk/baseDist/node_modules/write-file-atomic": { - "version": "4.0.2", - "dev": true, - "license": "ISC", - "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "../sdk/baseDist/node_modules/y18n": { - "version": "5.0.8", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "../sdk/baseDist/node_modules/yallist": { - "version": "3.1.1", - "dev": true, - "license": "ISC" - }, - "../sdk/baseDist/node_modules/yaml": { - "version": "2.7.1", - "license": "ISC", - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14" - } - }, - "../sdk/baseDist/node_modules/yargs": { - "version": "17.7.2", - "dev": true, - "license": "MIT", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "../sdk/baseDist/node_modules/yargs-parser": { - "version": "21.1.1", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "../sdk/baseDist/node_modules/yn": { - "version": "3.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "../sdk/baseDist/node_modules/yocto-queue": { - "version": "0.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@algolia/abtesting": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@algolia/abtesting/-/abtesting-1.1.0.tgz", + "integrity": "sha512-sEyWjw28a/9iluA37KLGu8vjxEIlb60uxznfTUmXImy7H5NvbpSO6yYgmgH5KiD7j+zTUUihiST0jEP12IoXow==", "devOptional": true, "license": "MIT", "dependencies": { @@ -5623,6 +160,8 @@ }, "node_modules/@algolia/client-abtesting": { "version": "5.35.0", + "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.35.0.tgz", + "integrity": "sha512-uUdHxbfHdoppDVflCHMxRlj49/IllPwwQ2cQ8DLC4LXr3kY96AHBpW0dMyi6ygkn2MtFCc6BxXCzr668ZRhLBQ==", "devOptional": true, "license": "MIT", "dependencies": { @@ -5637,6 +176,8 @@ }, "node_modules/@algolia/client-analytics": { "version": "5.35.0", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.35.0.tgz", + "integrity": "sha512-SunAgwa9CamLcRCPnPHx1V2uxdQwJGqb1crYrRWktWUdld0+B2KyakNEeVn5lln4VyeNtW17Ia7V7qBWyM/Skw==", "devOptional": true, "license": "MIT", "dependencies": { @@ -5651,6 +192,8 @@ }, "node_modules/@algolia/client-common": { "version": "5.35.0", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.35.0.tgz", + "integrity": "sha512-ipE0IuvHu/bg7TjT2s+187kz/E3h5ssfTtjpg1LbWMgxlgiaZIgTTbyynM7NfpSJSKsgQvCQxWjGUO51WSCu7w==", "devOptional": true, "license": "MIT", "engines": { @@ -5659,6 +202,8 @@ }, "node_modules/@algolia/client-insights": { "version": "5.35.0", + "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.35.0.tgz", + "integrity": "sha512-UNbCXcBpqtzUucxExwTSfAe8gknAJ485NfPN6o1ziHm6nnxx97piIbcBQ3edw823Tej2Wxu1C0xBY06KgeZ7gA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -5673,6 +218,8 @@ }, "node_modules/@algolia/client-personalization": { "version": "5.35.0", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.35.0.tgz", + "integrity": "sha512-/KWjttZ6UCStt4QnWoDAJ12cKlQ+fkpMtyPmBgSS2WThJQdSV/4UWcqCUqGH7YLbwlj3JjNirCu3Y7uRTClxvA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -5687,6 +234,8 @@ }, "node_modules/@algolia/client-query-suggestions": { "version": "5.35.0", + "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.35.0.tgz", + "integrity": "sha512-8oCuJCFf/71IYyvQQC+iu4kgViTODbXDk3m7yMctEncRSRV+u2RtDVlpGGfPlJQOrAY7OONwJlSHkmbbm2Kp/w==", "devOptional": true, "license": "MIT", "dependencies": { @@ -5701,6 +250,8 @@ }, "node_modules/@algolia/client-search": { "version": "5.35.0", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.35.0.tgz", + "integrity": "sha512-FfmdHTrXhIduWyyuko1YTcGLuicVbhUyRjO3HbXE4aP655yKZgdTIfMhZ/V5VY9bHuxv/fGEh3Od1Lvv2ODNTg==", "devOptional": true, "license": "MIT", "dependencies": { @@ -5715,6 +266,8 @@ }, "node_modules/@algolia/ingestion": { "version": "1.35.0", + "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.35.0.tgz", + "integrity": "sha512-gPzACem9IL1Co8mM1LKMhzn1aSJmp+Vp434An4C0OBY4uEJRcqsLN3uLBlY+bYvFg8C8ImwM9YRiKczJXRk0XA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -5729,6 +282,8 @@ }, "node_modules/@algolia/monitoring": { "version": "1.35.0", + "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.35.0.tgz", + "integrity": "sha512-w9MGFLB6ashI8BGcQoVt7iLgDIJNCn4OIu0Q0giE3M2ItNrssvb8C0xuwJQyTy1OFZnemG0EB1OvXhIHOvQwWw==", "devOptional": true, "license": "MIT", "dependencies": { @@ -5743,6 +298,8 @@ }, "node_modules/@algolia/recommend": { "version": "5.35.0", + "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.35.0.tgz", + "integrity": "sha512-AhrVgaaXAb8Ue0u2nuRWwugt0dL5UmRgS9LXe0Hhz493a8KFeZVUE56RGIV3hAa6tHzmAV7eIoqcWTQvxzlJeQ==", "devOptional": true, "license": "MIT", "dependencies": { @@ -5757,6 +314,8 @@ }, "node_modules/@algolia/requester-browser-xhr": { "version": "5.35.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.35.0.tgz", + "integrity": "sha512-diY415KLJZ6x1Kbwl9u96Jsz0OstE3asjXtJ9pmk1d+5gPuQ5jQyEsgC+WmEXzlec3iuVszm8AzNYYaqw6B+Zw==", "devOptional": true, "license": "MIT", "dependencies": { @@ -5768,6 +327,8 @@ }, "node_modules/@algolia/requester-fetch": { "version": "5.35.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.35.0.tgz", + "integrity": "sha512-uydqnSmpAjrgo8bqhE9N1wgcB98psTRRQXcjc4izwMB7yRl9C8uuAQ/5YqRj04U0mMQ+fdu2fcNF6m9+Z1BzDQ==", "devOptional": true, "license": "MIT", "dependencies": { @@ -5779,6 +340,8 @@ }, "node_modules/@algolia/requester-node-http": { "version": "5.35.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.35.0.tgz", + "integrity": "sha512-RgLX78ojYOrThJHrIiPzT4HW3yfQa0D7K+MQ81rhxqaNyNBu4F1r+72LNHYH/Z+y9I1Mrjrd/c/Ue5zfDgAEjQ==", "devOptional": true, "license": "MIT", "dependencies": { @@ -5790,6 +353,8 @@ }, "node_modules/@ampproject/remapping": { "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -5801,11 +366,13 @@ } }, "node_modules/@angular-devkit/architect": { - "version": "0.2002.2", + "version": "0.2003.7", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.2003.7.tgz", + "integrity": "sha512-NGHLfrNQNjwWwvyQomMM1AqRaqH3UU0TwySJh9XlSc9dC/roB5zD2NjLf98K4LfAIfHvDBwkQ+dMo3F556/Xuw==", "devOptional": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "20.2.2", + "@angular-devkit/core": "20.3.7", "rxjs": "7.8.2" }, "engines": { @@ -5815,8 +382,11 @@ } }, "node_modules/@angular-devkit/core": { - "version": "20.2.2", + "version": "20.3.7", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-20.3.7.tgz", + "integrity": "sha512-psmcjwYcXve4sLrcdnARc15/Wfd3RpydbtLo9+mViNzk5HQ6L2eEztKl/2QVYMgzZVIa1GfhjwUllVCyLAv3sg==", "license": "MIT", + "peer": true, "dependencies": { "ajv": "8.17.1", "ajv-formats": "3.0.1", @@ -5840,10 +410,13 @@ } }, "node_modules/@angular-devkit/schematics": { - "version": "20.2.2", + "version": "20.3.7", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-20.3.7.tgz", + "integrity": "sha512-DUxcQBPKO69p56ZgIdVfxWyLiSjdcUoD6BH9/nWHp0QiqRAR6GcXP4SFax76JPl2WsiCp4hHZ233Hf69AP1xew==", "license": "MIT", + "peer": true, "dependencies": { - "@angular-devkit/core": "20.2.2", + "@angular-devkit/core": "20.3.7", "jsonc-parser": "3.3.1", "magic-string": "0.30.17", "ora": "8.2.0", @@ -5857,6 +430,8 @@ }, "node_modules/@angular-experts/hawkeye": { "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@angular-experts/hawkeye/-/hawkeye-1.7.2.tgz", + "integrity": "sha512-6i6XJfWnyeeJICNsTieAr2CAPw4rNg7uWpu382EkneONaVkjbekVCQD0TO5SeXXxfc4L/JskrJe+HCuw9ys+pg==", "dev": true, "license": "ISC", "dependencies": { @@ -5872,8 +447,11 @@ } }, "node_modules/@angular/animations": { - "version": "20.2.4", + "version": "20.3.7", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-20.3.7.tgz", + "integrity": "sha512-i655RaL0zmLE3OESUlDnRNBDRIMW/67nTQvMqP6V1cQ42l2+SMJtREsxmX6cWt55/qvvgeytAA6aBN4aerBl5A==", "license": "MIT", + "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -5881,16 +459,18 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/core": "20.2.4" + "@angular/core": "20.3.7" } }, "node_modules/@angular/build": { - "version": "20.2.2", + "version": "20.3.7", + "resolved": "https://registry.npmjs.org/@angular/build/-/build-20.3.7.tgz", + "integrity": "sha512-NHN5JNDqUc0Ux4IZPCe/fpFAnuRHujkxVfRHSqDFW5+jtj2JuW1XO6qlX+kDheFRlj/NvFgTpidKsE9IjpfMWQ==", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.2002.2", + "@angular-devkit/architect": "0.2003.7", "@babel/core": "7.28.3", "@babel/helper-annotate-as-pure": "7.27.3", "@babel/helper-split-export-declaration": "7.24.7", @@ -5908,12 +488,12 @@ "parse5-html-rewriting-stream": "8.0.0", "picomatch": "4.0.3", "piscina": "5.1.3", - "rolldown": "1.0.0-beta.32", + "rollup": "4.52.3", "sass": "1.90.0", "semver": "7.7.2", "source-map-support": "0.5.21", "tinyglobby": "0.2.14", - "vite": "7.1.2", + "vite": "7.1.11", "watchpack": "2.4.4" }, "engines": { @@ -5932,7 +512,7 @@ "@angular/platform-browser": "^20.0.0", "@angular/platform-server": "^20.0.0", "@angular/service-worker": "^20.0.0", - "@angular/ssr": "^20.2.2", + "@angular/ssr": "^20.3.7", "karma": "^6.4.0", "less": "^4.2.0", "ng-packagr": "^20.0.0", @@ -5982,8 +562,11 @@ } }, "node_modules/@angular/cdk": { - "version": "20.2.2", + "version": "20.2.10", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-20.2.10.tgz", + "integrity": "sha512-d95C2r3JP11KCahouWmPaxswz/EE7Zn1k8ocoGt70jl33x42Sg96vAHeOpnQ4yfrdA4W7Q+eWB/NqqvAGCzOPQ==", "license": "MIT", + "peer": true, "dependencies": { "parse5": "^8.0.0", "tslib": "^2.3.0" @@ -5995,17 +578,20 @@ } }, "node_modules/@angular/cli": { - "version": "20.2.2", + "version": "20.3.7", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-20.3.7.tgz", + "integrity": "sha512-hNurF7g/e9cDHFBRCKLPSmQJs0n28jZsC3sTl/XuWE8PYtv5egh2EuqrxdruYB5GdANpIqSQNgDGQJrKrk/XnQ==", "devOptional": true, "license": "MIT", + "peer": true, "dependencies": { - "@angular-devkit/architect": "0.2002.2", - "@angular-devkit/core": "20.2.2", - "@angular-devkit/schematics": "20.2.2", + "@angular-devkit/architect": "0.2003.7", + "@angular-devkit/core": "20.3.7", + "@angular-devkit/schematics": "20.3.7", "@inquirer/prompts": "7.8.2", "@listr2/prompt-adapter-inquirer": "3.0.1", "@modelcontextprotocol/sdk": "1.17.3", - "@schematics/angular": "20.2.2", + "@schematics/angular": "20.3.7", "@yarnpkg/lockfile": "1.1.0", "algoliasearch": "5.35.0", "ini": "5.0.0", @@ -6028,8 +614,11 @@ } }, "node_modules/@angular/common": { - "version": "20.2.4", + "version": "20.3.7", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-20.3.7.tgz", + "integrity": "sha512-uf8dXYTJbedk/wudkt2MfbtvN/T97aEZBtOTq8/IFQQZ3722rag6D+Cg76e5hBccROOn+ueGJX2gpxz02phTwA==", "license": "MIT", + "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -6037,13 +626,16 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/core": "20.2.4", + "@angular/core": "20.3.7", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/compiler": { - "version": "20.2.4", + "version": "20.3.7", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-20.3.7.tgz", + "integrity": "sha512-EouHO15dUsgnFArj0M25R8cOPVoUfiFYSt6iXnMO8+S4dY1fDEmbFqkW5smlP66HL5Gys59Nwb5inejfIWHrLw==", "license": "MIT", + "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -6052,9 +644,12 @@ } }, "node_modules/@angular/compiler-cli": { - "version": "20.2.4", + "version": "20.3.7", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-20.3.7.tgz", + "integrity": "sha512-viZwWlwc1BAqryRJE0Wq2WgAxDaW9fuwtYHYrOWnIn9sy9KemKmR6RmU9VRydrwUROOlqK49R9+RC1wQ6sYwqA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/core": "7.28.3", "@jridgewell/sourcemap-codec": "^1.4.14", @@ -6073,7 +668,7 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/compiler": "20.2.4", + "@angular/compiler": "20.3.7", "typescript": ">=5.8 <6.0" }, "peerDependenciesMeta": { @@ -6083,8 +678,11 @@ } }, "node_modules/@angular/core": { - "version": "20.2.4", + "version": "20.3.7", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-20.3.7.tgz", + "integrity": "sha512-2UuYzC2A5SUtu33tYTN411Wk0WilA+2Uld/GP3O6mragw1O7v/M8pMFmbe9TR5Ah/abRJIocWGlNqeztZmQmrw==", "license": "MIT", + "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -6092,7 +690,7 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/compiler": "20.2.4", + "@angular/compiler": "20.3.7", "rxjs": "^6.5.3 || ^7.4.0", "zone.js": "~0.15.0" }, @@ -6106,8 +704,11 @@ } }, "node_modules/@angular/forms": { - "version": "20.2.4", + "version": "20.3.7", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-20.3.7.tgz", + "integrity": "sha512-uOCGCoqXeAWIlQMWiIeed/W8g8h2tk91YemMI+Ce1VQ/36Xfft40Bouz4eKcvJV6kLXGygdpWjzFGz32CE+3Og==", "license": "MIT", + "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -6115,14 +716,16 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/common": "20.2.4", - "@angular/core": "20.2.4", - "@angular/platform-browser": "20.2.4", + "@angular/common": "20.3.7", + "@angular/core": "20.3.7", + "@angular/platform-browser": "20.3.7", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/language-service": { - "version": "20.2.4", + "version": "20.3.7", + "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-20.3.7.tgz", + "integrity": "sha512-isULgp/s2NKpeZnU3xFMPBvYHyjqFkqvDDLA8/dBTKb6NZPyrSC6Ckpy8ZNYwNbA5xN6vYys9mip1Vi+oeRo/Q==", "dev": true, "license": "MIT", "engines": { @@ -6130,8 +733,11 @@ } }, "node_modules/@angular/platform-browser": { - "version": "20.2.4", + "version": "20.3.7", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-20.3.7.tgz", + "integrity": "sha512-AbLtyR7fVEGDYyrz95dP2pc69J5XIjLLsFNAuNQPzNX02WPoAxtrWrNY6UnTzGoSrCc5F52hiL2Uo6yPZTiJcg==", "license": "MIT", + "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -6139,9 +745,9 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/animations": "20.2.4", - "@angular/common": "20.2.4", - "@angular/core": "20.2.4" + "@angular/animations": "20.3.7", + "@angular/common": "20.3.7", + "@angular/core": "20.3.7" }, "peerDependenciesMeta": { "@angular/animations": { @@ -6150,7 +756,9 @@ } }, "node_modules/@angular/platform-browser-dynamic": { - "version": "20.2.4", + "version": "20.3.7", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-20.3.7.tgz", + "integrity": "sha512-4TEPA12183cMeVCzuU/Rmuk5RuIgsunTbjgx0o+ymxvYyULOxKDlhZ4hGDKzmRCOu6s3ZeEs4XbgaLP6pK+Kxg==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -6159,18 +767,20 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/common": "20.2.4", - "@angular/compiler": "20.2.4", - "@angular/core": "20.2.4", - "@angular/platform-browser": "20.2.4" + "@angular/common": "20.3.7", + "@angular/compiler": "20.3.7", + "@angular/core": "20.3.7", + "@angular/platform-browser": "20.3.7" } }, "node_modules/@angular/pwa": { - "version": "20.2.2", + "version": "20.3.7", + "resolved": "https://registry.npmjs.org/@angular/pwa/-/pwa-20.3.7.tgz", + "integrity": "sha512-OGWczAO2fZjI1dhQRi8WC/9UauaFaY13QaaxuxDLvXCcw9MuBO1dmb8HpU8JkoW5d4ahIahG+jiVdmZCWk7iFA==", "license": "MIT", "dependencies": { - "@angular-devkit/schematics": "20.2.2", - "@schematics/angular": "20.2.2", + "@angular-devkit/schematics": "20.3.7", + "@schematics/angular": "20.3.7", "parse5-html-rewriting-stream": "8.0.0" }, "engines": { @@ -6179,7 +789,7 @@ "yarn": ">= 1.13.0" }, "peerDependencies": { - "@angular/cli": "^20.2.2" + "@angular/cli": "^20.3.7" }, "peerDependenciesMeta": { "@angular/cli": { @@ -6188,8 +798,11 @@ } }, "node_modules/@angular/router": { - "version": "20.2.4", + "version": "20.3.7", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-20.3.7.tgz", + "integrity": "sha512-Lq7mCNcLP1npmNh2JlNEe02YS2jNnaLnCy/t//o+Qq0c6DGV78JRl7pHubiB2R6XXlgvOcZWg88v94Li+y85Iw==", "license": "MIT", + "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -6197,15 +810,18 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/common": "20.2.4", - "@angular/core": "20.2.4", - "@angular/platform-browser": "20.2.4", + "@angular/common": "20.3.7", + "@angular/core": "20.3.7", + "@angular/platform-browser": "20.3.7", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/service-worker": { - "version": "20.2.4", + "version": "20.3.7", + "resolved": "https://registry.npmjs.org/@angular/service-worker/-/service-worker-20.3.7.tgz", + "integrity": "sha512-q9Q77wBBqScRJJQ7T+F0RepMY543Hm0HCZGvOujT+vQNFK3aRlWLlYenOUIhq2vlLXOhszCt8e5dY7/R+1eRWw==", "license": "MIT", + "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -6216,12 +832,14 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/core": "20.2.4", + "@angular/core": "20.3.7", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@babel/code-frame": { "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", "dev": true, "license": "MIT", "dependencies": { @@ -6235,6 +853,8 @@ }, "node_modules/@babel/compat-data": { "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.4.tgz", + "integrity": "sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==", "dev": true, "license": "MIT", "engines": { @@ -6243,8 +863,11 @@ }, "node_modules/@babel/core": { "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.3.tgz", + "integrity": "sha512-yDBHV9kQNcr2/sUr9jghVyz9C3Y5G2zUM2H2lo+9mKv4sFgbA8s8Z9t8D1jiTkGoO/NoIfKMyKWr4s6CN23ZwQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", @@ -6272,11 +895,15 @@ }, "node_modules/@babel/core/node_modules/convert-source-map": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true, "license": "MIT" }, "node_modules/@babel/core/node_modules/semver": { "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "license": "ISC", "bin": { @@ -6285,6 +912,8 @@ }, "node_modules/@babel/generator": { "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", + "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", "dev": true, "license": "MIT", "dependencies": { @@ -6300,6 +929,8 @@ }, "node_modules/@babel/helper-annotate-as-pure": { "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", + "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", "dev": true, "license": "MIT", "dependencies": { @@ -6311,6 +942,8 @@ }, "node_modules/@babel/helper-compilation-targets": { "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", "dev": true, "license": "MIT", "dependencies": { @@ -6326,6 +959,8 @@ }, "node_modules/@babel/helper-compilation-targets/node_modules/semver": { "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "license": "ISC", "bin": { @@ -6334,6 +969,8 @@ }, "node_modules/@babel/helper-globals": { "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", "dev": true, "license": "MIT", "engines": { @@ -6342,6 +979,8 @@ }, "node_modules/@babel/helper-module-imports": { "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", "dev": true, "license": "MIT", "dependencies": { @@ -6354,6 +993,8 @@ }, "node_modules/@babel/helper-module-transforms": { "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", + "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", "dev": true, "license": "MIT", "dependencies": { @@ -6370,6 +1011,8 @@ }, "node_modules/@babel/helper-split-export-declaration": { "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", + "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", "dev": true, "license": "MIT", "dependencies": { @@ -6381,6 +1024,8 @@ }, "node_modules/@babel/helper-string-parser": { "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", "dev": true, "license": "MIT", "engines": { @@ -6389,6 +1034,8 @@ }, "node_modules/@babel/helper-validator-identifier": { "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", "dev": true, "license": "MIT", "engines": { @@ -6397,6 +1044,8 @@ }, "node_modules/@babel/helper-validator-option": { "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", "dev": true, "license": "MIT", "engines": { @@ -6405,6 +1054,8 @@ }, "node_modules/@babel/helpers": { "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", + "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", "dev": true, "license": "MIT", "dependencies": { @@ -6417,6 +1068,8 @@ }, "node_modules/@babel/parser": { "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz", + "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", "dev": true, "license": "MIT", "dependencies": { @@ -6431,6 +1084,8 @@ }, "node_modules/@babel/template": { "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", "dev": true, "license": "MIT", "dependencies": { @@ -6444,6 +1099,8 @@ }, "node_modules/@babel/traverse": { "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz", + "integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==", "dev": true, "license": "MIT", "dependencies": { @@ -6461,6 +1118,8 @@ }, "node_modules/@babel/types": { "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz", + "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==", "dev": true, "license": "MIT", "dependencies": { @@ -6473,6 +1132,8 @@ }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", "dev": true, "license": "MIT", "dependencies": { @@ -6484,6 +1145,8 @@ }, "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", "dev": true, "license": "MIT", "dependencies": { @@ -6491,8 +1154,282 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz", + "integrity": "sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.9.tgz", + "integrity": "sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.9.tgz", + "integrity": "sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.9.tgz", + "integrity": "sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.9.tgz", + "integrity": "sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.9.tgz", + "integrity": "sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.9.tgz", + "integrity": "sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.9.tgz", + "integrity": "sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.9.tgz", + "integrity": "sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.9.tgz", + "integrity": "sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.9.tgz", + "integrity": "sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.9.tgz", + "integrity": "sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.9.tgz", + "integrity": "sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.9.tgz", + "integrity": "sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.9.tgz", + "integrity": "sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.9.tgz", + "integrity": "sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/linux-x64": { "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.9.tgz", + "integrity": "sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==", "cpu": [ "x64" ], @@ -6506,15 +1443,180 @@ "node": ">=18" } }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.9.tgz", + "integrity": "sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.9.tgz", + "integrity": "sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.9.tgz", + "integrity": "sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.9.tgz", + "integrity": "sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.9.tgz", + "integrity": "sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.9.tgz", + "integrity": "sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.9.tgz", + "integrity": "sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.9.tgz", + "integrity": "sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.9.tgz", + "integrity": "sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/ansi": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.1.tgz", + "integrity": "sha512-yqq0aJW/5XPhi5xOAL1xRCpe1eh8UFVgYFpFsjEqmIR8rKLyP+HINvFXwUaxYICflJrVlxnp7lLN6As735kVpw==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/@inquirer/checkbox": { - "version": "4.2.2", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.3.0.tgz", + "integrity": "sha512-5+Q3PKH35YsnoPTh75LucALdAxom6xh5D1oeY561x4cqBuH24ZFVyFREPe14xgnrtmGu3EEt1dIi60wRVSnGCw==", "devOptional": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.2.0", - "@inquirer/figures": "^1.0.13", - "@inquirer/type": "^3.0.8", - "ansi-escapes": "^4.3.2", + "@inquirer/ansi": "^1.0.1", + "@inquirer/core": "^10.3.0", + "@inquirer/figures": "^1.0.14", + "@inquirer/type": "^3.0.9", "yoctocolors-cjs": "^2.1.2" }, "engines": { @@ -6531,6 +1633,8 @@ }, "node_modules/@inquirer/confirm": { "version": "5.1.14", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.14.tgz", + "integrity": "sha512-5yR4IBfe0kXe59r1YCTG8WXkUbl7Z35HK87Sw+WUyGD8wNUx7JvY7laahzeytyE1oLn74bQnL7hstctQxisQ8Q==", "devOptional": true, "license": "MIT", "dependencies": { @@ -6550,13 +1654,15 @@ } }, "node_modules/@inquirer/core": { - "version": "10.2.0", + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.3.0.tgz", + "integrity": "sha512-Uv2aPPPSK5jeCplQmQ9xadnFx2Zhj9b5Dj7bU6ZeCdDNNY11nhYy4btcSdtDguHqCT2h5oNeQTcUNSGGLA7NTA==", "devOptional": true, "license": "MIT", "dependencies": { - "@inquirer/figures": "^1.0.13", - "@inquirer/type": "^3.0.8", - "ansi-escapes": "^4.3.2", + "@inquirer/ansi": "^1.0.1", + "@inquirer/figures": "^1.0.14", + "@inquirer/type": "^3.0.9", "cli-width": "^4.1.0", "mute-stream": "^2.0.0", "signal-exit": "^4.1.0", @@ -6576,13 +1682,15 @@ } }, "node_modules/@inquirer/editor": { - "version": "4.2.18", + "version": "4.2.21", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.21.tgz", + "integrity": "sha512-MjtjOGjr0Kh4BciaFShYpZ1s9400idOdvQ5D7u7lE6VztPFoyLcVNE5dXBmEEIQq5zi4B9h2kU+q7AVBxJMAkQ==", "devOptional": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.2.0", - "@inquirer/external-editor": "^1.0.1", - "@inquirer/type": "^3.0.8" + "@inquirer/core": "^10.3.0", + "@inquirer/external-editor": "^1.0.2", + "@inquirer/type": "^3.0.9" }, "engines": { "node": ">=18" @@ -6597,12 +1705,14 @@ } }, "node_modules/@inquirer/expand": { - "version": "4.0.18", + "version": "4.0.21", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.21.tgz", + "integrity": "sha512-+mScLhIcbPFmuvU3tAGBed78XvYHSvCl6dBiYMlzCLhpr0bzGzd8tfivMMeqND6XZiaZ1tgusbUHJEfc6YzOdA==", "devOptional": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.2.0", - "@inquirer/type": "^3.0.8", + "@inquirer/core": "^10.3.0", + "@inquirer/type": "^3.0.9", "yoctocolors-cjs": "^2.1.2" }, "engines": { @@ -6618,12 +1728,14 @@ } }, "node_modules/@inquirer/external-editor": { - "version": "1.0.1", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.2.tgz", + "integrity": "sha512-yy9cOoBnx58TlsPrIxauKIFQTiyH+0MK4e97y4sV9ERbI+zDxw7i2hxHLCIEGIE/8PPvDxGhgzIOTSOWcs6/MQ==", "devOptional": true, "license": "MIT", "dependencies": { "chardet": "^2.1.0", - "iconv-lite": "^0.6.3" + "iconv-lite": "^0.7.0" }, "engines": { "node": ">=18" @@ -6638,7 +1750,9 @@ } }, "node_modules/@inquirer/figures": { - "version": "1.0.13", + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.14.tgz", + "integrity": "sha512-DbFgdt+9/OZYFM+19dbpXOSeAstPy884FPy1KjDu4anWwymZeOYhMY1mdFri172htv6mvc/uvIAAi7b7tvjJBQ==", "devOptional": true, "license": "MIT", "engines": { @@ -6646,12 +1760,14 @@ } }, "node_modules/@inquirer/input": { - "version": "4.2.2", + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.2.5.tgz", + "integrity": "sha512-7GoWev7P6s7t0oJbenH0eQ0ThNdDJbEAEtVt9vsrYZ9FulIokvd823yLyhQlWHJPGce1wzP53ttfdCZmonMHyA==", "devOptional": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.2.0", - "@inquirer/type": "^3.0.8" + "@inquirer/core": "^10.3.0", + "@inquirer/type": "^3.0.9" }, "engines": { "node": ">=18" @@ -6666,12 +1782,14 @@ } }, "node_modules/@inquirer/number": { - "version": "3.0.18", + "version": "3.0.21", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.21.tgz", + "integrity": "sha512-5QWs0KGaNMlhbdhOSCFfKsW+/dcAVC2g4wT/z2MCiZM47uLgatC5N20kpkDQf7dHx+XFct/MJvvNGy6aYJn4Pw==", "devOptional": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.2.0", - "@inquirer/type": "^3.0.8" + "@inquirer/core": "^10.3.0", + "@inquirer/type": "^3.0.9" }, "engines": { "node": ">=18" @@ -6686,13 +1804,15 @@ } }, "node_modules/@inquirer/password": { - "version": "4.0.18", + "version": "4.0.21", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.21.tgz", + "integrity": "sha512-xxeW1V5SbNFNig2pLfetsDb0svWlKuhmr7MPJZMYuDnCTkpVBI+X/doudg4pznc1/U+yYmWFFOi4hNvGgUo7EA==", "devOptional": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.2.0", - "@inquirer/type": "^3.0.8", - "ansi-escapes": "^4.3.2" + "@inquirer/ansi": "^1.0.1", + "@inquirer/core": "^10.3.0", + "@inquirer/type": "^3.0.9" }, "engines": { "node": ">=18" @@ -6708,8 +1828,11 @@ }, "node_modules/@inquirer/prompts": { "version": "7.8.2", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.8.2.tgz", + "integrity": "sha512-nqhDw2ZcAUrKNPwhjinJny903bRhI0rQhiDz1LksjeRxqa36i3l75+4iXbOy0rlDpLJGxqtgoPavQjmmyS5UJw==", "devOptional": true, "license": "MIT", + "peer": true, "dependencies": { "@inquirer/checkbox": "^4.2.1", "@inquirer/confirm": "^5.1.14", @@ -6735,12 +1858,14 @@ } }, "node_modules/@inquirer/rawlist": { - "version": "4.1.6", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.9.tgz", + "integrity": "sha512-AWpxB7MuJrRiSfTKGJ7Y68imYt8P9N3Gaa7ySdkFj1iWjr6WfbGAhdZvw/UnhFXTHITJzxGUI9k8IX7akAEBCg==", "devOptional": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.2.0", - "@inquirer/type": "^3.0.8", + "@inquirer/core": "^10.3.0", + "@inquirer/type": "^3.0.9", "yoctocolors-cjs": "^2.1.2" }, "engines": { @@ -6756,13 +1881,15 @@ } }, "node_modules/@inquirer/search": { - "version": "3.1.1", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.2.0.tgz", + "integrity": "sha512-a5SzB/qrXafDX1Z4AZW3CsVoiNxcIYCzYP7r9RzrfMpaLpB+yWi5U8BWagZyLmwR0pKbbL5umnGRd0RzGVI8bQ==", "devOptional": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.2.0", - "@inquirer/figures": "^1.0.13", - "@inquirer/type": "^3.0.8", + "@inquirer/core": "^10.3.0", + "@inquirer/figures": "^1.0.14", + "@inquirer/type": "^3.0.9", "yoctocolors-cjs": "^2.1.2" }, "engines": { @@ -6778,14 +1905,16 @@ } }, "node_modules/@inquirer/select": { - "version": "4.3.2", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.4.0.tgz", + "integrity": "sha512-kaC3FHsJZvVyIjYBs5Ih8y8Bj4P/QItQWrZW22WJax7zTN+ZPXVGuOM55vzbdCP9zKUiBd9iEJVdesujfF+cAA==", "devOptional": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.2.0", - "@inquirer/figures": "^1.0.13", - "@inquirer/type": "^3.0.8", - "ansi-escapes": "^4.3.2", + "@inquirer/ansi": "^1.0.1", + "@inquirer/core": "^10.3.0", + "@inquirer/figures": "^1.0.14", + "@inquirer/type": "^3.0.9", "yoctocolors-cjs": "^2.1.2" }, "engines": { @@ -6801,7 +1930,9 @@ } }, "node_modules/@inquirer/type": { - "version": "3.0.8", + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.9.tgz", + "integrity": "sha512-QPaNt/nmE2bLGQa9b7wwyRJoLZ7pN6rcyXvzU0YCmivmJyq1BVo94G98tStRWkoD1RgDX5C+dPlhhHzNdu/W/w==", "devOptional": true, "license": "MIT", "engines": { @@ -6818,6 +1949,8 @@ }, "node_modules/@isaacs/balanced-match": { "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", + "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", "devOptional": true, "license": "MIT", "engines": { @@ -6826,6 +1959,8 @@ }, "node_modules/@isaacs/brace-expansion": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", + "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -6837,6 +1972,8 @@ }, "node_modules/@isaacs/cliui": { "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", "devOptional": true, "license": "ISC", "dependencies": { @@ -6853,11 +1990,15 @@ }, "node_modules/@isaacs/cliui/node_modules/emoji-regex": { "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "devOptional": true, "license": "MIT" }, "node_modules/@isaacs/cliui/node_modules/string-width": { "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -6874,6 +2015,8 @@ }, "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "devOptional": true, "license": "MIT", "dependencies": { @@ -6890,6 +2033,8 @@ }, "node_modules/@isaacs/fs-minipass": { "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", "devOptional": true, "license": "ISC", "dependencies": { @@ -6901,6 +2046,8 @@ }, "node_modules/@istanbuljs/schema": { "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", "dev": true, "license": "MIT", "engines": { @@ -6909,6 +2056,8 @@ }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", "dev": true, "license": "MIT", "dependencies": { @@ -6918,6 +2067,8 @@ }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, "license": "MIT", "engines": { @@ -6926,10 +2077,14 @@ }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.30", + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "dev": true, "license": "MIT", "dependencies": { @@ -6939,6 +2094,8 @@ }, "node_modules/@listr2/prompt-adapter-inquirer": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@listr2/prompt-adapter-inquirer/-/prompt-adapter-inquirer-3.0.1.tgz", + "integrity": "sha512-3XFmGwm3u6ioREG+ynAQB7FoxfajgQnMhIu8wC5eo/Lsih4aKDg0VuIMGaOsYn7hJSJagSeaD4K8yfpkEoDEmA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -6952,8 +2109,66 @@ "listr2": "9.0.1" } }, + "node_modules/@lmdb/lmdb-darwin-arm64": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-3.4.2.tgz", + "integrity": "sha512-NK80WwDoODyPaSazKbzd3NEJ3ygePrkERilZshxBViBARNz21rmediktGHExoj9n5t9+ChlgLlxecdFKLCuCKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@lmdb/lmdb-darwin-x64": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-3.4.2.tgz", + "integrity": "sha512-zevaowQNmrp3U7Fz1s9pls5aIgpKRsKb3dZWDINtLiozh3jZI9fBrI19lYYBxqdyiIyNdlyiidPnwPShj4aK+w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@lmdb/lmdb-linux-arm": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-3.4.2.tgz", + "integrity": "sha512-OmHCULY17rkx/RoCoXlzU7LyR8xqrksgdYWwtYa14l/sseezZ8seKWXcogHcjulBddER5NnEFV4L/Jtr2nyxeg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@lmdb/lmdb-linux-arm64": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-3.4.2.tgz", + "integrity": "sha512-ZBEfbNZdkneebvZs98Lq30jMY8V9IJzckVeigGivV7nTHJc+89Ctomp1kAIWKlwIG0ovCDrFI448GzFPORANYg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/@lmdb/lmdb-linux-x64": { "version": "3.4.2", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-3.4.2.tgz", + "integrity": "sha512-vL9nM17C77lohPYE4YaAQvfZCSVJSryE4fXdi8M7uWPBnU+9DJabgKVAeyDb84ZM2vcFseoBE4/AagVtJeRE7g==", "cpu": [ "x64" ], @@ -6964,8 +2179,38 @@ "linux" ] }, + "node_modules/@lmdb/lmdb-win32-arm64": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-arm64/-/lmdb-win32-arm64-3.4.2.tgz", + "integrity": "sha512-SXWjdBfNDze4ZPeLtYIzsIeDJDJ/SdsA0pEXcUBayUIMO0FQBHfVZZyHXQjjHr4cvOAzANBgIiqaXRwfMhzmLw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@lmdb/lmdb-win32-x64": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-3.4.2.tgz", + "integrity": "sha512-IY+r3bxKW6Q6sIPiMC0L533DEfRJSXibjSI3Ft/w9Q8KQBNqEIvUFXt+09wV8S5BRk0a8uSF19YWxuRwEfI90g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@maskito/angular": { - "version": "3.10.3", + "version": "3.11.1", + "resolved": "https://registry.npmjs.org/@maskito/angular/-/angular-3.11.1.tgz", + "integrity": "sha512-+OZzbRJj/9fOGhgPr0xYctSHe/Ngahip3VdNWBslRTpt7g+UTBYcB8vU9J4cHfpdXYeLM3tM0tnKksc3Eis0+Q==", "license": "Apache-2.0", "peer": true, "dependencies": { @@ -6974,34 +2219,42 @@ "peerDependencies": { "@angular/core": ">=16.0.0", "@angular/forms": ">=16.0.0", - "@maskito/core": "^3.10.3" + "@maskito/core": "^3.11.1" } }, "node_modules/@maskito/core": { - "version": "3.10.3", + "version": "3.11.1", + "resolved": "https://registry.npmjs.org/@maskito/core/-/core-3.11.1.tgz", + "integrity": "sha512-zN5k/BiZXblo8mEFhsGnnXBCqKMkjEGArorOOcpB1/ymZyqF12Dk6IipEsSE6abMnWw4YF2tukzfq73BFZKz8A==", "license": "Apache-2.0", "peer": true }, "node_modules/@maskito/kit": { - "version": "3.10.3", + "version": "3.11.1", + "resolved": "https://registry.npmjs.org/@maskito/kit/-/kit-3.11.1.tgz", + "integrity": "sha512-KOBUqxRz383xJWCoe+Emwxv2oAzUrZobIN+Gntmi5Py2S10XbqYnGX/6W7QHN8CUK2Nx11d3HsxbEQaq5Hinjg==", "license": "Apache-2.0", "peer": true, "peerDependencies": { - "@maskito/core": "^3.10.3" + "@maskito/core": "^3.11.1" } }, "node_modules/@maskito/phone": { - "version": "3.10.3", + "version": "3.11.1", + "resolved": "https://registry.npmjs.org/@maskito/phone/-/phone-3.11.1.tgz", + "integrity": "sha512-ptNDPIZQs/v598qydBa9cnvoCE8+k2Sv07kKKVx3vG0V40DQnIlEL+LYKrJJbMIiPOB6CH90hB9eaA9KKReZ6w==", "license": "Apache-2.0", "peer": true, "peerDependencies": { - "@maskito/core": "^3.10.3", - "@maskito/kit": "^3.10.3", + "@maskito/core": "^3.11.1", + "@maskito/kit": "^3.11.1", "libphonenumber-js": ">=1.0.0" } }, "node_modules/@materia-ui/ngx-monaco-editor": { "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@materia-ui/ngx-monaco-editor/-/ngx-monaco-editor-6.0.0.tgz", + "integrity": "sha512-gTqNQjOGznZxOC0NlmKdKSGCJuTts8YmK4dsTQAGc5IgIV7cZdQWiW6AL742h0ruED6q0cAunEYjXT6jzHBoIQ==", "license": "MIT", "dependencies": { "tslib": "^2.0.0" @@ -7013,6 +2266,8 @@ }, "node_modules/@modelcontextprotocol/sdk": { "version": "1.17.3", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.17.3.tgz", + "integrity": "sha512-JPwUKWSsbzx+DLFznf/QZ32Qa+ptfbUlHhRLrBQBAFu9iI1iYvizM4p+zhhRDceSsPutXp4z+R/HPVphlIiclg==", "devOptional": true, "license": "MIT", "dependencies": { @@ -7035,6 +2290,8 @@ }, "node_modules/@modelcontextprotocol/sdk/node_modules/ajv": { "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "devOptional": true, "license": "MIT", "dependencies": { @@ -7050,11 +2307,71 @@ }, "node_modules/@modelcontextprotocol/sdk/node_modules/json-schema-traverse": { "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "devOptional": true, "license": "MIT" }, + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.3.tgz", + "integrity": "sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-x64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.3.tgz", + "integrity": "sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.3.tgz", + "integrity": "sha512-fg0uy/dG/nZEXfYilKoRe7yALaNmHoYeIoJuJ7KJ+YyU2bvY8vPv27f7UKhGRpY6euFYqEVhxCFZgAUNQBM3nw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.3.tgz", + "integrity": "sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": { "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.3.tgz", + "integrity": "sha512-cvwNfbP07pKUfq1uH+S6KJ7dT9K8WOE4ZiAcsrSes+UY55E/0jLYc+vq+DO7jlmqRb5zAggExKm0H7O/CBaesg==", "cpu": [ "x64" ], @@ -7065,8 +2382,24 @@ "linux" ] }, + "node_modules/@msgpackr-extract/msgpackr-extract-win32-x64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.3.tgz", + "integrity": "sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@napi-rs/nice": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice/-/nice-1.1.1.tgz", + "integrity": "sha512-xJIPs+bYuc9ASBl+cvGsKbGrJmS6fAKaSZCnT0lhahT5rhA2VVy9/EcIgd2JhtEuFOJNx7UHNn/qiTPTY4nrQw==", "dev": true, "license": "MIT", "optional": true, @@ -7097,8 +2430,197 @@ "@napi-rs/nice-win32-x64-msvc": "1.1.1" } }, + "node_modules/@napi-rs/nice-android-arm-eabi": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-android-arm-eabi/-/nice-android-arm-eabi-1.1.1.tgz", + "integrity": "sha512-kjirL3N6TnRPv5iuHw36wnucNqXAO46dzK9oPb0wj076R5Xm8PfUVA9nAFB5ZNMmfJQJVKACAPd/Z2KYMppthw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-android-arm64": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-android-arm64/-/nice-android-arm64-1.1.1.tgz", + "integrity": "sha512-blG0i7dXgbInN5urONoUCNf+DUEAavRffrO7fZSeoRMJc5qD+BJeNcpr54msPF6qfDD6kzs9AQJogZvT2KD5nw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-darwin-arm64": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-darwin-arm64/-/nice-darwin-arm64-1.1.1.tgz", + "integrity": "sha512-s/E7w45NaLqTGuOjC2p96pct4jRfo61xb9bU1unM/MJ/RFkKlJyJDx7OJI/O0ll/hrfpqKopuAFDV8yo0hfT7A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-darwin-x64": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-darwin-x64/-/nice-darwin-x64-1.1.1.tgz", + "integrity": "sha512-dGoEBnVpsdcC+oHHmW1LRK5eiyzLwdgNQq3BmZIav+9/5WTZwBYX7r5ZkQC07Nxd3KHOCkgbHSh4wPkH1N1LiQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-freebsd-x64": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-freebsd-x64/-/nice-freebsd-x64-1.1.1.tgz", + "integrity": "sha512-kHv4kEHAylMYmlNwcQcDtXjklYp4FCf0b05E+0h6nDHsZ+F0bDe04U/tXNOqrx5CmIAth4vwfkjjUmp4c4JktQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-arm-gnueabihf": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm-gnueabihf/-/nice-linux-arm-gnueabihf-1.1.1.tgz", + "integrity": "sha512-E1t7K0efyKXZDoZg1LzCOLxgolxV58HCkaEkEvIYQx12ht2pa8hoBo+4OB3qh7e+QiBlp1SRf+voWUZFxyhyqg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-arm64-gnu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm64-gnu/-/nice-linux-arm64-gnu-1.1.1.tgz", + "integrity": "sha512-CIKLA12DTIZlmTaaKhQP88R3Xao+gyJxNWEn04wZwC2wmRapNnxCUZkVwggInMJvtVElA+D4ZzOU5sX4jV+SmQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-arm64-musl": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm64-musl/-/nice-linux-arm64-musl-1.1.1.tgz", + "integrity": "sha512-+2Rzdb3nTIYZ0YJF43qf2twhqOCkiSrHx2Pg6DJaCPYhhaxbLcdlV8hCRMHghQ+EtZQWGNcS2xF4KxBhSGeutg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-ppc64-gnu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-ppc64-gnu/-/nice-linux-ppc64-gnu-1.1.1.tgz", + "integrity": "sha512-4FS8oc0GeHpwvv4tKciKkw3Y4jKsL7FRhaOeiPei0X9T4Jd619wHNe4xCLmN2EMgZoeGg+Q7GY7BsvwKpL22Tg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-riscv64-gnu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-riscv64-gnu/-/nice-linux-riscv64-gnu-1.1.1.tgz", + "integrity": "sha512-HU0nw9uD4FO/oGCCk409tCi5IzIZpH2agE6nN4fqpwVlCn5BOq0MS1dXGjXaG17JaAvrlpV5ZeyZwSon10XOXw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-s390x-gnu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-s390x-gnu/-/nice-linux-s390x-gnu-1.1.1.tgz", + "integrity": "sha512-2YqKJWWl24EwrX0DzCQgPLKQBxYDdBxOHot1KWEq7aY2uYeX+Uvtv4I8xFVVygJDgf6/92h9N3Y43WPx8+PAgQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, "node_modules/@napi-rs/nice-linux-x64-gnu": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-x64-gnu/-/nice-linux-x64-gnu-1.1.1.tgz", + "integrity": "sha512-/gaNz3R92t+dcrfCw/96pDopcmec7oCcAQ3l/M+Zxr82KT4DljD37CpgrnXV+pJC263JkW572pdbP3hP+KjcIg==", "cpu": [ "x64" ], @@ -7114,6 +2636,8 @@ }, "node_modules/@napi-rs/nice-linux-x64-musl": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-x64-musl/-/nice-linux-x64-musl-1.1.1.tgz", + "integrity": "sha512-xScCGnyj/oppsNPMnevsBe3pvNaoK7FGvMjT35riz9YdhB2WtTG47ZlbxtOLpjeO9SqqQ2J2igCmz6IJOD5JYw==", "cpu": [ "x64" ], @@ -7127,8 +2651,78 @@ "node": ">= 10" } }, + "node_modules/@napi-rs/nice-openharmony-arm64": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-openharmony-arm64/-/nice-openharmony-arm64-1.1.1.tgz", + "integrity": "sha512-6uJPRVwVCLDeoOaNyeiW0gp2kFIM4r7PL2MczdZQHkFi9gVlgm+Vn+V6nTWRcu856mJ2WjYJiumEajfSm7arPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-win32-arm64-msvc": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-arm64-msvc/-/nice-win32-arm64-msvc-1.1.1.tgz", + "integrity": "sha512-uoTb4eAvM5B2aj/z8j+Nv8OttPf2m+HVx3UjA5jcFxASvNhQriyCQF1OB1lHL43ZhW+VwZlgvjmP5qF3+59atA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-win32-ia32-msvc": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-ia32-msvc/-/nice-win32-ia32-msvc-1.1.1.tgz", + "integrity": "sha512-CNQqlQT9MwuCsg1Vd/oKXiuH+TcsSPJmlAFc5frFyX/KkOh0UpBLEj7aoY656d5UKZQMQFP7vJNa1DNUNORvug==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-win32-x64-msvc": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-x64-msvc/-/nice-win32-x64-msvc-1.1.1.tgz", + "integrity": "sha512-vB+4G/jBQCAh0jelMTY3+kgFy00Hlx2f2/1zjMoH821IbplbWZOkLiTYXQkygNTzQJTq5cvwBDgn2ppHD+bglQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, "node_modules/@ng-web-apis/common": { - "version": "4.12.0", + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@ng-web-apis/common/-/common-4.12.2.tgz", + "integrity": "sha512-fjmSpJfu+3i7i/+2U38owTTxoi8EoANQJVaIGmNymyF8EmSrbVCcPP6CXsZ6UsHJwE8IWso7h0cN6kBUqWERfw==", "license": "Apache-2.0", "peer": true, "dependencies": { @@ -7141,7 +2735,9 @@ } }, "node_modules/@ng-web-apis/intersection-observer": { - "version": "4.12.0", + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@ng-web-apis/intersection-observer/-/intersection-observer-4.12.2.tgz", + "integrity": "sha512-hE2jBuRpn/FBcbOZuYwMG/uGW4Y7T+T0g3MiY3eCY+YSZQ5wWtzHdkj8bpdAaAUbHuKJuxtzQG68uMd8yVUMMg==", "license": "Apache-2.0", "peer": true, "dependencies": { @@ -7153,7 +2749,9 @@ } }, "node_modules/@ng-web-apis/mutation-observer": { - "version": "4.12.0", + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@ng-web-apis/mutation-observer/-/mutation-observer-4.12.2.tgz", + "integrity": "sha512-LEbtahyyBp/LhPgxAsjY3G75bqeWmBTMHYiMH4kHa8/ExH0LSKplB/X9nadUJ9YdMQ8d/DDC9cxQvIozOzcyRA==", "license": "Apache-2.0", "peer": true, "dependencies": { @@ -7165,7 +2763,9 @@ } }, "node_modules/@ng-web-apis/platform": { - "version": "4.12.0", + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@ng-web-apis/platform/-/platform-4.12.2.tgz", + "integrity": "sha512-HO2nm1us87iiOntXwEGv1D5L1kQ4luJlOcWnCPjEwiWE4vxANDis/MnYvJAcwAUQRNikXw8BjgAEo3aWafxDhA==", "license": "Apache-2.0", "peer": true, "dependencies": { @@ -7173,7 +2773,9 @@ } }, "node_modules/@ng-web-apis/resize-observer": { - "version": "4.12.0", + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@ng-web-apis/resize-observer/-/resize-observer-4.12.2.tgz", + "integrity": "sha512-ogthPEuHRBaJCXv/Df8GCqag52WkKziKx4l/+jp2jmaxKHWtmzW59Ftb7HFfoCzmkb+tVlVdC3EwFyldax2eyw==", "license": "Apache-2.0", "peer": true, "dependencies": { @@ -7185,7 +2787,9 @@ } }, "node_modules/@ng-web-apis/screen-orientation": { - "version": "4.12.0", + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@ng-web-apis/screen-orientation/-/screen-orientation-4.12.2.tgz", + "integrity": "sha512-8ZKFrfu0/7coUECmqi+ppk/1lUfHi38N0msmKR+iZvVbDiZcaJhu2SptZEmEkR1pTykp1wbbKSSfdyDb3MK1hQ==", "license": "Apache-2.0", "peer": true, "dependencies": { @@ -7199,6 +2803,8 @@ }, "node_modules/@noble/curves": { "version": "1.9.7", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.7.tgz", + "integrity": "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==", "license": "MIT", "dependencies": { "@noble/hashes": "1.8.0" @@ -7212,6 +2818,8 @@ }, "node_modules/@noble/hashes": { "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", "license": "MIT", "engines": { "node": "^14.21.3 || >=16" @@ -7222,6 +2830,8 @@ }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "license": "MIT", "optional": true, "dependencies": { @@ -7234,6 +2844,8 @@ }, "node_modules/@nodelib/fs.stat": { "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "license": "MIT", "optional": true, "engines": { @@ -7242,6 +2854,8 @@ }, "node_modules/@nodelib/fs.walk": { "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "license": "MIT", "optional": true, "dependencies": { @@ -7254,6 +2868,8 @@ }, "node_modules/@npmcli/agent": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-3.0.0.tgz", + "integrity": "sha512-S79NdEgDQd/NGCay6TCoVzXSj74skRZIKJcpJjC5lOq34SZzyI6MqtiiWoiVWoVrTcGjNeC4ipbh1VIHlpfF5Q==", "devOptional": true, "license": "ISC", "dependencies": { @@ -7269,11 +2885,15 @@ }, "node_modules/@npmcli/agent/node_modules/lru-cache": { "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "devOptional": true, "license": "ISC" }, "node_modules/@npmcli/fs": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-4.0.0.tgz", + "integrity": "sha512-/xGlezI6xfGO9NwuJlnwz/K14qD1kCSAGtacBHnGzeAIuJGazcp45KP5NuyARXoKb7cwulAGWVsbeSxdG/cb0Q==", "devOptional": true, "license": "ISC", "dependencies": { @@ -7285,6 +2905,8 @@ }, "node_modules/@npmcli/git": { "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-6.0.3.tgz", + "integrity": "sha512-GUYESQlxZRAdhs3UhbB6pVRNUELQOHXwK9ruDkwmCv2aZ5y0SApQzUJCg02p3A7Ue2J5hxvlk1YI53c00NmRyQ==", "devOptional": true, "license": "ISC", "dependencies": { @@ -7303,6 +2925,8 @@ }, "node_modules/@npmcli/git/node_modules/isexe": { "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", "devOptional": true, "license": "ISC", "engines": { @@ -7311,11 +2935,15 @@ }, "node_modules/@npmcli/git/node_modules/lru-cache": { "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "devOptional": true, "license": "ISC" }, "node_modules/@npmcli/git/node_modules/which": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz", + "integrity": "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==", "devOptional": true, "license": "ISC", "dependencies": { @@ -7330,6 +2958,8 @@ }, "node_modules/@npmcli/installed-package-contents": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-3.0.0.tgz", + "integrity": "sha512-fkxoPuFGvxyrH+OQzyTkX2LUEamrF4jZSmxjAtPPHHGO0dqsQ8tTKjnIS8SAnPHdk2I03BDtSMR5K/4loKg79Q==", "devOptional": true, "license": "ISC", "dependencies": { @@ -7345,6 +2975,8 @@ }, "node_modules/@npmcli/node-gyp": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-4.0.0.tgz", + "integrity": "sha512-+t5DZ6mO/QFh78PByMq1fGSAub/agLJZDRfJRMeOSNCt8s9YVlTjmGpIPwPhvXTGUIJk+WszlT0rQa1W33yzNA==", "devOptional": true, "license": "ISC", "engines": { @@ -7353,6 +2985,8 @@ }, "node_modules/@npmcli/package-json": { "version": "6.2.0", + "resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-6.2.0.tgz", + "integrity": "sha512-rCNLSB/JzNvot0SEyXqWZ7tX2B5dD2a1br2Dp0vSYVo5jh8Z0EZ7lS9TsZ1UtziddB1UfNUaMCc538/HztnJGA==", "devOptional": true, "license": "ISC", "dependencies": { @@ -7370,6 +3004,8 @@ }, "node_modules/@npmcli/package-json/node_modules/hosted-git-info": { "version": "8.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-8.1.0.tgz", + "integrity": "sha512-Rw/B2DNQaPBICNXEm8balFz9a6WpZrkCGpcWFpy7nCj+NyhSdqXipmfvtmWt9xGfp0wZnBxB+iVpLmQMYt47Tw==", "devOptional": true, "license": "ISC", "dependencies": { @@ -7381,11 +3017,15 @@ }, "node_modules/@npmcli/package-json/node_modules/lru-cache": { "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "devOptional": true, "license": "ISC" }, "node_modules/@npmcli/promise-spawn": { "version": "8.0.3", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-8.0.3.tgz", + "integrity": "sha512-Yb00SWaL4F8w+K8YGhQ55+xE4RUNdMHV43WZGsiTM92gS+lC0mGsn7I4hLug7pbao035S6bj3Y3w0cUNGLfmkg==", "devOptional": true, "license": "ISC", "dependencies": { @@ -7397,6 +3037,8 @@ }, "node_modules/@npmcli/promise-spawn/node_modules/isexe": { "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", "devOptional": true, "license": "ISC", "engines": { @@ -7405,6 +3047,8 @@ }, "node_modules/@npmcli/promise-spawn/node_modules/which": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz", + "integrity": "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==", "devOptional": true, "license": "ISC", "dependencies": { @@ -7419,6 +3063,8 @@ }, "node_modules/@npmcli/redact": { "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@npmcli/redact/-/redact-3.2.2.tgz", + "integrity": "sha512-7VmYAmk4csGv08QzrDKScdzn11jHPFGyqJW39FyPgPuAp3zIaUmuCo1yxw9aGs+NEJuTGQ9Gwqpt93vtJubucg==", "devOptional": true, "license": "ISC", "engines": { @@ -7427,6 +3073,8 @@ }, "node_modules/@npmcli/run-script": { "version": "9.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-9.1.0.tgz", + "integrity": "sha512-aoNSbxtkePXUlbZB+anS1LqsJdctG5n3UVhfU47+CDdwMi6uNTBMF9gPcQRnqghQd2FGzcwwIFBruFMxjhBewg==", "devOptional": true, "license": "ISC", "dependencies": { @@ -7443,6 +3091,8 @@ }, "node_modules/@npmcli/run-script/node_modules/isexe": { "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", "devOptional": true, "license": "ISC", "engines": { @@ -7451,6 +3101,8 @@ }, "node_modules/@npmcli/run-script/node_modules/which": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz", + "integrity": "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==", "devOptional": true, "license": "ISC", "dependencies": { @@ -7463,24 +3115,10 @@ "node": "^18.17.0 || >=20.5.0" } }, - "node_modules/@oxc-project/runtime": { - "version": "0.81.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@oxc-project/types": { - "version": "0.81.0", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/Boshen" - } - }, "node_modules/@parcel/watcher": { "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz", + "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -7514,8 +3152,178 @@ "@parcel/watcher-win32-x64": "2.5.1" } }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz", + "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz", + "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz", + "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz", + "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz", + "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz", + "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz", + "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz", + "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, "node_modules/@parcel/watcher-linux-x64-glibc": { "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz", + "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==", "cpu": [ "x64" ], @@ -7535,6 +3343,8 @@ }, "node_modules/@parcel/watcher-linux-x64-musl": { "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz", + "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==", "cpu": [ "x64" ], @@ -7552,8 +3362,73 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz", + "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz", + "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz", + "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, "node_modules/@parcel/watcher/node_modules/detect-libc": { "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", "dev": true, "license": "Apache-2.0", "optional": true, @@ -7566,12 +3441,16 @@ }, "node_modules/@parcel/watcher/node_modules/node-addon-api": { "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", "dev": true, "license": "MIT", "optional": true }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", "dev": true, "license": "MIT", "optional": true, @@ -7579,37 +3458,10 @@ "node": ">=14" } }, - "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.0.0-beta.32", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.0.0-beta.32", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.32", - "dev": true, - "license": "MIT" - }, "node_modules/@rollup/plugin-json": { "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-6.1.0.tgz", + "integrity": "sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==", "dev": true, "license": "MIT", "dependencies": { @@ -7629,6 +3481,8 @@ }, "node_modules/@rollup/pluginutils": { "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", + "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", "dev": true, "license": "MIT", "dependencies": { @@ -7650,11 +3504,225 @@ }, "node_modules/@rollup/pluginutils/node_modules/@types/estree": { "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", "dev": true, "license": "MIT" }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.52.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.3.tgz", + "integrity": "sha512-h6cqHGZ6VdnwliFG1NXvMPTy/9PS3h8oLh7ImwR+kl+oYnQizgjxsONmmPSb2C66RksfkfIxEVtDSEcJiO0tqw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.52.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.3.tgz", + "integrity": "sha512-wd+u7SLT/u6knklV/ifG7gr5Qy4GUbH2hMWcDauPFJzmCZUAJ8L2bTkVXC2niOIxp8lk3iH/QX8kSrUxVZrOVw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.52.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.3.tgz", + "integrity": "sha512-lj9ViATR1SsqycwFkJCtYfQTheBdvlWJqzqxwc9f2qrcVrQaF/gCuBRTiTolkRWS6KvNxSk4KHZWG7tDktLgjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.52.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.3.tgz", + "integrity": "sha512-+Dyo7O1KUmIsbzx1l+4V4tvEVnVQqMOIYtrxK7ncLSknl1xnMHLgn7gddJVrYPNZfEB8CIi3hK8gq8bDhb3h5A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.52.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.3.tgz", + "integrity": "sha512-u9Xg2FavYbD30g3DSfNhxgNrxhi6xVG4Y6i9Ur1C7xUuGDW3banRbXj+qgnIrwRN4KeJ396jchwy9bCIzbyBEQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.52.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.3.tgz", + "integrity": "sha512-5M8kyi/OX96wtD5qJR89a/3x5x8x5inXBZO04JWhkQb2JWavOWfjgkdvUqibGJeNNaz1/Z1PPza5/tAPXICI6A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.52.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.3.tgz", + "integrity": "sha512-IoerZJ4l1wRMopEHRKOO16e04iXRDyZFZnNZKrWeNquh5d6bucjezgd+OxG03mOMTnS1x7hilzb3uURPkJ0OfA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.52.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.3.tgz", + "integrity": "sha512-ZYdtqgHTDfvrJHSh3W22TvjWxwOgc3ThK/XjgcNGP2DIwFIPeAPNsQxrJO5XqleSlgDux2VAoWQ5iJrtaC1TbA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.52.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.3.tgz", + "integrity": "sha512-NcViG7A0YtuFDA6xWSgmFb6iPFzHlf5vcqb2p0lGEbT+gjrEEz8nC/EeDHvx6mnGXnGCC1SeVV+8u+smj0CeGQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.52.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.3.tgz", + "integrity": "sha512-d3pY7LWno6SYNXRm6Ebsq0DJGoiLXTb83AIPCXl9fmtIQs/rXoS8SJxxUNtFbJ5MiOvs+7y34np77+9l4nfFMw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.52.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.3.tgz", + "integrity": "sha512-3y5GA0JkBuirLqmjwAKwB0keDlI6JfGYduMlJD/Rl7fvb4Ni8iKdQs1eiunMZJhwDWdCvrcqXRY++VEBbvk6Eg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.52.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.3.tgz", + "integrity": "sha512-AUUH65a0p3Q0Yfm5oD2KVgzTKgwPyp9DSXc3UA7DtxhEb/WSPfbG4wqXeSN62OG5gSo18em4xv6dbfcUGXcagw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.52.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.3.tgz", + "integrity": "sha512-1makPhFFVBqZE+XFg3Dkq+IkQ7JvmUrwwqaYBL2CE+ZpxPaqkGaiWFEWVGyvTwZace6WLJHwjVh/+CXbKDGPmg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.52.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.3.tgz", + "integrity": "sha512-OOFJa28dxfl8kLOPMUOQBCO6z3X2SAfzIE276fwT52uXDWUS178KWq0pL7d6p1kz7pkzA0yQwtqL0dEPoVcRWg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.52.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.3.tgz", + "integrity": "sha512-jMdsML2VI5l+V7cKfZx3ak+SLlJ8fKvLJ0Eoa4b9/vCUrzXKgoKxvHqvJ/mkWhFiyp88nCkM5S2v6nIwRtPcgg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.50.1", + "version": "4.52.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.3.tgz", + "integrity": "sha512-tPgGd6bY2M2LJTA1uGq8fkSPK8ZLYjDjY+ZLK9WHncCnfIz29LIXIqUgzCR0hIefzy6Hpbe8Th5WOSwTM8E7LA==", "cpu": [ "x64" ], @@ -7666,7 +3734,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.50.1", + "version": "4.52.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.3.tgz", + "integrity": "sha512-BCFkJjgk+WFzP+tcSMXq77ymAPIxsX9lFJWs+2JzuZTLtksJ2o5hvgTdIcZ5+oKzUDMwI0PfWzRBYAydAHF2Mw==", "cpu": [ "x64" ], @@ -7677,8 +3747,80 @@ "linux" ] }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.52.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.3.tgz", + "integrity": "sha512-KTD/EqjZF3yvRaWUJdD1cW+IQBk4fbQaHYJUmP8N4XoKFZilVL8cobFSTDnjTtxWJQ3JYaMgF4nObY/+nYkumA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.52.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.3.tgz", + "integrity": "sha512-+zteHZdoUYLkyYKObGHieibUFLbttX2r+58l27XZauq0tcWYYuKUwY2wjeCN9oK1Um2YgH2ibd6cnX/wFD7DuA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.52.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.3.tgz", + "integrity": "sha512-of1iHkTQSo3kr6dTIRX6t81uj/c/b15HXVsPcEElN5sS859qHrOepM5p9G41Hah+CTqSh2r8Bm56dL2z9UQQ7g==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.52.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.3.tgz", + "integrity": "sha512-s0hybmlHb56mWVZQj8ra9048/WZTPLILKxcvcq+8awSZmyiSUZjjem1AhU3Tf4ZKpYhK4mg36HtHDOe8QJS5PQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.52.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.3.tgz", + "integrity": "sha512-zGIbEVVXVtauFgl3MRwGWEN36P5ZGenHRMgNw88X5wEhEBpq0XrMEZwOn07+ICrwM17XO5xfMZqh0OldCH5VTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@rollup/wasm-node": { - "version": "4.50.1", + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/wasm-node/-/wasm-node-4.52.5.tgz", + "integrity": "sha512-ldY4tEzSMBHNwB8TfRpi7RRRjjyfKlwjdebw5pS1lu0xaY3g4RDc6ople2wEYulVOKVeH7ZJwRx0iw4pGtjMHg==", "dev": true, "license": "MIT", "dependencies": { @@ -7697,15 +3839,19 @@ }, "node_modules/@rollup/wasm-node/node_modules/@types/estree": { "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", "dev": true, "license": "MIT" }, "node_modules/@schematics/angular": { - "version": "20.2.2", + "version": "20.3.7", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-20.3.7.tgz", + "integrity": "sha512-jR2LPJVGK6yzPTNXkGJZYtdeLGkNdqJhVow2E+ILt3pk/LZuT/iSdr9V4nArU9yysifGuJFTyZapVOYkEYaykg==", "license": "MIT", "dependencies": { - "@angular-devkit/core": "20.2.2", - "@angular-devkit/schematics": "20.2.2", + "@angular-devkit/core": "20.3.7", + "@angular-devkit/schematics": "20.3.7", "jsonc-parser": "3.3.1" }, "engines": { @@ -7716,6 +3862,8 @@ }, "node_modules/@sigstore/bundle": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-3.1.0.tgz", + "integrity": "sha512-Mm1E3/CmDDCz3nDhFKTuYdB47EdRFRQMOE/EAbiG1MJW77/w1b3P7Qx7JSrVJs8PfwOLOVcKQCHErIwCTyPbag==", "devOptional": true, "license": "Apache-2.0", "dependencies": { @@ -7727,6 +3875,8 @@ }, "node_modules/@sigstore/core": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sigstore/core/-/core-2.0.0.tgz", + "integrity": "sha512-nYxaSb/MtlSI+JWcwTHQxyNmWeWrUXJJ/G4liLrGG7+tS4vAz6LF3xRXqLH6wPIVUoZQel2Fs4ddLx4NCpiIYg==", "devOptional": true, "license": "Apache-2.0", "engines": { @@ -7735,6 +3885,8 @@ }, "node_modules/@sigstore/protobuf-specs": { "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.4.3.tgz", + "integrity": "sha512-fk2zjD9117RL9BjqEwF7fwv7Q/P9yGsMV4MUJZ/DocaQJ6+3pKr+syBq1owU5Q5qGw5CUbXzm+4yJ2JVRDQeSA==", "devOptional": true, "license": "Apache-2.0", "engines": { @@ -7743,6 +3895,8 @@ }, "node_modules/@sigstore/sign": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-3.1.0.tgz", + "integrity": "sha512-knzjmaOHOov1Ur7N/z4B1oPqZ0QX5geUfhrVaqVlu+hl0EAoL4o+l0MSULINcD5GCWe3Z0+YJO8ues6vFlW0Yw==", "devOptional": true, "license": "Apache-2.0", "dependencies": { @@ -7759,6 +3913,8 @@ }, "node_modules/@sigstore/tuf": { "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-3.1.1.tgz", + "integrity": "sha512-eFFvlcBIoGwVkkwmTi/vEQFSva3xs5Ot3WmBcjgjVdiaoelBLQaQ/ZBfhlG0MnG0cmTYScPpk7eDdGDWUcFUmg==", "devOptional": true, "license": "Apache-2.0", "dependencies": { @@ -7771,6 +3927,8 @@ }, "node_modules/@sigstore/verify": { "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@sigstore/verify/-/verify-2.1.1.tgz", + "integrity": "sha512-hVJD77oT67aowHxwT4+M6PGOp+E2LtLdTK3+FC0lBO9T7sYwItDMXZ7Z07IDCvR1M717a4axbIWckrW67KMP/w==", "devOptional": true, "license": "Apache-2.0", "dependencies": { @@ -7783,14 +3941,18 @@ } }, "node_modules/@start9labs/argon2": { - "version": "0.3.0" + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@start9labs/argon2/-/argon2-0.3.0.tgz", + "integrity": "sha512-nAuIxTJKwPNMideyJsDX3gbiF6SFnmg8LBwNbB672ff94COc73CyrB7WQUxXjkVjfG09s54qW/FpnMrnCANl7g==" }, "node_modules/@start9labs/start-sdk": { "resolved": "../sdk/baseDist", "link": true }, "node_modules/@taiga-ui/addon-charts": { - "version": "4.52.0", + "version": "4.55.0", + "resolved": "https://registry.npmjs.org/@taiga-ui/addon-charts/-/addon-charts-4.55.0.tgz", + "integrity": "sha512-Rwgcc7NaLm75GsHYhqbO4jgNhD1bGbA7Kk0sNFE+Tgz9+V3ARXMuBw7C3cU9UxLSFnOsXz9RYLosmZ3jAVlyuQ==", "license": "Apache-2.0", "dependencies": { "tslib": ">=2.8.1" @@ -7799,14 +3961,17 @@ "@angular/common": ">=16.0.0", "@angular/core": ">=16.0.0", "@ng-web-apis/common": "^4.12.0", - "@taiga-ui/cdk": "^4.52.0", - "@taiga-ui/core": "^4.52.0", + "@taiga-ui/cdk": "^4.55.0", + "@taiga-ui/core": "^4.55.0", "@taiga-ui/polymorpheus": "^4.9.0" } }, "node_modules/@taiga-ui/addon-commerce": { - "version": "4.52.0", + "version": "4.55.0", + "resolved": "https://registry.npmjs.org/@taiga-ui/addon-commerce/-/addon-commerce-4.55.0.tgz", + "integrity": "sha512-eOOBkIJSsagtRkpRZ04xlL8ePIP01d4Xo264zSTg2SRxD6vwR/7/QJlf9108BvIJv/jfTpmFukLwSB9LazqmCw==", "license": "Apache-2.0", + "peer": true, "dependencies": { "tslib": ">=2.8.1" }, @@ -7818,16 +3983,18 @@ "@maskito/core": "^3.10.3", "@maskito/kit": "^3.10.3", "@ng-web-apis/common": "^4.12.0", - "@taiga-ui/cdk": "^4.52.0", - "@taiga-ui/core": "^4.52.0", - "@taiga-ui/i18n": "^4.52.0", - "@taiga-ui/kit": "^4.52.0", + "@taiga-ui/cdk": "^4.55.0", + "@taiga-ui/core": "^4.55.0", + "@taiga-ui/i18n": "^4.55.0", + "@taiga-ui/kit": "^4.55.0", "@taiga-ui/polymorpheus": "^4.9.0", "rxjs": ">=7.0.0" } }, "node_modules/@taiga-ui/addon-mobile": { - "version": "4.52.0", + "version": "4.55.0", + "resolved": "https://registry.npmjs.org/@taiga-ui/addon-mobile/-/addon-mobile-4.55.0.tgz", + "integrity": "sha512-NQRozVKcXLs9/rd/s1yI7T5rIokzwHQ5IN/c3NLBUEka1iKUr1ZTch+g9CHJf8GTVB0uAwWKNCgX5LxtiSI5zg==", "license": "Apache-2.0", "dependencies": { "tslib": ">=2.8.1" @@ -7837,16 +4004,18 @@ "@angular/common": ">=16.0.0", "@angular/core": ">=16.0.0", "@ng-web-apis/common": "^4.12.0", - "@taiga-ui/cdk": "^4.52.0", - "@taiga-ui/core": "^4.52.0", - "@taiga-ui/kit": "^4.52.0", - "@taiga-ui/layout": "^4.52.0", + "@taiga-ui/cdk": "^4.55.0", + "@taiga-ui/core": "^4.55.0", + "@taiga-ui/kit": "^4.55.0", + "@taiga-ui/layout": "^4.55.0", "@taiga-ui/polymorpheus": "^4.9.0", "rxjs": ">=7.0.0" } }, "node_modules/@taiga-ui/addon-table": { - "version": "4.52.0", + "version": "4.55.0", + "resolved": "https://registry.npmjs.org/@taiga-ui/addon-table/-/addon-table-4.55.0.tgz", + "integrity": "sha512-K5qpOS0UQLDqruJXPNDic8scCRvO3oAN/ZCPQ9XOGDrcvydvo4AKUwjKRPj+pZ/z0ulxbwAAruFFFCvRNnbzaA==", "license": "Apache-2.0", "dependencies": { "tslib": ">=2.8.1" @@ -7855,17 +4024,20 @@ "@angular/common": ">=16.0.0", "@angular/core": ">=16.0.0", "@ng-web-apis/intersection-observer": "^4.12.0", - "@taiga-ui/cdk": "^4.52.0", - "@taiga-ui/core": "^4.52.0", - "@taiga-ui/i18n": "^4.52.0", - "@taiga-ui/kit": "^4.52.0", + "@taiga-ui/cdk": "^4.55.0", + "@taiga-ui/core": "^4.55.0", + "@taiga-ui/i18n": "^4.55.0", + "@taiga-ui/kit": "^4.55.0", "@taiga-ui/polymorpheus": "^4.9.0", "rxjs": ">=7.0.0" } }, "node_modules/@taiga-ui/cdk": { - "version": "4.52.0", + "version": "4.55.0", + "resolved": "https://registry.npmjs.org/@taiga-ui/cdk/-/cdk-4.55.0.tgz", + "integrity": "sha512-vA5nGyx+YIHR1xZeq5D9gSqTRQg74qhe1AOt5FlqFOC0P4LvmLkNg3De7AeahXALNSeRz/DYcqI7WuGo6xpcLQ==", "license": "Apache-2.0", + "peer": true, "dependencies": { "tslib": "2.8.1" }, @@ -7887,14 +4059,17 @@ "@ng-web-apis/platform": "^4.12.0", "@ng-web-apis/resize-observer": "^4.12.0", "@ng-web-apis/screen-orientation": "^4.12.0", - "@taiga-ui/event-plugins": "^4.6.0", + "@taiga-ui/event-plugins": "^4.7.0", "@taiga-ui/polymorpheus": "^4.9.0", "rxjs": ">=7.0.0" } }, "node_modules/@taiga-ui/core": { - "version": "4.52.0", + "version": "4.55.0", + "resolved": "https://registry.npmjs.org/@taiga-ui/core/-/core-4.55.0.tgz", + "integrity": "sha512-Z2ATVNmEAlHEk2cgs/tnS6qZML87IchkPDeRl6HQfBT2fjYVjh1oCzXL07t86Lv6tpvkllyUVqoBCTSvDXs9kA==", "license": "Apache-2.0", + "peer": true, "dependencies": { "tslib": ">=2.8.1" }, @@ -7907,15 +4082,17 @@ "@angular/router": ">=16.0.0", "@ng-web-apis/common": "^4.12.0", "@ng-web-apis/mutation-observer": "^4.12.0", - "@taiga-ui/cdk": "^4.52.0", - "@taiga-ui/event-plugins": "^4.6.0", - "@taiga-ui/i18n": "^4.52.0", + "@taiga-ui/cdk": "^4.55.0", + "@taiga-ui/event-plugins": "^4.7.0", + "@taiga-ui/i18n": "^4.55.0", "@taiga-ui/polymorpheus": "^4.9.0", "rxjs": ">=7.0.0" } }, "node_modules/@taiga-ui/dompurify": { "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@taiga-ui/dompurify/-/dompurify-4.1.11.tgz", + "integrity": "sha512-nwskeI/wFe+spuLQdkhVCn/GJBHJamxZ5deZuyto7C4I3O+pF8GaCNJdKM1YG5TZyGz932Qm8uNtBVZ/fZX8sQ==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.8.1" @@ -7929,7 +4106,10 @@ }, "node_modules/@taiga-ui/event-plugins": { "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@taiga-ui/event-plugins/-/event-plugins-4.7.0.tgz", + "integrity": "sha512-j3HPRPR7XxKxgMeytb+r/CNUoLBMVrfdfL8KJr1XiFO9jyEvoC4chFXDXWlkGyUHJIC6wy5VIXlIlI/kpqOiGg==", "license": "Apache-2.0", + "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -7940,7 +4120,9 @@ } }, "node_modules/@taiga-ui/experimental": { - "version": "4.52.0", + "version": "4.55.0", + "resolved": "https://registry.npmjs.org/@taiga-ui/experimental/-/experimental-4.55.0.tgz", + "integrity": "sha512-3zq2BTl+fE/N/tEr74TzWbyzT5OoS9YEApKobJehKivW5XxZmF/MDRWp45kSe4jDtVbJ2ueI0Jn8h0BDNykkcg==", "license": "Apache-2.0", "dependencies": { "tslib": ">=2.8.1" @@ -7948,17 +4130,19 @@ "peerDependencies": { "@angular/common": ">=16.0.0", "@angular/core": ">=16.0.0", - "@taiga-ui/addon-commerce": "^4.52.0", - "@taiga-ui/cdk": "^4.52.0", - "@taiga-ui/core": "^4.52.0", - "@taiga-ui/kit": "^4.52.0", - "@taiga-ui/layout": "^4.52.0", + "@taiga-ui/addon-commerce": "^4.55.0", + "@taiga-ui/cdk": "^4.55.0", + "@taiga-ui/core": "^4.55.0", + "@taiga-ui/kit": "^4.55.0", + "@taiga-ui/layout": "^4.55.0", "@taiga-ui/polymorpheus": "^4.9.0", "rxjs": ">=7.0.0" } }, "node_modules/@taiga-ui/i18n": { - "version": "4.53.0", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@taiga-ui/i18n/-/i18n-4.59.0.tgz", + "integrity": "sha512-IxPzqkORJlSqagvUdmqBL9fuvfRm/Ca/W/bCDEK2GN/4QtSZ0yFzAyQdWduoIJubqyEPMXRbXZGc7WBtDgAMIQ==", "license": "Apache-2.0", "peer": true, "dependencies": { @@ -7971,15 +4155,20 @@ } }, "node_modules/@taiga-ui/icons": { - "version": "4.52.0", + "version": "4.55.0", + "resolved": "https://registry.npmjs.org/@taiga-ui/icons/-/icons-4.55.0.tgz", + "integrity": "sha512-sYqSG9wgUcwHBrDRnMhLCMEkvAAw/SZrvvq0jdY2oWGmKwAj/6WBt+wA+jnFkDDKEZ7mjzdPIQffpVaUjSwsiw==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.3.0" } }, "node_modules/@taiga-ui/kit": { - "version": "4.52.0", + "version": "4.55.0", + "resolved": "https://registry.npmjs.org/@taiga-ui/kit/-/kit-4.55.0.tgz", + "integrity": "sha512-xTvi7viI+wI2ifPv2bsf8prhYWWS4g1lbx059jXV3f5Cttc0Xg6DEb6xpaQOf4loBkcrP2FzkA4njACUuiouzw==", "license": "Apache-2.0", + "peer": true, "dependencies": { "tslib": ">=2.8.1" }, @@ -7996,32 +4185,38 @@ "@ng-web-apis/intersection-observer": "^4.12.0", "@ng-web-apis/mutation-observer": "^4.12.0", "@ng-web-apis/resize-observer": "^4.12.0", - "@taiga-ui/cdk": "^4.52.0", - "@taiga-ui/core": "^4.52.0", - "@taiga-ui/i18n": "^4.52.0", + "@taiga-ui/cdk": "^4.55.0", + "@taiga-ui/core": "^4.55.0", + "@taiga-ui/i18n": "^4.55.0", "@taiga-ui/polymorpheus": "^4.9.0", "rxjs": ">=7.0.0" } }, "node_modules/@taiga-ui/layout": { - "version": "4.52.0", + "version": "4.55.0", + "resolved": "https://registry.npmjs.org/@taiga-ui/layout/-/layout-4.55.0.tgz", + "integrity": "sha512-C+e4gudZwjIc46VITil5vySas1FPpfe+D4uwLRggJOTuUosZlZHBuc51v91wCCc0pL0Xfu+TD0s8W9kRd1sQHA==", "license": "Apache-2.0", + "peer": true, "dependencies": { "tslib": ">=2.8.1" }, "peerDependencies": { "@angular/common": ">=16.0.0", "@angular/core": ">=16.0.0", - "@taiga-ui/cdk": "^4.52.0", - "@taiga-ui/core": "^4.52.0", - "@taiga-ui/kit": "^4.52.0", + "@taiga-ui/cdk": "^4.55.0", + "@taiga-ui/core": "^4.55.0", + "@taiga-ui/kit": "^4.55.0", "@taiga-ui/polymorpheus": "^4.9.0", "rxjs": ">=7.0.0" } }, "node_modules/@taiga-ui/polymorpheus": { "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@taiga-ui/polymorpheus/-/polymorpheus-4.9.0.tgz", + "integrity": "sha512-TbIIwslbEnxunKuL9OyPZdmefrvJEK6HYiADEKQHUMUs4Pk2UbhMckUieURo83yPDamk/Mww+Nu/g60J/4uh2w==", "license": "Apache-2.0", + "peer": true, "dependencies": { "tslib": "^2.8.1" }, @@ -8032,6 +4227,8 @@ }, "node_modules/@ts-morph/common": { "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.24.0.tgz", + "integrity": "sha512-c1xMmNHWpNselmpIqursHeOHHBTIsJLbB+NuovbTTRCNiTLEr/U9dbJ8qy0jd/O2x5pc3seWuOUN5R2IoOTp8A==", "license": "MIT", "optional": true, "dependencies": { @@ -8043,6 +4240,8 @@ }, "node_modules/@ts-morph/common/node_modules/minimatch": { "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "license": "ISC", "optional": true, "dependencies": { @@ -8057,6 +4256,8 @@ }, "node_modules/@ts-morph/common/node_modules/mkdirp": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", + "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", "license": "MIT", "optional": true, "bin": { @@ -8071,26 +4272,36 @@ }, "node_modules/@tsconfig/node10": { "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node12": { "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node14": { "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node16": { "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", "dev": true, "license": "MIT" }, "node_modules/@tufjs/canonical-json": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz", + "integrity": "sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA==", "devOptional": true, "license": "MIT", "engines": { @@ -8099,6 +4310,8 @@ }, "node_modules/@tufjs/models": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-3.0.1.tgz", + "integrity": "sha512-UUYHISyhCU3ZgN8yaear3cGATHb3SMuKHsQ/nVbHXcmnBf+LzQ/cQfhNG+rfaSHgqGKNEm2cOCLVLELStUQ1JA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -8111,6 +4324,8 @@ }, "node_modules/@tufjs/models/node_modules/minimatch": { "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "devOptional": true, "license": "ISC", "dependencies": { @@ -8125,50 +4340,70 @@ }, "node_modules/@types/dompurify": { "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/dompurify/-/dompurify-3.0.5.tgz", + "integrity": "sha512-1Wg0g3BtQF7sSb27fJQAKck1HECM6zV1EB66j8JH9i3LCjYabJa0FSdiSgsD5K/RbrsR0SiraKacLB+T8ZVYAg==", "license": "MIT", + "peer": true, "dependencies": { "@types/trusted-types": "*" } }, "node_modules/@types/estree": { "version": "0.0.51", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", + "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", "dev": true, "license": "MIT" }, "node_modules/@types/js-yaml": { "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz", + "integrity": "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==", "dev": true, "license": "MIT" }, "node_modules/@types/luxon": { "version": "3.3.8", + "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.3.8.tgz", + "integrity": "sha512-jYvz8UMLDgy3a5SkGJne8H7VA7zPV2Lwohjx0V8V31+SqAjNmurWMkk9cQhfvlcnXWudBpK9xPM1n4rljOcHYQ==", "license": "MIT" }, "node_modules/@types/marked": { "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@types/marked/-/marked-4.3.2.tgz", + "integrity": "sha512-a79Yc3TOk6dGdituy8hmTTJXjOkZ7zsFYV10L337ttq/rec8lRMDBpV7fL3uLx6TgbFCa5DU/h8FmIBQPSbU0w==", "dev": true, "license": "MIT" }, "node_modules/@types/minimatch": { "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", + "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", "license": "MIT", "optional": true }, "node_modules/@types/mustache": { "version": "4.2.6", + "resolved": "https://registry.npmjs.org/@types/mustache/-/mustache-4.2.6.tgz", + "integrity": "sha512-t+8/QWTAhOFlrF1IVZqKnMRJi84EgkIK5Kh0p2JV4OLywUvCwJPFxbJAl7XAow7DVIHsF+xW9f1MVzg0L6Szjw==", "dev": true, "license": "MIT" }, "node_modules/@types/node": { - "version": "22.18.1", + "version": "22.18.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.18.12.tgz", + "integrity": "sha512-BICHQ67iqxQGFSzfCFTT7MRQ5XcBjG5aeKh5Ok38UBbPe5fxTyE+aHFxwVrGyr8GNlqFMLKD1D3P2K/1ks8tog==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "undici-types": "~6.21.0" } }, "node_modules/@types/node-jose": { "version": "1.1.13", + "resolved": "https://registry.npmjs.org/@types/node-jose/-/node-jose-1.1.13.tgz", + "integrity": "sha512-QjMd4yhwy1EvSToQn0YI3cD29YhyfxFwj7NecuymjLys2/P0FwxWnkgBlFxCai6Y3aBCe7rbwmqwJJawxlgcXw==", "dev": true, "license": "MIT", "dependencies": { @@ -8177,11 +4412,15 @@ }, "node_modules/@types/parse-json": { "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", "dev": true, "license": "MIT" }, "node_modules/@types/pbkdf2": { "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@types/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-uRwJqmiXmh9++aSu1VNEn3iIxWOhd8AHXNSdlaLfdAAdSTY9jYVeGWnzejM3dvrkbqE3/hyQkQQ29IFATEGlew==", "dev": true, "license": "MIT", "dependencies": { @@ -8190,15 +4429,21 @@ }, "node_modules/@types/trusted-types": { "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", "license": "MIT" }, "node_modules/@types/uuid": { "version": "8.3.4", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", + "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==", "dev": true, "license": "MIT" }, "node_modules/@vitejs/plugin-basic-ssl": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-2.1.0.tgz", + "integrity": "sha512-dOxxrhgyDIEUADhb/8OlV9JIqYLgos03YorAueTIeOUskLJSEsfwCByjbu98ctXitUN3znXKp0bYD/WHSudCeA==", "dev": true, "license": "MIT", "engines": { @@ -8210,11 +4455,15 @@ }, "node_modules/@yarnpkg/lockfile": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", + "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", "devOptional": true, "license": "BSD-2-Clause" }, "node_modules/abbrev": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-3.0.1.tgz", + "integrity": "sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg==", "devOptional": true, "license": "ISC", "engines": { @@ -8223,6 +4472,8 @@ }, "node_modules/accepts": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", "devOptional": true, "license": "MIT", "dependencies": { @@ -8235,6 +4486,8 @@ }, "node_modules/acorn": { "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", "bin": { @@ -8246,6 +4499,8 @@ }, "node_modules/acorn-walk": { "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", "dev": true, "license": "MIT", "dependencies": { @@ -8257,6 +4512,8 @@ }, "node_modules/agent-base": { "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", "devOptional": true, "license": "MIT", "engines": { @@ -8265,6 +4522,8 @@ }, "node_modules/ajv": { "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", @@ -8279,6 +4538,8 @@ }, "node_modules/ajv-formats": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", "license": "MIT", "dependencies": { "ajv": "^8.0.0" @@ -8294,6 +4555,8 @@ }, "node_modules/algoliasearch": { "version": "5.35.0", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.35.0.tgz", + "integrity": "sha512-Y+moNhsqgLmvJdgTsO4GZNgsaDWv8AOGAaPeIeHKlDn/XunoAqYbA+XNpBd1dW8GOXAUDyxC9Rxc7AV4kpFcIg==", "devOptional": true, "license": "MIT", "dependencies": { @@ -8318,6 +4581,8 @@ }, "node_modules/ansi-colors": { "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", "dev": true, "license": "MIT", "engines": { @@ -8325,14 +4590,16 @@ } }, "node_modules/ansi-escapes": { - "version": "4.3.2", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.1.1.tgz", + "integrity": "sha512-Zhl0ErHcSRUaVfGUeUdDuLgpkEo8KIFjB4Y9uAc46ScOpdDiU1Dbyplh7qWJeJ/ZHpbyMSM26+X3BySgnIz40Q==", "devOptional": true, "license": "MIT", "dependencies": { - "type-fest": "^0.21.3" + "environment": "^1.0.0" }, "engines": { - "node": ">=8" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -8340,6 +4607,8 @@ }, "node_modules/ansi-regex": { "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", "license": "MIT", "engines": { "node": ">=12" @@ -8350,6 +4619,8 @@ }, "node_modules/ansi-styles": { "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "devOptional": true, "license": "MIT", "engines": { @@ -8361,6 +4632,8 @@ }, "node_modules/ansi-to-html": { "version": "0.7.2", + "resolved": "https://registry.npmjs.org/ansi-to-html/-/ansi-to-html-0.7.2.tgz", + "integrity": "sha512-v6MqmEpNlxF+POuyhKkidusCHWWkaLcGRURzivcU3I9tv7k4JVhFcnukrM5Rlk2rUywdZuzYAZ+kbZqWCnfN3g==", "license": "MIT", "dependencies": { "entities": "^2.2.0" @@ -8372,25 +4645,23 @@ "node": ">=8.0.0" } }, - "node_modules/ansis": { - "version": "4.1.0", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - } - }, "node_modules/arg": { "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", "dev": true, "license": "MIT" }, "node_modules/argparse": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "license": "Python-2.0" }, "node_modules/array-differ": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-3.0.0.tgz", + "integrity": "sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==", "license": "MIT", "optional": true, "engines": { @@ -8399,6 +4670,8 @@ }, "node_modules/array-union": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "license": "MIT", "optional": true, "engines": { @@ -8407,6 +4680,8 @@ }, "node_modules/arrify": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", "license": "MIT", "optional": true, "engines": { @@ -8415,11 +4690,15 @@ }, "node_modules/async": { "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", "dev": true, "license": "MIT" }, "node_modules/available-typed-arrays": { "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", "license": "MIT", "dependencies": { "possible-typed-array-names": "^1.0.0" @@ -8433,11 +4712,15 @@ }, "node_modules/balanced-match": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "devOptional": true, "license": "MIT" }, "node_modules/base64-js": { "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", "funding": [ { "type": "github", @@ -8456,13 +4739,27 @@ }, "node_modules/base64url": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz", + "integrity": "sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==", "license": "MIT", "engines": { "node": ">=6.0.0" } }, + "node_modules/baseline-browser-mapping": { + "version": "2.8.19", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.19.tgz", + "integrity": "sha512-zoKGUdu6vb2jd3YOq0nnhEDQVbPcHhco3UImJrv5dSkvxTc2pl2WjOPsjZXDwPDSl5eghIMuY3R6J9NDKF3KcQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, "node_modules/basic-auth": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", "dev": true, "license": "MIT", "dependencies": { @@ -8474,11 +4771,15 @@ }, "node_modules/basic-auth/node_modules/safe-buffer": { "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true, "license": "MIT" }, "node_modules/beasties": { "version": "0.3.5", + "resolved": "https://registry.npmjs.org/beasties/-/beasties-0.3.5.tgz", + "integrity": "sha512-NaWu+f4YrJxEttJSm16AzMIFtVldCvaJ68b1L098KpqXmxt9xOLtKoLkKxb8ekhOrLqEJAbvT6n6SEvB/sac7A==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -8497,6 +4798,8 @@ }, "node_modules/body-parser": { "version": "2.2.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", + "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==", "devOptional": true, "license": "MIT", "dependencies": { @@ -8514,13 +4817,30 @@ "node": ">=18" } }, + "node_modules/body-parser/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/boolbase": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", "dev": true, "license": "ISC" }, "node_modules/brace-expansion": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "devOptional": true, "license": "MIT", "dependencies": { @@ -8529,6 +4849,8 @@ }, "node_modules/braces": { "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -8539,7 +4861,9 @@ } }, "node_modules/browserslist": { - "version": "4.25.4", + "version": "4.27.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.27.0.tgz", + "integrity": "sha512-AXVQwdhot1eqLihwasPElhX2tAZiBjWdJ9i/Zcj2S6QYIjkx62OKSfnobkriB81C3l4w0rVy3Nt4jaTBltYEpw==", "dev": true, "funding": [ { @@ -8556,11 +4880,13 @@ } ], "license": "MIT", + "peer": true, "dependencies": { - "caniuse-lite": "^1.0.30001737", - "electron-to-chromium": "^1.5.211", - "node-releases": "^2.0.19", - "update-browserslist-db": "^1.1.3" + "baseline-browser-mapping": "^2.8.19", + "caniuse-lite": "^1.0.30001751", + "electron-to-chromium": "^1.5.238", + "node-releases": "^2.0.26", + "update-browserslist-db": "^1.1.4" }, "bin": { "browserslist": "cli.js" @@ -8571,6 +4897,8 @@ }, "node_modules/buffer": { "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", "funding": [ { "type": "github", @@ -8593,11 +4921,15 @@ }, "node_modules/buffer-from": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true, "license": "MIT" }, "node_modules/builtin-modules": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha512-wxXCdllwGhI2kCC0MnvTGYTMvnVZTvqgypkiTI8Pa5tcz2i6VqsqwYGgqwXji+4RgCzms6EajE4IxiUH6HH8nQ==", "dev": true, "license": "MIT", "engines": { @@ -8606,6 +4938,8 @@ }, "node_modules/bundle-name": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", "dev": true, "license": "MIT", "dependencies": { @@ -8620,6 +4954,8 @@ }, "node_modules/bytes": { "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "devOptional": true, "license": "MIT", "engines": { @@ -8628,6 +4964,8 @@ }, "node_modules/cacache": { "version": "19.0.1", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-19.0.1.tgz", + "integrity": "sha512-hdsUxulXCi5STId78vRVYEtDAjq99ICAUktLTeTYsLoTE6Z8dS0c8pWNCxwdrk9YfJeobDZc2Y186hD/5ZQgFQ==", "devOptional": true, "license": "ISC", "dependencies": { @@ -8650,6 +4988,8 @@ }, "node_modules/cacache/node_modules/chownr": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", "devOptional": true, "license": "BlueOak-1.0.0", "engines": { @@ -8658,33 +4998,22 @@ }, "node_modules/cacache/node_modules/lru-cache": { "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "devOptional": true, "license": "ISC" }, - "node_modules/cacache/node_modules/mkdirp": { - "version": "3.0.1", - "devOptional": true, - "license": "MIT", - "bin": { - "mkdirp": "dist/cjs/src/bin.js" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/cacache/node_modules/tar": { - "version": "7.4.3", + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.1.tgz", + "integrity": "sha512-nlGpxf+hv0v7GkWBK2V9spgactGOp0qvfWRxUMjqHyzrt3SgwE48DIv/FhqPHJYLHpgW1opq3nERbz5Anq7n1g==", "devOptional": true, "license": "ISC", "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", - "minizlib": "^3.0.1", - "mkdirp": "^3.0.1", + "minizlib": "^3.1.0", "yallist": "^5.0.0" }, "engines": { @@ -8693,6 +5022,8 @@ }, "node_modules/cacache/node_modules/yallist": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", "devOptional": true, "license": "BlueOak-1.0.0", "engines": { @@ -8701,6 +5032,8 @@ }, "node_modules/call-bind": { "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.0", @@ -8717,6 +5050,8 @@ }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -8728,6 +5063,8 @@ }, "node_modules/call-bound": { "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", @@ -8742,6 +5079,8 @@ }, "node_modules/callsites": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, "license": "MIT", "engines": { @@ -8750,13 +5089,17 @@ }, "node_modules/camelcase": { "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/caniuse-lite": { - "version": "1.0.30001741", + "version": "1.0.30001751", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001751.tgz", + "integrity": "sha512-A0QJhug0Ly64Ii3eIqHu5X51ebln3k4yTUkY1j8drqpWHVreg/VLijN48cZ1bYPiqOQuqpkIKnzr/Ul8V+p6Cw==", "dev": true, "funding": [ { @@ -8777,10 +5120,14 @@ "node_modules/cbor": { "name": "@jprochazk/cbor", "version": "0.4.9", + "resolved": "https://registry.npmjs.org/@jprochazk/cbor/-/cbor-0.4.9.tgz", + "integrity": "sha512-FWNnkOtWrFOLXKG2nzOHR/EnCCGZZPvatAvWXDmkTDxgjj9JHDK3DkMUHcFCY3a9weylMCSO/nLOUM170NAO0Q==", "license": "MIT" }, "node_modules/cbor-web": { "version": "8.1.0", + "resolved": "https://registry.npmjs.org/cbor-web/-/cbor-web-8.1.0.tgz", + "integrity": "sha512-2hWHHMVrfffgoEmsAUh8vCxHoLa1vgodtC73+C5cSarkJlwTapnqAzcHINlP6Ej0DXuP4OmmJ9LF+JaNM5Lj/g==", "license": "MIT", "engines": { "node": ">=12.19" @@ -8788,6 +5135,8 @@ }, "node_modules/chalk": { "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", "license": "MIT", "engines": { "node": "^12.17.0 || ^14.13 || >=16.0.0" @@ -8798,13 +5147,18 @@ }, "node_modules/chardet": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.0.tgz", + "integrity": "sha512-bNFETTG/pM5ryzQ9Ad0lJOTa6HWD/YsScAR3EnCPZRPlQh77JocYktSHOUHelyhm8IARL+o4c4F1bP5KVOjiRA==", "devOptional": true, "license": "MIT" }, "node_modules/chokidar": { "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", "devOptional": true, "license": "MIT", + "peer": true, "dependencies": { "readdirp": "^4.0.1" }, @@ -8817,6 +5171,8 @@ }, "node_modules/chownr": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", "devOptional": true, "license": "ISC", "engines": { @@ -8825,15 +5181,20 @@ }, "node_modules/ci-info": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", "dev": true, "license": "MIT" }, "node_modules/cipher-base": { - "version": "1.0.6", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.7.tgz", + "integrity": "sha512-Mz9QMT5fJe7bKI7MH31UilT5cEK5EHHRCccw/YRFsRY47AuNgaV6HY3rscp0/I4Q+tTW/5zoqpSeRRI54TkDWA==", "license": "MIT", "dependencies": { "inherits": "^2.0.4", - "safe-buffer": "^5.2.1" + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.2" }, "engines": { "node": ">= 0.10" @@ -8841,6 +5202,8 @@ }, "node_modules/cli-cursor": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", "license": "MIT", "dependencies": { "restore-cursor": "^5.0.0" @@ -8854,6 +5217,8 @@ }, "node_modules/cli-spinners": { "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", "license": "MIT", "engines": { "node": ">=6" @@ -8864,6 +5229,8 @@ }, "node_modules/cli-truncate": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz", + "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -8879,6 +5246,8 @@ }, "node_modules/cli-width": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", "devOptional": true, "license": "ISC", "engines": { @@ -8887,6 +5256,8 @@ }, "node_modules/cliui": { "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", + "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", "devOptional": true, "license": "ISC", "dependencies": { @@ -8900,6 +5271,8 @@ }, "node_modules/cliui/node_modules/wrap-ansi": { "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", "devOptional": true, "license": "MIT", "dependencies": { @@ -8916,11 +5289,15 @@ }, "node_modules/code-block-writer": { "version": "13.0.3", + "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-13.0.3.tgz", + "integrity": "sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg==", "license": "MIT", "optional": true }, "node_modules/color-convert": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -8931,15 +5308,21 @@ }, "node_modules/color-name": { "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "license": "MIT" }, "node_modules/colorette": { "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", "devOptional": true, "license": "MIT" }, "node_modules/commander": { "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", "dev": true, "license": "MIT", "engines": { @@ -8948,21 +5331,29 @@ }, "node_modules/common-path-prefix": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", + "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==", "dev": true, "license": "ISC" }, "node_modules/compare-versions": { "version": "3.6.0", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.6.0.tgz", + "integrity": "sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA==", "dev": true, "license": "MIT" }, "node_modules/concat-map": { "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "devOptional": true, "license": "MIT" }, "node_modules/content-disposition": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", + "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", "devOptional": true, "license": "MIT", "dependencies": { @@ -8974,6 +5365,8 @@ }, "node_modules/content-type": { "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "devOptional": true, "license": "MIT", "engines": { @@ -8982,11 +5375,15 @@ }, "node_modules/convert-source-map": { "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", "dev": true, "license": "MIT" }, "node_modules/cookie": { "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", "devOptional": true, "license": "MIT", "engines": { @@ -8995,6 +5392,8 @@ }, "node_modules/cookie-signature": { "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", "devOptional": true, "license": "MIT", "engines": { @@ -9003,6 +5402,8 @@ }, "node_modules/copy-anything": { "version": "2.0.6", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", + "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", "dev": true, "license": "MIT", "dependencies": { @@ -9013,7 +5414,9 @@ } }, "node_modules/core-js": { - "version": "3.45.1", + "version": "3.46.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.46.0.tgz", + "integrity": "sha512-vDMm9B0xnqqZ8uSBpZ8sNtRtOdmfShrvT6h2TuQGLs0Is+cR0DYbj/KWP6ALVNbWPpqA/qPLoOuppJN07humpA==", "hasInstallScript": true, "license": "MIT", "funding": { @@ -9021,8 +5424,16 @@ "url": "https://opencollective.com/core-js" } }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT" + }, "node_modules/cors": { "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", "devOptional": true, "license": "MIT", "dependencies": { @@ -9035,6 +5446,8 @@ }, "node_modules/corser": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz", + "integrity": "sha512-utCYNzRSQIZNPIcGZdQc92UVJYAhtGAteCFg0yRaFm8f0P+CPtyGyHXJcGXnffjCybUCEx3FQ2G7U3/o9eIkVQ==", "dev": true, "license": "MIT", "engines": { @@ -9043,6 +5456,8 @@ }, "node_modules/cosmiconfig": { "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", "dev": true, "license": "MIT", "dependencies": { @@ -9058,6 +5473,8 @@ }, "node_modules/cosmiconfig/node_modules/yaml": { "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", "dev": true, "license": "ISC", "engines": { @@ -9065,17 +5482,22 @@ } }, "node_modules/create-hash": { - "version": "1.1.3", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "license": "MIT", "dependencies": { "cipher-base": "^1.0.1", "inherits": "^2.0.1", - "ripemd160": "^2.0.0", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", "sha.js": "^2.4.0" } }, "node_modules/create-hmac": { "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "license": "MIT", "dependencies": { "cipher-base": "^1.0.3", @@ -9088,11 +5510,15 @@ }, "node_modules/create-require": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "dev": true, "license": "MIT" }, "node_modules/cron": { "version": "2.4.4", + "resolved": "https://registry.npmjs.org/cron/-/cron-2.4.4.tgz", + "integrity": "sha512-MHlPImXJj3K7x7lyUHjtKEOl69CSlTOWxS89jiFgNkzXfvhVjhMz/nc7/EIfN9vgooZp8XTtXJ1FREdmbyXOiQ==", "license": "MIT", "dependencies": { "@types/luxon": "~3.3.0", @@ -9101,6 +5527,8 @@ }, "node_modules/cronstrue": { "version": "2.59.0", + "resolved": "https://registry.npmjs.org/cronstrue/-/cronstrue-2.59.0.tgz", + "integrity": "sha512-YKGmAy84hKH+hHIIER07VCAHf9u0Ldelx1uU6EBxsRPDXIA1m5fsKmJfyC3xBhw6cVC/1i83VdbL4PvepTrt8A==", "license": "MIT", "bin": { "cronstrue": "bin/cli.js" @@ -9108,6 +5536,8 @@ }, "node_modules/cross-spawn": { "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -9121,6 +5551,8 @@ }, "node_modules/css-select": { "version": "6.0.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-6.0.0.tgz", + "integrity": "sha512-rZZVSLle8v0+EY8QAkDWrKhpgt6SA5OtHsgBnsj6ZaLb5dmDVOWUDtQitd9ydxxvEjhewNudS6eTVU7uOyzvXw==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -9136,6 +5568,8 @@ }, "node_modules/css-what": { "version": "7.0.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-7.0.0.tgz", + "integrity": "sha512-wD5oz5xibMOPHzy13CyGmogB3phdvcDaB5t0W/Nr5Z2O/agcB8YwOz6e2Lsp10pNDzBoDO9nVa3RGs/2BttpHQ==", "dev": true, "license": "BSD-2-Clause", "engines": { @@ -9146,7 +5580,9 @@ } }, "node_modules/debug": { - "version": "4.4.1", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -9163,6 +5599,8 @@ }, "node_modules/decamelize": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -9170,6 +5608,8 @@ }, "node_modules/deep-equality-data-structures": { "version": "1.5.1", + "resolved": "https://registry.npmjs.org/deep-equality-data-structures/-/deep-equality-data-structures-1.5.1.tgz", + "integrity": "sha512-P7zsL2/AbZIGHDxbo/LLEhCp11AttRp8GvzXOXudqMT/qiGCLo/pyI4lAZvjUZyQnlIbPna3fv8DMsuRvLt4ww==", "license": "MIT", "dependencies": { "object-hash": "^3.0.0" @@ -9177,6 +5617,8 @@ }, "node_modules/default-browser": { "version": "5.2.1", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz", + "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==", "dev": true, "license": "MIT", "dependencies": { @@ -9192,6 +5634,8 @@ }, "node_modules/default-browser-id": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz", + "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==", "dev": true, "license": "MIT", "engines": { @@ -9203,6 +5647,8 @@ }, "node_modules/define-data-property": { "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", @@ -9218,6 +5664,8 @@ }, "node_modules/define-lazy-prop": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", "dev": true, "license": "MIT", "engines": { @@ -9229,6 +5677,8 @@ }, "node_modules/depd": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "devOptional": true, "license": "MIT", "engines": { @@ -9237,6 +5687,8 @@ }, "node_modules/dependency-graph": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-1.0.0.tgz", + "integrity": "sha512-cW3gggJ28HZ/LExwxP2B++aiKxhJXMSIt9K48FOXQkm+vuG5gyatXnLsONRJdzO/7VfjDIiaOOa/bs4l464Lwg==", "dev": true, "license": "MIT", "engines": { @@ -9244,7 +5696,9 @@ } }, "node_modules/detect-libc": { - "version": "2.0.4", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", "dev": true, "license": "Apache-2.0", "optional": true, @@ -9254,6 +5708,8 @@ }, "node_modules/diff": { "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -9262,10 +5718,14 @@ }, "node_modules/dijkstrajs": { "version": "1.0.3", + "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.3.tgz", + "integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==", "license": "MIT" }, "node_modules/dom-serializer": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", "dev": true, "license": "MIT", "dependencies": { @@ -9279,6 +5739,8 @@ }, "node_modules/dom-serializer/node_modules/entities": { "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", "dev": true, "license": "BSD-2-Clause", "engines": { @@ -9290,6 +5752,8 @@ }, "node_modules/domelementtype": { "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", "dev": true, "funding": [ { @@ -9301,6 +5765,8 @@ }, "node_modules/domhandler": { "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -9315,10 +5781,15 @@ }, "node_modules/dompurify": { "version": "3.1.7", - "license": "(MPL-2.0 OR Apache-2.0)" + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.7.tgz", + "integrity": "sha512-VaTstWtsneJY8xzy7DekmYWEOZcmzIe3Qb3zPd4STve1OBTa+e+WmS1ITQec1fZYXI3HCsOZZiSMpG6oxoWMWQ==", + "license": "(MPL-2.0 OR Apache-2.0)", + "peer": true }, "node_modules/domutils": { "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -9332,6 +5803,8 @@ }, "node_modules/dunder-proto": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.1", @@ -9344,25 +5817,35 @@ }, "node_modules/eastasianwidth": { "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", "devOptional": true, "license": "MIT" }, "node_modules/ee-first": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", "devOptional": true, "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.215", + "version": "1.5.239", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.239.tgz", + "integrity": "sha512-1y5w0Zsq39MSPmEjHjbizvhYoTaulVtivpxkp5q5kaPmQtsK6/2nvAzGRxNMS9DoYySp9PkW0MAQDwU1m764mg==", "dev": true, "license": "ISC" }, "node_modules/emoji-regex": { - "version": "10.5.0", + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", "license": "MIT" }, "node_modules/encodeurl": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "devOptional": true, "license": "MIT", "engines": { @@ -9371,6 +5854,8 @@ }, "node_modules/encoding": { "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", "dev": true, "license": "MIT", "optional": true, @@ -9378,8 +5863,24 @@ "iconv-lite": "^0.6.2" } }, + "node_modules/encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/entities": { "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", "license": "BSD-2-Clause", "funding": { "url": "https://github.com/fb55/entities?sponsor=1" @@ -9387,6 +5888,8 @@ }, "node_modules/env-paths": { "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", "devOptional": true, "license": "MIT", "engines": { @@ -9395,6 +5898,8 @@ }, "node_modules/environment": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", "devOptional": true, "license": "MIT", "engines": { @@ -9406,11 +5911,15 @@ }, "node_modules/err-code": { "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", "devOptional": true, "license": "MIT" }, "node_modules/errno": { "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", "dev": true, "license": "MIT", "optional": true, @@ -9422,7 +5931,9 @@ } }, "node_modules/error-ex": { - "version": "1.3.2", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", "dev": true, "license": "MIT", "dependencies": { @@ -9431,6 +5942,8 @@ }, "node_modules/es-define-property": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -9438,6 +5951,8 @@ }, "node_modules/es-errors": { "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -9445,6 +5960,8 @@ }, "node_modules/es-object-atoms": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0" @@ -9455,10 +5972,14 @@ }, "node_modules/es6-promise": { "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", "license": "MIT" }, "node_modules/esbuild": { "version": "0.25.9", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.9.tgz", + "integrity": "sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -9499,6 +6020,8 @@ }, "node_modules/escalade": { "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "devOptional": true, "license": "MIT", "engines": { @@ -9507,11 +6030,15 @@ }, "node_modules/escape-html": { "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", "devOptional": true, "license": "MIT" }, "node_modules/escape-string-regexp": { "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "dev": true, "license": "MIT", "engines": { @@ -9520,6 +6047,8 @@ }, "node_modules/esprima": { "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true, "license": "BSD-2-Clause", "bin": { @@ -9532,11 +6061,15 @@ }, "node_modules/estree-walker": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", "dev": true, "license": "MIT" }, "node_modules/etag": { "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "devOptional": true, "license": "MIT", "engines": { @@ -9545,11 +6078,15 @@ }, "node_modules/eventemitter3": { "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", "dev": true, "license": "MIT" }, "node_modules/eventsource": { "version": "3.0.7", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", + "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -9561,6 +6098,8 @@ }, "node_modules/eventsource-parser": { "version": "3.0.6", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.6.tgz", + "integrity": "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==", "devOptional": true, "license": "MIT", "engines": { @@ -9569,6 +6108,8 @@ }, "node_modules/execa": { "version": "7.2.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz", + "integrity": "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==", "dev": true, "license": "MIT", "dependencies": { @@ -9591,18 +6132,25 @@ }, "node_modules/execa/node_modules/signal-exit": { "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true, "license": "ISC" }, "node_modules/exponential-backoff": { - "version": "3.1.2", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.3.tgz", + "integrity": "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==", "devOptional": true, "license": "Apache-2.0" }, "node_modules/express": { "version": "5.1.0", + "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", + "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", "devOptional": true, "license": "MIT", + "peer": true, "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.0", @@ -9642,6 +6190,8 @@ }, "node_modules/express-rate-limit": { "version": "7.5.1", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.5.1.tgz", + "integrity": "sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==", "devOptional": true, "license": "MIT", "engines": { @@ -9656,10 +6206,14 @@ }, "node_modules/fast-deep-equal": { "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "license": "MIT" }, "node_modules/fast-glob": { "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", "license": "MIT", "optional": true, "dependencies": { @@ -9675,6 +6229,8 @@ }, "node_modules/fast-glob/node_modules/micromatch": { "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "license": "MIT", "optional": true, "dependencies": { @@ -9687,6 +6243,8 @@ }, "node_modules/fast-glob/node_modules/picomatch": { "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "license": "MIT", "optional": true, "engines": { @@ -9698,15 +6256,21 @@ }, "node_modules/fast-json-patch": { "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-3.1.1.tgz", + "integrity": "sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ==", "license": "MIT" }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "devOptional": true, "license": "MIT" }, "node_modules/fast-uri": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", "funding": [ { "type": "github", @@ -9721,6 +6285,8 @@ }, "node_modules/fastq": { "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", "license": "ISC", "optional": true, "dependencies": { @@ -9729,6 +6295,8 @@ }, "node_modules/fdir": { "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", "devOptional": true, "license": "MIT", "engines": { @@ -9745,6 +6313,8 @@ }, "node_modules/fill-range": { "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "devOptional": true, "license": "MIT", "dependencies": { @@ -9756,6 +6326,8 @@ }, "node_modules/finalhandler": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", + "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", "devOptional": true, "license": "MIT", "dependencies": { @@ -9772,6 +6344,8 @@ }, "node_modules/find-cache-directory": { "version": "6.0.0", + "resolved": "https://registry.npmjs.org/find-cache-directory/-/find-cache-directory-6.0.0.tgz", + "integrity": "sha512-CvFd5ivA6HcSHbD+59P7CyzINHXzwhuQK8RY7CxJZtgDSAtRlHiCaQpZQ2lMR/WRyUIEmzUvL6G2AGurMfegZA==", "dev": true, "license": "MIT", "dependencies": { @@ -9787,6 +6361,8 @@ }, "node_modules/find-cache-directory/node_modules/pkg-dir": { "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-8.0.0.tgz", + "integrity": "sha512-4peoBq4Wks0riS0z8741NVv+/8IiTvqnZAr8QGgtdifrtpdXbNw/FxRS1l6NFqm4EMzuS0EDqNNx4XGaz8cuyQ==", "dev": true, "license": "MIT", "dependencies": { @@ -9801,6 +6377,8 @@ }, "node_modules/find-up": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, "license": "MIT", "dependencies": { @@ -9816,6 +6394,8 @@ }, "node_modules/find-up-simple": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.1.tgz", + "integrity": "sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==", "dev": true, "license": "MIT", "engines": { @@ -9827,6 +6407,8 @@ }, "node_modules/find-versions": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-4.0.0.tgz", + "integrity": "sha512-wgpWy002tA+wgmO27buH/9KzyEOQnKsG/R0yrcjPT9BOFm0zRBVQbZ95nRGXWMywS8YR5knRbpohio0bcJABxQ==", "dev": true, "license": "MIT", "dependencies": { @@ -9841,6 +6423,8 @@ }, "node_modules/follow-redirects": { "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", "dev": true, "funding": [ { @@ -9860,6 +6444,8 @@ }, "node_modules/for-each": { "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", "license": "MIT", "dependencies": { "is-callable": "^1.2.7" @@ -9873,6 +6459,8 @@ }, "node_modules/foreground-child": { "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", "devOptional": true, "license": "ISC", "dependencies": { @@ -9888,6 +6476,8 @@ }, "node_modules/forwarded": { "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", "devOptional": true, "license": "MIT", "engines": { @@ -9896,6 +6486,8 @@ }, "node_modules/fresh": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", "devOptional": true, "license": "MIT", "engines": { @@ -9904,6 +6496,8 @@ }, "node_modules/fs-minipass": { "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", + "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", "devOptional": true, "license": "ISC", "dependencies": { @@ -9915,11 +6509,30 @@ }, "node_modules/fs.realpath": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true, "license": "ISC" }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/function-bind": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -9927,6 +6540,8 @@ }, "node_modules/fuse.js": { "version": "6.6.2", + "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-6.6.2.tgz", + "integrity": "sha512-cJaJkxCCxC8qIIcPBF9yGxY0W/tVZS3uEISDxhYIdtk8OL93pe+6Zj7LjCqVV4dzbqcriOZ+kQ/NE4RXZHsIGA==", "license": "Apache-2.0", "engines": { "node": ">=10" @@ -9934,6 +6549,8 @@ }, "node_modules/gensync": { "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", "dev": true, "license": "MIT", "engines": { @@ -9942,13 +6559,17 @@ }, "node_modules/get-caller-file": { "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "license": "ISC", "engines": { "node": "6.* || 8.* || >= 10.*" } }, "node_modules/get-east-asian-width": { - "version": "1.3.1", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz", + "integrity": "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==", "license": "MIT", "engines": { "node": ">=18" @@ -9959,6 +6580,8 @@ }, "node_modules/get-intrinsic": { "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", @@ -9981,6 +6604,8 @@ }, "node_modules/get-proto": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", "license": "MIT", "dependencies": { "dunder-proto": "^1.0.1", @@ -9992,6 +6617,8 @@ }, "node_modules/get-stream": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true, "license": "MIT", "engines": { @@ -10003,6 +6630,8 @@ }, "node_modules/glob": { "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "devOptional": true, "license": "ISC", "dependencies": { @@ -10022,6 +6651,8 @@ }, "node_modules/glob-parent": { "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "license": "ISC", "optional": true, "dependencies": { @@ -10033,11 +6664,15 @@ }, "node_modules/glob-to-regexp": { "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", "dev": true, "license": "BSD-2-Clause" }, "node_modules/glob/node_modules/minimatch": { "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "devOptional": true, "license": "ISC", "dependencies": { @@ -10052,6 +6687,8 @@ }, "node_modules/gopd": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -10062,11 +6699,15 @@ }, "node_modules/graceful-fs": { "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "devOptional": true, "license": "ISC" }, "node_modules/has-flag": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, "license": "MIT", "engines": { @@ -10075,6 +6716,8 @@ }, "node_modules/has-property-descriptors": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "license": "MIT", "dependencies": { "es-define-property": "^1.0.0" @@ -10085,6 +6728,8 @@ }, "node_modules/has-symbols": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -10095,6 +6740,8 @@ }, "node_modules/has-tostringtag": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "license": "MIT", "dependencies": { "has-symbols": "^1.0.3" @@ -10107,14 +6754,24 @@ } }, "node_modules/hash-base": { - "version": "2.0.2", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.2.tgz", + "integrity": "sha512-Bb33KbowVTIj5s7Ked1OsqHUeCpz//tPwR+E2zJgJKo9Z5XolZ9b6bdUgjmYlwnWhoOQKoTd1TYToZGn5mAYOg==", "license": "MIT", "dependencies": { - "inherits": "^2.0.1" + "inherits": "^2.0.4", + "readable-stream": "^2.3.8", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.1" + }, + "engines": { + "node": ">= 0.8" } }, "node_modules/hasown": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -10125,6 +6782,8 @@ }, "node_modules/he": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true, "license": "MIT", "bin": { @@ -10132,7 +6791,9 @@ } }, "node_modules/hosted-git-info": { - "version": "9.0.0", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-9.0.2.tgz", + "integrity": "sha512-M422h7o/BR3rmCQ8UHi7cyyMqKltdP9Uo+J2fXK+RSAY+wTcKOIRyhTuKv4qn+DJf3g+PL890AzId5KZpX+CBg==", "devOptional": true, "license": "ISC", "dependencies": { @@ -10143,7 +6804,9 @@ } }, "node_modules/hosted-git-info/node_modules/lru-cache": { - "version": "11.2.1", + "version": "11.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.2.tgz", + "integrity": "sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==", "devOptional": true, "license": "ISC", "engines": { @@ -10152,6 +6815,8 @@ }, "node_modules/html-encoding-sniffer": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", + "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", "dev": true, "license": "MIT", "dependencies": { @@ -10163,6 +6828,8 @@ }, "node_modules/htmlparser2": { "version": "10.0.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.0.0.tgz", + "integrity": "sha512-TwAZM+zE5Tq3lrEHvOlvwgj1XLWQCtaaibSN11Q+gGBAS7Y1uZSWwXXRe4iF6OXnaq1riyQAPFOBtYc77Mxq0g==", "dev": true, "funding": [ "https://github.com/fb55/htmlparser2?sponsor=1", @@ -10181,6 +6848,8 @@ }, "node_modules/htmlparser2/node_modules/entities": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", "dev": true, "license": "BSD-2-Clause", "engines": { @@ -10192,11 +6861,15 @@ }, "node_modules/http-cache-semantics": { "version": "4.2.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", "devOptional": true, "license": "BSD-2-Clause" }, "node_modules/http-errors": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", "devOptional": true, "license": "MIT", "dependencies": { @@ -10212,6 +6885,8 @@ }, "node_modules/http-errors/node_modules/statuses": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", "devOptional": true, "license": "MIT", "engines": { @@ -10220,6 +6895,8 @@ }, "node_modules/http-proxy": { "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", "dev": true, "license": "MIT", "dependencies": { @@ -10233,6 +6910,8 @@ }, "node_modules/http-proxy-agent": { "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", "devOptional": true, "license": "MIT", "dependencies": { @@ -10245,6 +6924,8 @@ }, "node_modules/http-server": { "version": "14.1.1", + "resolved": "https://registry.npmjs.org/http-server/-/http-server-14.1.1.tgz", + "integrity": "sha512-+cbxadF40UXd9T01zUHgA+rlo2Bg1Srer4+B4NwIHdaGxAGGv59nYRnGGDJ9LBk7alpS0US+J+bLLdQOOkJq4A==", "dev": true, "license": "MIT", "dependencies": { @@ -10271,6 +6952,8 @@ }, "node_modules/http-server/node_modules/ansi-styles": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", "dependencies": { @@ -10285,6 +6968,8 @@ }, "node_modules/http-server/node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "license": "MIT", "dependencies": { @@ -10300,6 +6985,8 @@ }, "node_modules/http-server/node_modules/mime": { "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", "dev": true, "license": "MIT", "bin": { @@ -10311,6 +6998,8 @@ }, "node_modules/https-proxy-agent": { "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", "devOptional": true, "license": "MIT", "dependencies": { @@ -10323,6 +7012,8 @@ }, "node_modules/human-signals": { "version": "4.3.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", + "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", "dev": true, "license": "Apache-2.0", "engines": { @@ -10331,6 +7022,8 @@ }, "node_modules/husky": { "version": "4.3.8", + "resolved": "https://registry.npmjs.org/husky/-/husky-4.3.8.tgz", + "integrity": "sha512-LCqqsB0PzJQ/AlCgfrfzRe3e3+NvmefAdKQhRYpxS4u6clblBoDdzzvHi8fmxKRzvMxPY/1WZWzomPZww0Anow==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -10360,6 +7053,8 @@ }, "node_modules/husky/node_modules/ansi-styles": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", "dependencies": { @@ -10374,6 +7069,8 @@ }, "node_modules/husky/node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "license": "MIT", "dependencies": { @@ -10388,7 +7085,9 @@ } }, "node_modules/iconv-lite": { - "version": "0.6.3", + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", + "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", "devOptional": true, "license": "MIT", "dependencies": { @@ -10396,10 +7095,16 @@ }, "engines": { "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/ieee754": { "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", "funding": [ { "type": "github", @@ -10418,6 +7123,8 @@ }, "node_modules/ignore-walk": { "version": "8.0.0", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-8.0.0.tgz", + "integrity": "sha512-FCeMZT4NiRQGh+YkeKMtWrOmBgWjHjMJ26WQWrRQyoyzqevdaGSakUaJW5xQYmjLlUVk2qUnCjYVBax9EKKg8A==", "devOptional": true, "license": "ISC", "dependencies": { @@ -10429,6 +7136,8 @@ }, "node_modules/ignore-walk/node_modules/minimatch": { "version": "10.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.3.tgz", + "integrity": "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==", "devOptional": true, "license": "ISC", "dependencies": { @@ -10443,6 +7152,8 @@ }, "node_modules/image-size": { "version": "0.5.5", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", + "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", "dev": true, "license": "MIT", "optional": true, @@ -10454,12 +7165,16 @@ } }, "node_modules/immutable": { - "version": "5.1.3", + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.4.tgz", + "integrity": "sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA==", "dev": true, "license": "MIT" }, "node_modules/import-fresh": { "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", "dev": true, "license": "MIT", "dependencies": { @@ -10475,6 +7190,8 @@ }, "node_modules/imurmurhash": { "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "devOptional": true, "license": "MIT", "engines": { @@ -10483,6 +7200,9 @@ }, "node_modules/inflight": { "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "dev": true, "license": "ISC", "dependencies": { @@ -10492,10 +7212,14 @@ }, "node_modules/inherits": { "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "license": "ISC" }, "node_modules/ini": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-5.0.0.tgz", + "integrity": "sha512-+N0ngpO3e7cRUWOJAS7qw0IZIVc6XPrW4MlFBdD066F2L4k1L6ker3hLqSq7iXxU5tgS4WGkIUElWn5vogAEnw==", "devOptional": true, "license": "ISC", "engines": { @@ -10503,7 +7227,9 @@ } }, "node_modules/injection-js": { - "version": "2.5.0", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/injection-js/-/injection-js-2.6.1.tgz", + "integrity": "sha512-dbR5bdhi7TWDoCye9cByZqeg/gAfamm8Vu3G1KZOTYkOif8WkuM8CD0oeDPtZYMzT5YH76JAFB7bkmyY9OJi2A==", "dev": true, "license": "MIT", "dependencies": { @@ -10511,14 +7237,16 @@ } }, "node_modules/inquirer": { - "version": "12.9.4", + "version": "12.10.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-12.10.0.tgz", + "integrity": "sha512-K/epfEnDBZj2Q3NMDcgXWZye3nhSPeoJnOh8lcKWrldw54UEZfS4EmAMsAsmVbl7qKi+vjAsy39Sz4fbgRMewg==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.2.0", - "@inquirer/prompts": "^7.8.4", - "@inquirer/type": "^3.0.8", - "ansi-escapes": "^4.3.2", + "@inquirer/ansi": "^1.0.1", + "@inquirer/core": "^10.3.0", + "@inquirer/prompts": "^7.9.0", + "@inquirer/type": "^3.0.9", "mute-stream": "^2.0.0", "run-async": "^4.0.5", "rxjs": "^7.8.2" @@ -10536,12 +7264,14 @@ } }, "node_modules/inquirer/node_modules/@inquirer/confirm": { - "version": "5.1.16", + "version": "5.1.19", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.19.tgz", + "integrity": "sha512-wQNz9cfcxrtEnUyG5PndC8g3gZ7lGDBzmWiXZkX8ot3vfZ+/BLjR8EvyGX4YzQLeVqtAlY/YScZpW7CW8qMoDQ==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.2.0", - "@inquirer/type": "^3.0.8" + "@inquirer/core": "^10.3.0", + "@inquirer/type": "^3.0.9" }, "engines": { "node": ">=18" @@ -10556,20 +7286,22 @@ } }, "node_modules/inquirer/node_modules/@inquirer/prompts": { - "version": "7.8.4", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.9.0.tgz", + "integrity": "sha512-X7/+dG9SLpSzRkwgG5/xiIzW0oMrV3C0HOa7YHG1WnrLK+vCQHfte4k/T80059YBdei29RBC3s+pSMvPJDU9/A==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/checkbox": "^4.2.2", - "@inquirer/confirm": "^5.1.16", - "@inquirer/editor": "^4.2.18", - "@inquirer/expand": "^4.0.18", - "@inquirer/input": "^4.2.2", - "@inquirer/number": "^3.0.18", - "@inquirer/password": "^4.0.18", - "@inquirer/rawlist": "^4.1.6", - "@inquirer/search": "^3.1.1", - "@inquirer/select": "^4.3.2" + "@inquirer/checkbox": "^4.3.0", + "@inquirer/confirm": "^5.1.19", + "@inquirer/editor": "^4.2.21", + "@inquirer/expand": "^4.0.21", + "@inquirer/input": "^4.2.5", + "@inquirer/number": "^3.0.21", + "@inquirer/password": "^4.0.21", + "@inquirer/rawlist": "^4.1.9", + "@inquirer/search": "^3.2.0", + "@inquirer/select": "^4.4.0" }, "engines": { "node": ">=18" @@ -10585,6 +7317,8 @@ }, "node_modules/ip-address": { "version": "10.0.1", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.0.1.tgz", + "integrity": "sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==", "devOptional": true, "license": "MIT", "engines": { @@ -10593,6 +7327,8 @@ }, "node_modules/ipaddr.js": { "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", "devOptional": true, "license": "MIT", "engines": { @@ -10601,11 +7337,15 @@ }, "node_modules/is-arrayish": { "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", "dev": true, "license": "MIT" }, "node_modules/is-callable": { "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -10616,6 +7356,8 @@ }, "node_modules/is-core-module": { "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", "devOptional": true, "license": "MIT", "dependencies": { @@ -10630,6 +7372,8 @@ }, "node_modules/is-docker": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", "dev": true, "license": "MIT", "bin": { @@ -10644,6 +7388,8 @@ }, "node_modules/is-extglob": { "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "license": "MIT", "optional": true, "engines": { @@ -10652,6 +7398,8 @@ }, "node_modules/is-fullwidth-code-point": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", "devOptional": true, "license": "MIT", "engines": { @@ -10663,6 +7411,8 @@ }, "node_modules/is-glob": { "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "license": "MIT", "optional": true, "dependencies": { @@ -10674,6 +7424,8 @@ }, "node_modules/is-inside-container": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", "dev": true, "license": "MIT", "dependencies": { @@ -10691,6 +7443,8 @@ }, "node_modules/is-interactive": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", + "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", "license": "MIT", "engines": { "node": ">=12" @@ -10701,6 +7455,8 @@ }, "node_modules/is-number": { "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "devOptional": true, "license": "MIT", "engines": { @@ -10709,11 +7465,15 @@ }, "node_modules/is-promise": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", "devOptional": true, "license": "MIT" }, "node_modules/is-stream": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", "dev": true, "license": "MIT", "engines": { @@ -10725,6 +7485,8 @@ }, "node_modules/is-typed-array": { "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", "license": "MIT", "dependencies": { "which-typed-array": "^1.1.16" @@ -10738,6 +7500,8 @@ }, "node_modules/is-unicode-supported": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", "license": "MIT", "engines": { "node": ">=18" @@ -10748,11 +7512,15 @@ }, "node_modules/is-what": { "version": "3.14.1", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", + "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", "dev": true, "license": "MIT" }, "node_modules/is-wsl": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", + "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", "dev": true, "license": "MIT", "dependencies": { @@ -10766,16 +7534,22 @@ } }, "node_modules/isarray": { - "version": "2.0.5", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "license": "MIT" }, "node_modules/isexe": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "devOptional": true, "license": "ISC" }, "node_modules/istanbul-lib-coverage": { "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -10784,6 +7558,8 @@ }, "node_modules/istanbul-lib-instrument": { "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -10799,6 +7575,8 @@ }, "node_modules/jackspeak": { "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", "devOptional": true, "license": "BlueOak-1.0.0", "dependencies": { @@ -10813,6 +7591,8 @@ }, "node_modules/jose": { "version": "4.15.9", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.9.tgz", + "integrity": "sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/panva" @@ -10820,11 +7600,15 @@ }, "node_modules/js-tokens": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "dev": true, "license": "MIT" }, "node_modules/js-yaml": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "license": "MIT", "dependencies": { "argparse": "^2.0.1" @@ -10835,6 +7619,8 @@ }, "node_modules/jsesc": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", "dev": true, "license": "MIT", "bin": { @@ -10846,6 +7632,8 @@ }, "node_modules/json-parse-even-better-errors": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-4.0.0.tgz", + "integrity": "sha512-lR4MXjGNgkJc7tkQ97kb2nuEMnNCyU//XYVH0MKTGcXEiSudQ5MKGKen3C5QubYy0vmq+JGitUg92uuywGEwIA==", "devOptional": true, "license": "MIT", "engines": { @@ -10854,10 +7642,14 @@ }, "node_modules/json-schema-traverse": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "license": "MIT" }, "node_modules/json5": { "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, "license": "MIT", "bin": { @@ -10869,10 +7661,14 @@ }, "node_modules/jsonc-parser": { "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", "license": "MIT" }, "node_modules/jsonparse": { "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", "devOptional": true, "engines": [ "node >= 0.2.0" @@ -10880,9 +7676,12 @@ "license": "MIT" }, "node_modules/less": { - "version": "4.4.1", + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/less/-/less-4.4.2.tgz", + "integrity": "sha512-j1n1IuTX1VQjIy3tT7cyGbX7nvQOsFLoIqobZv4ttI5axP923gA44zUj6miiA6R5Aoms4sEGVIIcucXUbRI14g==", "dev": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "copy-anything": "^2.0.1", "parse-node-version": "^1.0.1", @@ -10906,6 +7705,8 @@ }, "node_modules/less/node_modules/mime": { "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", "dev": true, "license": "MIT", "optional": true, @@ -10918,6 +7719,8 @@ }, "node_modules/less/node_modules/source-map": { "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, "license": "BSD-3-Clause", "optional": true, @@ -10926,12 +7729,16 @@ } }, "node_modules/libphonenumber-js": { - "version": "1.12.15", + "version": "1.12.24", + "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.12.24.tgz", + "integrity": "sha512-l5IlyL9AONj4voSd7q9xkuQOL4u8Ty44puTic7J88CmdXkxfGsRfoVLXHCxppwehgpb/Chdb80FFehHqjN3ItQ==", "license": "MIT", "peer": true }, "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": { @@ -10940,11 +7747,15 @@ }, "node_modules/lines-and-columns": { "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "dev": true, "license": "MIT" }, "node_modules/lint-staged": { "version": "13.3.0", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-13.3.0.tgz", + "integrity": "sha512-mPRtrYnipYYv1FEE134ufbWpeggNTo+O/UPzngoaKzbzHAthvR55am+8GfHTnqNRQVRRrYQLGW9ZyUoD7DsBHQ==", "dev": true, "license": "MIT", "dependencies": { @@ -10971,6 +7782,8 @@ }, "node_modules/lint-staged/node_modules/ansi-escapes": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-5.0.0.tgz", + "integrity": "sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA==", "dev": true, "license": "MIT", "dependencies": { @@ -10985,6 +7798,8 @@ }, "node_modules/lint-staged/node_modules/chalk": { "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", "dev": true, "license": "MIT", "engines": { @@ -10996,6 +7811,8 @@ }, "node_modules/lint-staged/node_modules/cli-cursor": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", + "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==", "dev": true, "license": "MIT", "dependencies": { @@ -11010,6 +7827,8 @@ }, "node_modules/lint-staged/node_modules/cli-truncate": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-3.1.0.tgz", + "integrity": "sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==", "dev": true, "license": "MIT", "dependencies": { @@ -11025,6 +7844,8 @@ }, "node_modules/lint-staged/node_modules/commander": { "version": "11.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.0.0.tgz", + "integrity": "sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ==", "dev": true, "license": "MIT", "engines": { @@ -11033,6 +7854,8 @@ }, "node_modules/lint-staged/node_modules/debug": { "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "license": "MIT", "dependencies": { @@ -11049,16 +7872,22 @@ }, "node_modules/lint-staged/node_modules/emoji-regex": { "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "dev": true, "license": "MIT" }, "node_modules/lint-staged/node_modules/eventemitter3": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", "dev": true, "license": "MIT" }, "node_modules/lint-staged/node_modules/listr2": { "version": "6.6.1", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-6.6.1.tgz", + "integrity": "sha512-+rAXGHh0fkEWdXBmX+L6mmfmXmXvDGEKzkjxO+8mP3+nI/r/CWznVBvsibXdxda9Zz0OW2e2ikphN3OwCT/jSg==", "dev": true, "license": "MIT", "dependencies": { @@ -11083,6 +7912,8 @@ }, "node_modules/lint-staged/node_modules/log-update": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-5.0.1.tgz", + "integrity": "sha512-5UtUDQ/6edw4ofyljDNcOVJQ4c7OjDro4h3y8e1GQL5iYElYclVHJ3zeWchylvMaKnDbDilC8irOVyexnA/Slw==", "dev": true, "license": "MIT", "dependencies": { @@ -11101,6 +7932,8 @@ }, "node_modules/lint-staged/node_modules/mimic-fn": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true, "license": "MIT", "engines": { @@ -11109,11 +7942,15 @@ }, "node_modules/lint-staged/node_modules/ms": { "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true, "license": "MIT" }, "node_modules/lint-staged/node_modules/onetime": { "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "dev": true, "license": "MIT", "dependencies": { @@ -11128,6 +7965,8 @@ }, "node_modules/lint-staged/node_modules/restore-cursor": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", + "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==", "dev": true, "license": "MIT", "dependencies": { @@ -11143,11 +7982,15 @@ }, "node_modules/lint-staged/node_modules/signal-exit": { "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true, "license": "ISC" }, "node_modules/lint-staged/node_modules/string-width": { "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "dev": true, "license": "MIT", "dependencies": { @@ -11162,19 +8005,10 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lint-staged/node_modules/type-fest": { - "version": "1.4.0", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/lint-staged/node_modules/wrap-ansi": { "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "dev": true, "license": "MIT", "dependencies": { @@ -11191,6 +8025,8 @@ }, "node_modules/lint-staged/node_modules/yaml": { "version": "2.3.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.1.tgz", + "integrity": "sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==", "dev": true, "license": "ISC", "engines": { @@ -11199,8 +8035,11 @@ }, "node_modules/listr2": { "version": "9.0.1", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-9.0.1.tgz", + "integrity": "sha512-SL0JY3DaxylDuo/MecFeiC+7pedM0zia33zl0vcjgwcq1q1FWWF1To9EIauPbl8GbMCU0R2e0uJ8bZunhYKD2g==", "devOptional": true, "license": "MIT", + "peer": true, "dependencies": { "cli-truncate": "^4.0.0", "colorette": "^2.0.20", @@ -11215,11 +8054,15 @@ }, "node_modules/listr2/node_modules/eventemitter3": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", "devOptional": true, "license": "MIT" }, "node_modules/listr2/node_modules/wrap-ansi": { "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", "devOptional": true, "license": "MIT", "dependencies": { @@ -11236,6 +8079,8 @@ }, "node_modules/lmdb": { "version": "3.4.2", + "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-3.4.2.tgz", + "integrity": "sha512-nwVGUfTBUwJKXd6lRV8pFNfnrCC1+l49ESJRM19t/tFb/97QfJEixe5DYRvug5JO7DSFKoKaVy7oGMt5rVqZvg==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -11262,6 +8107,8 @@ }, "node_modules/locate-path": { "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, "license": "MIT", "dependencies": { @@ -11276,10 +8123,14 @@ }, "node_modules/lodash": { "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "license": "MIT" }, "node_modules/log-symbols": { "version": "6.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz", + "integrity": "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==", "license": "MIT", "dependencies": { "chalk": "^5.3.0", @@ -11294,6 +8145,8 @@ }, "node_modules/log-symbols/node_modules/is-unicode-supported": { "version": "1.3.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", + "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", "license": "MIT", "engines": { "node": ">=12" @@ -11304,6 +8157,8 @@ }, "node_modules/log-update": { "version": "6.1.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", + "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", "devOptional": true, "license": "MIT", "dependencies": { @@ -11320,22 +8175,10 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/log-update/node_modules/ansi-escapes": { - "version": "7.1.0", - "devOptional": true, - "license": "MIT", - "dependencies": { - "environment": "^1.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/log-update/node_modules/is-fullwidth-code-point": { "version": "5.1.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", + "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", "devOptional": true, "license": "MIT", "dependencies": { @@ -11350,6 +8193,8 @@ }, "node_modules/log-update/node_modules/slice-ansi": { "version": "7.1.2", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", + "integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==", "devOptional": true, "license": "MIT", "dependencies": { @@ -11365,6 +8210,8 @@ }, "node_modules/log-update/node_modules/wrap-ansi": { "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", "devOptional": true, "license": "MIT", "dependencies": { @@ -11381,10 +8228,14 @@ }, "node_modules/long": { "version": "5.3.2", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", "license": "Apache-2.0" }, "node_modules/lru-cache": { "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dev": true, "license": "ISC", "dependencies": { @@ -11393,6 +8244,8 @@ }, "node_modules/luxon": { "version": "3.3.0", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.3.0.tgz", + "integrity": "sha512-An0UCfG/rSiqtAIiBPO0Y9/zAnHUZxAMiCpTd5h2smgsj7GGmcenvrvww2cqNA8/4A5ZrD1gJpHN2mIHZQF+Mg==", "license": "MIT", "engines": { "node": ">=12" @@ -11400,6 +8253,8 @@ }, "node_modules/magic-string": { "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" @@ -11407,6 +8262,8 @@ }, "node_modules/make-dir": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", "dev": true, "license": "MIT", "optional": true, @@ -11420,6 +8277,8 @@ }, "node_modules/make-dir/node_modules/semver": { "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, "license": "ISC", "optional": true, @@ -11429,11 +8288,15 @@ }, "node_modules/make-error": { "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", "dev": true, "license": "ISC" }, "node_modules/make-fetch-happen": { "version": "14.0.3", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-14.0.3.tgz", + "integrity": "sha512-QMjGbFTP0blj97EeidG5hk/QhKQ3T4ICckQGLgz38QF7Vgbk6e6FTARN8KhKxyBbWn8R0HU+bnw8aSoFPD4qtQ==", "devOptional": true, "license": "ISC", "dependencies": { @@ -11455,6 +8318,8 @@ }, "node_modules/marked": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", + "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", "license": "MIT", "bin": { "marked": "bin/marked.js" @@ -11465,13 +8330,28 @@ }, "node_modules/math-intrinsics": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", "license": "MIT", "engines": { "node": ">= 0.4" } }, + "node_modules/md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "license": "MIT", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, "node_modules/media-typer": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", "devOptional": true, "license": "MIT", "engines": { @@ -11480,6 +8360,8 @@ }, "node_modules/merge-descriptors": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", "devOptional": true, "license": "MIT", "engines": { @@ -11491,11 +8373,15 @@ }, "node_modules/merge-stream": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", "dev": true, "license": "MIT" }, "node_modules/merge2": { "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "license": "MIT", "optional": true, "engines": { @@ -11504,6 +8390,8 @@ }, "node_modules/micromatch": { "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "dev": true, "license": "MIT", "dependencies": { @@ -11516,6 +8404,8 @@ }, "node_modules/micromatch/node_modules/picomatch": { "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, "license": "MIT", "engines": { @@ -11526,7 +8416,9 @@ } }, "node_modules/mime": { - "version": "4.0.7", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-4.1.0.tgz", + "integrity": "sha512-X5ju04+cAzsojXKes0B/S4tcYtFAJ6tTMuSPBEn9CPGlrWr8Fiw7qYeLT0XyH80HSoAoqWCaz+MWKh22P7G1cw==", "funding": [ "https://github.com/sponsors/broofa" ], @@ -11540,6 +8432,8 @@ }, "node_modules/mime-db": { "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", "devOptional": true, "license": "MIT", "engines": { @@ -11548,6 +8442,8 @@ }, "node_modules/mime-types": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -11559,6 +8455,8 @@ }, "node_modules/mimic-fn": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", "dev": true, "license": "MIT", "engines": { @@ -11570,6 +8468,8 @@ }, "node_modules/mimic-function": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", "license": "MIT", "engines": { "node": ">=18" @@ -11580,6 +8480,8 @@ }, "node_modules/minimatch": { "version": "10.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", + "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", "license": "ISC", "optional": true, "dependencies": { @@ -11594,6 +8496,8 @@ }, "node_modules/minimist": { "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true, "license": "MIT", "funding": { @@ -11602,6 +8506,8 @@ }, "node_modules/minipass": { "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "devOptional": true, "license": "ISC", "engines": { @@ -11610,6 +8516,8 @@ }, "node_modules/minipass-collect": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", + "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", "devOptional": true, "license": "ISC", "dependencies": { @@ -11621,6 +8529,8 @@ }, "node_modules/minipass-fetch": { "version": "4.0.1", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-4.0.1.tgz", + "integrity": "sha512-j7U11C5HXigVuutxebFadoYBbd7VSdZWggSe64NVdvWNBqGAiXPL2QVCehjmw7lY1oF9gOllYbORh+hiNgfPgQ==", "devOptional": true, "license": "MIT", "dependencies": { @@ -11637,6 +8547,8 @@ }, "node_modules/minipass-flush": { "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", "devOptional": true, "license": "ISC", "dependencies": { @@ -11648,6 +8560,8 @@ }, "node_modules/minipass-flush/node_modules/minipass": { "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "devOptional": true, "license": "ISC", "dependencies": { @@ -11659,11 +8573,15 @@ }, "node_modules/minipass-flush/node_modules/yallist": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "devOptional": true, "license": "ISC" }, "node_modules/minipass-pipeline": { "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", "devOptional": true, "license": "ISC", "dependencies": { @@ -11675,6 +8593,8 @@ }, "node_modules/minipass-pipeline/node_modules/minipass": { "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "devOptional": true, "license": "ISC", "dependencies": { @@ -11686,11 +8606,15 @@ }, "node_modules/minipass-pipeline/node_modules/yallist": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "devOptional": true, "license": "ISC" }, "node_modules/minipass-sized": { "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", "devOptional": true, "license": "ISC", "dependencies": { @@ -11702,6 +8626,8 @@ }, "node_modules/minipass-sized/node_modules/minipass": { "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "devOptional": true, "license": "ISC", "dependencies": { @@ -11713,11 +8639,15 @@ }, "node_modules/minipass-sized/node_modules/yallist": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "devOptional": true, "license": "ISC" }, "node_modules/minizlib": { - "version": "3.0.2", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", + "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", "devOptional": true, "license": "MIT", "dependencies": { @@ -11729,6 +8659,8 @@ }, "node_modules/mkdirp": { "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "devOptional": true, "license": "MIT", "bin": { @@ -11740,10 +8672,14 @@ }, "node_modules/monaco-editor": { "version": "0.33.0", + "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.33.0.tgz", + "integrity": "sha512-VcRWPSLIUEgQJQIE0pVT8FcGBIgFoxz7jtqctE+IiCxWugD0DwgyQBcZBhdSrdMC84eumoqMZsGl2GTreOzwqw==", "license": "MIT" }, "node_modules/mrmime": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", "dev": true, "license": "MIT", "engines": { @@ -11752,11 +8688,15 @@ }, "node_modules/ms": { "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "devOptional": true, "license": "MIT" }, "node_modules/msgpackr": { "version": "1.11.5", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.11.5.tgz", + "integrity": "sha512-UjkUHN0yqp9RWKy0Lplhh+wlpdt9oQBYgULZOiFhV3VclSF1JnSQWZ5r9gORQlNYaUKQoR8itv7g7z1xDDuACA==", "dev": true, "license": "MIT", "optional": true, @@ -11766,6 +8706,8 @@ }, "node_modules/msgpackr-extract": { "version": "3.0.3", + "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.3.tgz", + "integrity": "sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -11787,6 +8729,8 @@ }, "node_modules/multimatch": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-5.0.0.tgz", + "integrity": "sha512-ypMKuglUrZUD99Tk2bUQ+xNQj43lPEfAeX2o9cTteAmShXy2VHDJpuwu1o0xqoKCt9jLVAvwyFKdLTPXKAfJyA==", "license": "MIT", "optional": true, "dependencies": { @@ -11805,6 +8749,8 @@ }, "node_modules/multimatch/node_modules/brace-expansion": { "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "license": "MIT", "optional": true, "dependencies": { @@ -11814,6 +8760,8 @@ }, "node_modules/multimatch/node_modules/minimatch": { "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "license": "ISC", "optional": true, "dependencies": { @@ -11825,6 +8773,8 @@ }, "node_modules/mustache": { "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", + "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", "license": "MIT", "bin": { "mustache": "bin/mustache" @@ -11832,6 +8782,8 @@ }, "node_modules/mute-stream": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", + "integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==", "devOptional": true, "license": "ISC", "engines": { @@ -11840,6 +8792,8 @@ }, "node_modules/nanoid": { "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", "dev": true, "funding": [ { @@ -11857,6 +8811,8 @@ }, "node_modules/needle": { "version": "3.3.1", + "resolved": "https://registry.npmjs.org/needle/-/needle-3.3.1.tgz", + "integrity": "sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==", "dev": true, "license": "MIT", "optional": true, @@ -11871,8 +8827,24 @@ "node": ">= 4.4.x" } }, + "node_modules/needle/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/negotiator": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", "devOptional": true, "license": "MIT", "engines": { @@ -11881,6 +8853,8 @@ }, "node_modules/ng-morph": { "version": "4.8.4", + "resolved": "https://registry.npmjs.org/ng-morph/-/ng-morph-4.8.4.tgz", + "integrity": "sha512-XwL53wCOhyaAxvoekN74ONbWUK30huzp+GpZYyC01RfaG2AX9l7YlC1mGG/l7Rx7YXtFAk85VFnNJqn2e46K8g==", "license": "Apache-2.0", "optional": true, "dependencies": { @@ -11896,9 +8870,12 @@ } }, "node_modules/ng-packagr": { - "version": "20.2.0", + "version": "20.3.0", + "resolved": "https://registry.npmjs.org/ng-packagr/-/ng-packagr-20.3.0.tgz", + "integrity": "sha512-hwPZNeV/6C3pWojK70AHxe6uk1rz2bzoe+WdH+GIWouUcyXrjYQjOFyLfOGD0ia9D+yWVzjsi4CKVK/dQFDQ6Q==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@ampproject/remapping": "^2.3.0", "@rollup/plugin-json": "^6.1.0", @@ -11932,7 +8909,7 @@ "rollup": "^4.24.0" }, "peerDependencies": { - "@angular/compiler-cli": "^20.0.0 || ^20.2.0-rc", + "@angular/compiler-cli": "^20.0.0", "tailwindcss": "^2.0.0 || ^3.0.0 || ^4.0.0", "tslib": "^2.3.0", "typescript": ">=5.8 <6.0" @@ -11944,7 +8921,9 @@ } }, "node_modules/ng-packagr/node_modules/commander": { - "version": "14.0.0", + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.1.tgz", + "integrity": "sha512-2JkV3gUZUVrbNA+1sjBOYLsMZ5cEEl8GTFP2a4AVz5hvasAMCQ1D2l2le/cX+pV4N6ZU17zjUahLpIXRrnWL8A==", "dev": true, "license": "MIT", "engines": { @@ -11953,6 +8932,8 @@ }, "node_modules/ng-qrcode": { "version": "20.0.0", + "resolved": "https://registry.npmjs.org/ng-qrcode/-/ng-qrcode-20.0.0.tgz", + "integrity": "sha512-uAUVn9UXdTOY4IjB8+JtXfNWSIkpK7e9jgD8MPrzSftKA4KJZV6sX5VuJHKpTOFMM5SOVBSlO21U844OVjbXWA==", "license": "MIT", "dependencies": { "qrcode": "^1.5.3", @@ -11965,19 +8946,25 @@ }, "node_modules/node-addon-api": { "version": "6.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", + "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==", "dev": true, "license": "MIT", "optional": true }, "node_modules/node-forge": { "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", "license": "(BSD-3-Clause OR GPL-2.0)", "engines": { "node": ">= 6.13.0" } }, "node_modules/node-gyp": { - "version": "11.4.2", + "version": "11.5.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-11.5.0.tgz", + "integrity": "sha512-ra7Kvlhxn5V9Slyus0ygMa2h+UqExPqUIkfk7Pc8QTLT956JLSy51uWFwHtIYy0vI8cB4BDhc/S03+880My/LQ==", "devOptional": true, "license": "MIT", "dependencies": { @@ -12001,6 +8988,8 @@ }, "node_modules/node-gyp-build-optional-packages": { "version": "5.2.2", + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.2.2.tgz", + "integrity": "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==", "dev": true, "license": "MIT", "optional": true, @@ -12015,6 +9004,8 @@ }, "node_modules/node-gyp/node_modules/chownr": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", "devOptional": true, "license": "BlueOak-1.0.0", "engines": { @@ -12023,36 +9014,25 @@ }, "node_modules/node-gyp/node_modules/isexe": { "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", "devOptional": true, "license": "ISC", "engines": { "node": ">=16" } }, - "node_modules/node-gyp/node_modules/mkdirp": { - "version": "3.0.1", - "devOptional": true, - "license": "MIT", - "bin": { - "mkdirp": "dist/cjs/src/bin.js" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/node-gyp/node_modules/tar": { - "version": "7.4.3", + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.1.tgz", + "integrity": "sha512-nlGpxf+hv0v7GkWBK2V9spgactGOp0qvfWRxUMjqHyzrt3SgwE48DIv/FhqPHJYLHpgW1opq3nERbz5Anq7n1g==", "devOptional": true, "license": "ISC", "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", - "minizlib": "^3.0.1", - "mkdirp": "^3.0.1", + "minizlib": "^3.1.0", "yallist": "^5.0.0" }, "engines": { @@ -12061,6 +9041,8 @@ }, "node_modules/node-gyp/node_modules/which": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz", + "integrity": "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==", "devOptional": true, "license": "ISC", "dependencies": { @@ -12075,6 +9057,8 @@ }, "node_modules/node-gyp/node_modules/yallist": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", "devOptional": true, "license": "BlueOak-1.0.0", "engines": { @@ -12083,6 +9067,8 @@ }, "node_modules/node-html-parser": { "version": "5.4.2", + "resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-5.4.2.tgz", + "integrity": "sha512-RaBPP3+51hPne/OolXxcz89iYvQvKOydaqoePpOgXcrOKZhjVIzmpKZz+Hd/RBO2/zN2q6CNJhQzucVz+u3Jyw==", "dev": true, "license": "MIT", "dependencies": { @@ -12092,6 +9078,8 @@ }, "node_modules/node-html-parser/node_modules/css-select": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -12107,6 +9095,8 @@ }, "node_modules/node-html-parser/node_modules/css-what": { "version": "6.2.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", + "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", "dev": true, "license": "BSD-2-Clause", "engines": { @@ -12118,6 +9108,8 @@ }, "node_modules/node-html-parser/node_modules/dom-serializer": { "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", "dev": true, "license": "MIT", "dependencies": { @@ -12131,6 +9123,8 @@ }, "node_modules/node-html-parser/node_modules/domhandler": { "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -12145,6 +9139,8 @@ }, "node_modules/node-html-parser/node_modules/domutils": { "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -12158,6 +9154,8 @@ }, "node_modules/node-jose": { "version": "2.2.0", + "resolved": "https://registry.npmjs.org/node-jose/-/node-jose-2.2.0.tgz", + "integrity": "sha512-XPCvJRr94SjLrSIm4pbYHKLEaOsDvJCpyFw/6V/KK/IXmyZ6SFBzAUDO9HQf4DB/nTEFcRGH87mNciOP23kFjw==", "license": "Apache-2.0", "dependencies": { "base64url": "^3.0.1", @@ -12173,6 +9171,8 @@ }, "node_modules/node-jose/node_modules/uuid": { "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", "funding": [ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" @@ -12183,12 +9183,16 @@ } }, "node_modules/node-releases": { - "version": "2.0.20", + "version": "2.0.26", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.26.tgz", + "integrity": "sha512-S2M9YimhSjBSvYnlr5/+umAnPHE++ODwt5e2Ij6FoX45HA/s4vHdkDx1eax2pAPeAOqu4s9b7ppahsyEFdVqQA==", "dev": true, "license": "MIT" }, "node_modules/nopt": { "version": "8.1.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-8.1.0.tgz", + "integrity": "sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==", "devOptional": true, "license": "ISC", "dependencies": { @@ -12203,6 +9207,8 @@ }, "node_modules/npm-bundled": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-4.0.0.tgz", + "integrity": "sha512-IxaQZDMsqfQ2Lz37VvyyEtKLe8FsRZuysmedy/N06TU1RyVppYKXrO4xIhR0F+7ubIBox6Q7nir6fQI3ej39iA==", "devOptional": true, "license": "ISC", "dependencies": { @@ -12214,6 +9220,8 @@ }, "node_modules/npm-install-checks": { "version": "7.1.2", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-7.1.2.tgz", + "integrity": "sha512-z9HJBCYw9Zr8BqXcllKIs5nI+QggAImbBdHphOzVYrz2CB4iQ6FzWyKmlqDZua+51nAu7FcemlbTc9VgQN5XDQ==", "devOptional": true, "license": "BSD-2-Clause", "dependencies": { @@ -12225,6 +9233,8 @@ }, "node_modules/npm-normalize-package-bin": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-4.0.0.tgz", + "integrity": "sha512-TZKxPvItzai9kN9H/TkmCtx/ZN/hvr3vUycjlfmH0ootY9yFBzNOpiXAdIn1Iteqsvk4lQn6B5PTrt+n6h8k/w==", "devOptional": true, "license": "ISC", "engines": { @@ -12233,6 +9243,8 @@ }, "node_modules/npm-package-arg": { "version": "13.0.0", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-13.0.0.tgz", + "integrity": "sha512-+t2etZAGcB7TbbLHfDwooV9ppB2LhhcT6A+L9cahsf9mEUAoQ6CktLEVvEnpD0N5CkX7zJqnPGaFtoQDy9EkHQ==", "devOptional": true, "license": "ISC", "dependencies": { @@ -12246,11 +9258,14 @@ } }, "node_modules/npm-packlist": { - "version": "10.0.1", + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-10.0.2.tgz", + "integrity": "sha512-DrIWNiWT0FTdDRjGOYfEEZUNe1IzaSZ+up7qBTKnrQDySpdmuOQvytrqQlpK5QrCA4IThMvL4wTumqaa1ZvVIQ==", "devOptional": true, "license": "ISC", "dependencies": { - "ignore-walk": "^8.0.0" + "ignore-walk": "^8.0.0", + "proc-log": "^5.0.0" }, "engines": { "node": "^20.17.0 || >=22.9.0" @@ -12258,6 +9273,8 @@ }, "node_modules/npm-pick-manifest": { "version": "10.0.0", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-10.0.0.tgz", + "integrity": "sha512-r4fFa4FqYY8xaM7fHecQ9Z2nE9hgNfJR+EmoKv0+chvzWkBcORX3r0FpTByP+CbOVJDladMXnPQGVN8PBLGuTQ==", "devOptional": true, "license": "ISC", "dependencies": { @@ -12272,6 +9289,8 @@ }, "node_modules/npm-pick-manifest/node_modules/hosted-git-info": { "version": "8.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-8.1.0.tgz", + "integrity": "sha512-Rw/B2DNQaPBICNXEm8balFz9a6WpZrkCGpcWFpy7nCj+NyhSdqXipmfvtmWt9xGfp0wZnBxB+iVpLmQMYt47Tw==", "devOptional": true, "license": "ISC", "dependencies": { @@ -12283,11 +9302,15 @@ }, "node_modules/npm-pick-manifest/node_modules/lru-cache": { "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "devOptional": true, "license": "ISC" }, "node_modules/npm-pick-manifest/node_modules/npm-package-arg": { "version": "12.0.2", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-12.0.2.tgz", + "integrity": "sha512-f1NpFjNI9O4VbKMOlA5QoBq/vSQPORHcTZ2feJpFkTHJ9eQkdlmZEKSjcAhxTGInC7RlEyScT9ui67NaOsjFWA==", "devOptional": true, "license": "ISC", "dependencies": { @@ -12302,6 +9325,8 @@ }, "node_modules/npm-registry-fetch": { "version": "18.0.2", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-18.0.2.tgz", + "integrity": "sha512-LeVMZBBVy+oQb5R6FDV9OlJCcWDU+al10oKpe+nsvcHnG24Z3uM3SvJYKfGJlfGjVU8v9liejCrUR/M5HO5NEQ==", "devOptional": true, "license": "ISC", "dependencies": { @@ -12320,6 +9345,8 @@ }, "node_modules/npm-registry-fetch/node_modules/hosted-git-info": { "version": "8.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-8.1.0.tgz", + "integrity": "sha512-Rw/B2DNQaPBICNXEm8balFz9a6WpZrkCGpcWFpy7nCj+NyhSdqXipmfvtmWt9xGfp0wZnBxB+iVpLmQMYt47Tw==", "devOptional": true, "license": "ISC", "dependencies": { @@ -12331,11 +9358,15 @@ }, "node_modules/npm-registry-fetch/node_modules/lru-cache": { "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "devOptional": true, "license": "ISC" }, "node_modules/npm-registry-fetch/node_modules/npm-package-arg": { "version": "12.0.2", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-12.0.2.tgz", + "integrity": "sha512-f1NpFjNI9O4VbKMOlA5QoBq/vSQPORHcTZ2feJpFkTHJ9eQkdlmZEKSjcAhxTGInC7RlEyScT9ui67NaOsjFWA==", "devOptional": true, "license": "ISC", "dependencies": { @@ -12350,6 +9381,8 @@ }, "node_modules/npm-run-path": { "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", "dev": true, "license": "MIT", "dependencies": { @@ -12364,6 +9397,8 @@ }, "node_modules/npm-run-path/node_modules/path-key": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", "dev": true, "license": "MIT", "engines": { @@ -12375,6 +9410,8 @@ }, "node_modules/nth-check": { "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -12386,6 +9423,8 @@ }, "node_modules/object-assign": { "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "devOptional": true, "license": "MIT", "engines": { @@ -12394,6 +9433,8 @@ }, "node_modules/object-hash": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", "license": "MIT", "engines": { "node": ">= 6" @@ -12401,6 +9442,8 @@ }, "node_modules/object-inspect": { "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", "devOptional": true, "license": "MIT", "engines": { @@ -12412,6 +9455,8 @@ }, "node_modules/on-finished": { "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "devOptional": true, "license": "MIT", "dependencies": { @@ -12423,6 +9468,8 @@ }, "node_modules/once": { "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "devOptional": true, "license": "ISC", "dependencies": { @@ -12431,6 +9478,8 @@ }, "node_modules/onetime": { "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", "dev": true, "license": "MIT", "dependencies": { @@ -12445,6 +9494,8 @@ }, "node_modules/open": { "version": "10.2.0", + "resolved": "https://registry.npmjs.org/open/-/open-10.2.0.tgz", + "integrity": "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==", "dev": true, "license": "MIT", "dependencies": { @@ -12462,6 +9513,8 @@ }, "node_modules/opencollective-postinstall": { "version": "2.0.3", + "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz", + "integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==", "dev": true, "license": "MIT", "bin": { @@ -12470,6 +9523,8 @@ }, "node_modules/opener": { "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", "dev": true, "license": "(WTFPL OR MIT)", "bin": { @@ -12478,6 +9533,8 @@ }, "node_modules/ora": { "version": "8.2.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-8.2.0.tgz", + "integrity": "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==", "license": "MIT", "dependencies": { "chalk": "^5.3.0", @@ -12499,12 +9556,16 @@ }, "node_modules/ordered-binary": { "version": "1.6.0", + "resolved": "https://registry.npmjs.org/ordered-binary/-/ordered-binary-1.6.0.tgz", + "integrity": "sha512-IQh2aMfMIDbPjI/8a3Edr+PiOpcsB7yo8NdW7aHWVaoR/pcDldunMvnnwbk/auPGqmKeAdxtZl7MHX/QmPwhvQ==", "dev": true, "license": "MIT", "optional": true }, "node_modules/p-limit": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "license": "MIT", "dependencies": { @@ -12519,6 +9580,8 @@ }, "node_modules/p-locate": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, "license": "MIT", "dependencies": { @@ -12533,6 +9596,8 @@ }, "node_modules/p-map": { "version": "7.0.3", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.3.tgz", + "integrity": "sha512-VkndIv2fIB99swvQoA65bm+fsmt6UNdGeIB0oxBs+WhAhdh08QA04JXpI7rbB9r08/nkbysKoya9rtDERYOYMA==", "devOptional": true, "license": "MIT", "engines": { @@ -12544,6 +9609,8 @@ }, "node_modules/p-try": { "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "license": "MIT", "engines": { "node": ">=6" @@ -12551,11 +9618,15 @@ }, "node_modules/package-json-from-dist": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", "devOptional": true, "license": "BlueOak-1.0.0" }, "node_modules/pacote": { "version": "21.0.0", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-21.0.0.tgz", + "integrity": "sha512-lcqexq73AMv6QNLo7SOpz0JJoaGdS3rBFgF122NZVl1bApo2mfu+XzUBU/X/XsiJu+iUmKpekRayqQYAs+PhkA==", "devOptional": true, "license": "ISC", "dependencies": { @@ -12586,6 +9657,8 @@ }, "node_modules/pacote/node_modules/hosted-git-info": { "version": "8.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-8.1.0.tgz", + "integrity": "sha512-Rw/B2DNQaPBICNXEm8balFz9a6WpZrkCGpcWFpy7nCj+NyhSdqXipmfvtmWt9xGfp0wZnBxB+iVpLmQMYt47Tw==", "devOptional": true, "license": "ISC", "dependencies": { @@ -12597,11 +9670,15 @@ }, "node_modules/pacote/node_modules/lru-cache": { "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "devOptional": true, "license": "ISC" }, "node_modules/pacote/node_modules/npm-package-arg": { "version": "12.0.2", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-12.0.2.tgz", + "integrity": "sha512-f1NpFjNI9O4VbKMOlA5QoBq/vSQPORHcTZ2feJpFkTHJ9eQkdlmZEKSjcAhxTGInC7RlEyScT9ui67NaOsjFWA==", "devOptional": true, "license": "ISC", "dependencies": { @@ -12616,10 +9693,14 @@ }, "node_modules/pako": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz", + "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==", "license": "(MIT AND Zlib)" }, "node_modules/parent-module": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, "license": "MIT", "dependencies": { @@ -12631,6 +9712,8 @@ }, "node_modules/parse-json": { "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, "license": "MIT", "dependencies": { @@ -12648,11 +9731,15 @@ }, "node_modules/parse-json/node_modules/json-parse-even-better-errors": { "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "dev": true, "license": "MIT" }, "node_modules/parse-node-version": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", + "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", "dev": true, "license": "MIT", "engines": { @@ -12661,6 +9748,8 @@ }, "node_modules/parse5": { "version": "8.0.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.0.tgz", + "integrity": "sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==", "license": "MIT", "dependencies": { "entities": "^6.0.0" @@ -12671,6 +9760,8 @@ }, "node_modules/parse5-html-rewriting-stream": { "version": "8.0.0", + "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-8.0.0.tgz", + "integrity": "sha512-wzh11mj8KKkno1pZEu+l2EVeWsuKDfR5KNWZOTsslfUX8lPDZx77m9T0kIoAVkFtD1nx6YF8oh4BnPHvxMtNMw==", "license": "MIT", "dependencies": { "entities": "^6.0.0", @@ -12683,6 +9774,8 @@ }, "node_modules/parse5-html-rewriting-stream/node_modules/entities": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", "license": "BSD-2-Clause", "engines": { "node": ">=0.12" @@ -12693,6 +9786,8 @@ }, "node_modules/parse5-sax-parser": { "version": "8.0.0", + "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-8.0.0.tgz", + "integrity": "sha512-/dQ8UzHZwnrzs3EvDj6IkKrD/jIZyTlB+8XrHJvcjNgRdmWruNdN9i9RK/JtxakmlUdPwKubKPTCqvbTgzGhrw==", "license": "MIT", "dependencies": { "parse5": "^8.0.0" @@ -12703,6 +9798,8 @@ }, "node_modules/parse5/node_modules/entities": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", "license": "BSD-2-Clause", "engines": { "node": ">=0.12" @@ -12713,6 +9810,8 @@ }, "node_modules/parseurl": { "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", "devOptional": true, "license": "MIT", "engines": { @@ -12725,11 +9824,15 @@ }, "node_modules/path-browserify": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", "license": "MIT", "optional": true }, "node_modules/path-exists": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "license": "MIT", "engines": { "node": ">=8" @@ -12737,6 +9840,8 @@ }, "node_modules/path-is-absolute": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true, "license": "MIT", "engines": { @@ -12745,6 +9850,8 @@ }, "node_modules/path-key": { "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "devOptional": true, "license": "MIT", "engines": { @@ -12753,11 +9860,15 @@ }, "node_modules/path-parse": { "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "devOptional": true, "license": "MIT" }, "node_modules/path-scurry": { "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", "devOptional": true, "license": "BlueOak-1.0.0", "dependencies": { @@ -12773,11 +9884,15 @@ }, "node_modules/path-scurry/node_modules/lru-cache": { "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "devOptional": true, "license": "ISC" }, "node_modules/path-to-regexp": { "version": "8.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", + "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", "devOptional": true, "license": "MIT", "funding": { @@ -12787,6 +9902,8 @@ }, "node_modules/path-type": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true, "license": "MIT", "engines": { @@ -12794,27 +9911,33 @@ } }, "node_modules/pbkdf2": { - "version": "3.1.3", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.5.tgz", + "integrity": "sha512-Q3CG/cYvCO1ye4QKkuH7EXxs3VC/rI1/trd+qX2+PolbaKG0H+bgcZzrTt96mMyRtejk+JMCiLUn3y29W8qmFQ==", "license": "MIT", "dependencies": { - "create-hash": "~1.1.3", + "create-hash": "^1.2.0", "create-hmac": "^1.1.7", - "ripemd160": "=2.0.1", + "ripemd160": "^2.0.3", "safe-buffer": "^5.2.1", - "sha.js": "^2.4.11", - "to-buffer": "^1.2.0" + "sha.js": "^2.4.12", + "to-buffer": "^1.2.1" }, "engines": { - "node": ">=0.12" + "node": ">= 0.10" } }, "node_modules/picocolors": { "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" }, "node_modules/picomatch": { "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "license": "MIT", "engines": { "node": ">=12" @@ -12825,6 +9948,8 @@ }, "node_modules/pidtree": { "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", "dev": true, "license": "MIT", "bin": { @@ -12836,6 +9961,8 @@ }, "node_modules/pify": { "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", "dev": true, "license": "MIT", "optional": true, @@ -12845,6 +9972,8 @@ }, "node_modules/piscina": { "version": "5.1.3", + "resolved": "https://registry.npmjs.org/piscina/-/piscina-5.1.3.tgz", + "integrity": "sha512-0u3N7H4+hbr40KjuVn2uNhOcthu/9usKhnw5vT3J7ply79v3D3M8naI00el9Klcy16x557VsEkkUQaHCWFXC/g==", "dev": true, "license": "MIT", "engines": { @@ -12856,6 +9985,8 @@ }, "node_modules/pkce-challenge": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.0.tgz", + "integrity": "sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==", "devOptional": true, "license": "MIT", "engines": { @@ -12864,6 +9995,8 @@ }, "node_modules/pkg-dir": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-5.0.0.tgz", + "integrity": "sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==", "dev": true, "license": "MIT", "dependencies": { @@ -12875,6 +10008,8 @@ }, "node_modules/please-upgrade-node": { "version": "3.2.0", + "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz", + "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==", "dev": true, "license": "MIT", "dependencies": { @@ -12883,13 +10018,17 @@ }, "node_modules/pngjs": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz", + "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==", "license": "MIT", "engines": { "node": ">=10.13.0" } }, "node_modules/portfinder": { - "version": "1.0.37", + "version": "1.0.38", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.38.tgz", + "integrity": "sha512-rEwq/ZHlJIKw++XtLAO8PPuOQA/zaPJOZJ37BVuN97nLpMJeuDVLVGRwbFoBgLudgdTMP2hdRJP++H+8QOA3vg==", "dev": true, "license": "MIT", "dependencies": { @@ -12902,6 +10041,8 @@ }, "node_modules/possible-typed-array-names": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -12909,6 +10050,8 @@ }, "node_modules/postcss": { "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", "dev": true, "funding": [ { @@ -12936,11 +10079,15 @@ }, "node_modules/postcss-media-query-parser": { "version": "0.2.3", + "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz", + "integrity": "sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig==", "dev": true, "license": "MIT" }, "node_modules/prettier": { "version": "3.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", + "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", "dev": true, "license": "MIT", "bin": { @@ -12955,6 +10102,8 @@ }, "node_modules/proc-log": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-5.0.0.tgz", + "integrity": "sha512-Azwzvl90HaF0aCz1JrDdXQykFakSSNPaPoiZ9fm5qJIMHioDZEi7OAdRwSm6rSoPtY3Qutnm3L7ogmg3dc+wbQ==", "devOptional": true, "license": "ISC", "engines": { @@ -12963,13 +10112,23 @@ }, "node_modules/process": { "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", "license": "MIT", "engines": { "node": ">= 0.6.0" } }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" + }, "node_modules/promise-retry": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", "devOptional": true, "license": "MIT", "dependencies": { @@ -12982,6 +10141,8 @@ }, "node_modules/proxy-addr": { "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", "devOptional": true, "license": "MIT", "dependencies": { @@ -12994,12 +10155,16 @@ }, "node_modules/prr": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", "dev": true, "license": "MIT", "optional": true }, "node_modules/punycode": { "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "devOptional": true, "license": "MIT", "engines": { @@ -13008,6 +10173,8 @@ }, "node_modules/qrcode": { "version": "1.5.4", + "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.4.tgz", + "integrity": "sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==", "license": "MIT", "dependencies": { "dijkstrajs": "^1.0.1", @@ -13023,6 +10190,8 @@ }, "node_modules/qrcode/node_modules/ansi-regex": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "license": "MIT", "engines": { "node": ">=8" @@ -13030,6 +10199,8 @@ }, "node_modules/qrcode/node_modules/cliui": { "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", "license": "ISC", "dependencies": { "string-width": "^4.2.0", @@ -13039,10 +10210,14 @@ }, "node_modules/qrcode/node_modules/emoji-regex": { "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "license": "MIT" }, "node_modules/qrcode/node_modules/find-up": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "license": "MIT", "dependencies": { "locate-path": "^5.0.0", @@ -13054,6 +10229,8 @@ }, "node_modules/qrcode/node_modules/is-fullwidth-code-point": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "license": "MIT", "engines": { "node": ">=8" @@ -13061,6 +10238,8 @@ }, "node_modules/qrcode/node_modules/locate-path": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "license": "MIT", "dependencies": { "p-locate": "^4.1.0" @@ -13071,6 +10250,8 @@ }, "node_modules/qrcode/node_modules/p-limit": { "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "license": "MIT", "dependencies": { "p-try": "^2.0.0" @@ -13084,6 +10265,8 @@ }, "node_modules/qrcode/node_modules/p-locate": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "license": "MIT", "dependencies": { "p-limit": "^2.2.0" @@ -13094,6 +10277,8 @@ }, "node_modules/qrcode/node_modules/string-width": { "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -13106,6 +10291,8 @@ }, "node_modules/qrcode/node_modules/strip-ansi": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -13116,10 +10303,14 @@ }, "node_modules/qrcode/node_modules/y18n": { "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", "license": "ISC" }, "node_modules/qrcode/node_modules/yargs": { "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", "license": "MIT", "dependencies": { "cliui": "^6.0.0", @@ -13140,6 +10331,8 @@ }, "node_modules/qrcode/node_modules/yargs-parser": { "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", "license": "ISC", "dependencies": { "camelcase": "^5.0.0", @@ -13151,6 +10344,8 @@ }, "node_modules/qs": { "version": "6.14.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", "devOptional": true, "license": "BSD-3-Clause", "dependencies": { @@ -13165,6 +10360,8 @@ }, "node_modules/queue-microtask": { "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "funding": [ { "type": "github", @@ -13184,6 +10381,8 @@ }, "node_modules/range-parser": { "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", "devOptional": true, "license": "MIT", "engines": { @@ -13192,6 +10391,8 @@ }, "node_modules/raw-body": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.1.tgz", + "integrity": "sha512-9G8cA+tuMS75+6G/TzW8OtLzmBDMo8p1JRxN5AZ+LAp8uxGA8V8GZm4GQ4/N5QNQEnLmg6SS7wyuSmbKepiKqA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -13204,23 +10405,31 @@ "node": ">= 0.10" } }, - "node_modules/raw-body/node_modules/iconv-lite": { - "version": "0.7.0", - "devOptional": true, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "license": "MIT", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, + "node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, "node_modules/readdirp": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", "devOptional": true, "license": "MIT", "engines": { @@ -13233,11 +10442,15 @@ }, "node_modules/reflect-metadata": { "version": "0.2.2", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", + "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==", "dev": true, "license": "Apache-2.0" }, "node_modules/require-directory": { "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -13245,6 +10458,8 @@ }, "node_modules/require-from-string": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -13252,15 +10467,21 @@ }, "node_modules/require-main-filename": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", "license": "ISC" }, "node_modules/requires-port": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", "dev": true, "license": "MIT" }, "node_modules/resolve": { "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", "devOptional": true, "license": "MIT", "dependencies": { @@ -13280,6 +10501,8 @@ }, "node_modules/resolve-from": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, "license": "MIT", "engines": { @@ -13288,6 +10511,8 @@ }, "node_modules/restore-cursor": { "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", "license": "MIT", "dependencies": { "onetime": "^7.0.0", @@ -13302,6 +10527,8 @@ }, "node_modules/restore-cursor/node_modules/onetime": { "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", "license": "MIT", "dependencies": { "mimic-function": "^5.0.0" @@ -13315,6 +10542,8 @@ }, "node_modules/retry": { "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", "devOptional": true, "license": "MIT", "engines": { @@ -13323,6 +10552,8 @@ }, "node_modules/reusify": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", "license": "MIT", "optional": true, "engines": { @@ -13332,11 +10563,15 @@ }, "node_modules/rfdc": { "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", "devOptional": true, "license": "MIT" }, "node_modules/rimraf": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.0.1.tgz", + "integrity": "sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==", "dev": true, "license": "ISC", "dependencies": { @@ -13355,6 +10590,8 @@ }, "node_modules/rimraf/node_modules/glob": { "version": "11.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.3.tgz", + "integrity": "sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA==", "dev": true, "license": "ISC", "dependencies": { @@ -13377,6 +10614,8 @@ }, "node_modules/rimraf/node_modules/jackspeak": { "version": "4.1.1", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.1.1.tgz", + "integrity": "sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { @@ -13390,7 +10629,9 @@ } }, "node_modules/rimraf/node_modules/lru-cache": { - "version": "11.2.1", + "version": "11.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.2.tgz", + "integrity": "sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==", "dev": true, "license": "ISC", "engines": { @@ -13399,6 +10640,8 @@ }, "node_modules/rimraf/node_modules/minimatch": { "version": "10.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.3.tgz", + "integrity": "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==", "dev": true, "license": "ISC", "dependencies": { @@ -13413,6 +10656,8 @@ }, "node_modules/rimraf/node_modules/path-scurry": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz", + "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { @@ -13427,47 +10672,25 @@ } }, "node_modules/ripemd160": { - "version": "2.0.1", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.3.tgz", + "integrity": "sha512-5Di9UC0+8h1L6ZD2d7awM7E/T4uA1fJRlx6zk/NvdCCVEoAnFqvHmCuNeIKoCeIixBX/q8uM+6ycDvF8woqosA==", "license": "MIT", "dependencies": { - "hash-base": "^2.0.0", - "inherits": "^2.0.1" - } - }, - "node_modules/rolldown": { - "version": "1.0.0-beta.32", - "dev": true, - "license": "MIT", - "dependencies": { - "@oxc-project/runtime": "=0.81.0", - "@oxc-project/types": "=0.81.0", - "@rolldown/pluginutils": "1.0.0-beta.32", - "ansis": "^4.0.0" + "hash-base": "^3.1.2", + "inherits": "^2.0.4" }, - "bin": { - "rolldown": "bin/cli.mjs" - }, - "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.0.0-beta.32", - "@rolldown/binding-darwin-arm64": "1.0.0-beta.32", - "@rolldown/binding-darwin-x64": "1.0.0-beta.32", - "@rolldown/binding-freebsd-x64": "1.0.0-beta.32", - "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-beta.32", - "@rolldown/binding-linux-arm64-gnu": "1.0.0-beta.32", - "@rolldown/binding-linux-arm64-musl": "1.0.0-beta.32", - "@rolldown/binding-linux-x64-gnu": "1.0.0-beta.32", - "@rolldown/binding-linux-x64-musl": "1.0.0-beta.32", - "@rolldown/binding-openharmony-arm64": "1.0.0-beta.32", - "@rolldown/binding-wasm32-wasi": "1.0.0-beta.32", - "@rolldown/binding-win32-arm64-msvc": "1.0.0-beta.32", - "@rolldown/binding-win32-ia32-msvc": "1.0.0-beta.32", - "@rolldown/binding-win32-x64-msvc": "1.0.0-beta.32" + "engines": { + "node": ">= 0.8" } }, "node_modules/rollup": { - "version": "4.50.1", + "version": "4.52.3", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.3.tgz", + "integrity": "sha512-RIDh866U8agLgiIcdpB+COKnlCreHJLfIhWC3LVflku5YHfpnsIKigRZeFfMfCc4dVcqNVfQQ5gO/afOck064A==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/estree": "1.0.8" }, @@ -13479,32 +10702,35 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.50.1", - "@rollup/rollup-android-arm64": "4.50.1", - "@rollup/rollup-darwin-arm64": "4.50.1", - "@rollup/rollup-darwin-x64": "4.50.1", - "@rollup/rollup-freebsd-arm64": "4.50.1", - "@rollup/rollup-freebsd-x64": "4.50.1", - "@rollup/rollup-linux-arm-gnueabihf": "4.50.1", - "@rollup/rollup-linux-arm-musleabihf": "4.50.1", - "@rollup/rollup-linux-arm64-gnu": "4.50.1", - "@rollup/rollup-linux-arm64-musl": "4.50.1", - "@rollup/rollup-linux-loongarch64-gnu": "4.50.1", - "@rollup/rollup-linux-ppc64-gnu": "4.50.1", - "@rollup/rollup-linux-riscv64-gnu": "4.50.1", - "@rollup/rollup-linux-riscv64-musl": "4.50.1", - "@rollup/rollup-linux-s390x-gnu": "4.50.1", - "@rollup/rollup-linux-x64-gnu": "4.50.1", - "@rollup/rollup-linux-x64-musl": "4.50.1", - "@rollup/rollup-openharmony-arm64": "4.50.1", - "@rollup/rollup-win32-arm64-msvc": "4.50.1", - "@rollup/rollup-win32-ia32-msvc": "4.50.1", - "@rollup/rollup-win32-x64-msvc": "4.50.1", + "@rollup/rollup-android-arm-eabi": "4.52.3", + "@rollup/rollup-android-arm64": "4.52.3", + "@rollup/rollup-darwin-arm64": "4.52.3", + "@rollup/rollup-darwin-x64": "4.52.3", + "@rollup/rollup-freebsd-arm64": "4.52.3", + "@rollup/rollup-freebsd-x64": "4.52.3", + "@rollup/rollup-linux-arm-gnueabihf": "4.52.3", + "@rollup/rollup-linux-arm-musleabihf": "4.52.3", + "@rollup/rollup-linux-arm64-gnu": "4.52.3", + "@rollup/rollup-linux-arm64-musl": "4.52.3", + "@rollup/rollup-linux-loong64-gnu": "4.52.3", + "@rollup/rollup-linux-ppc64-gnu": "4.52.3", + "@rollup/rollup-linux-riscv64-gnu": "4.52.3", + "@rollup/rollup-linux-riscv64-musl": "4.52.3", + "@rollup/rollup-linux-s390x-gnu": "4.52.3", + "@rollup/rollup-linux-x64-gnu": "4.52.3", + "@rollup/rollup-linux-x64-musl": "4.52.3", + "@rollup/rollup-openharmony-arm64": "4.52.3", + "@rollup/rollup-win32-arm64-msvc": "4.52.3", + "@rollup/rollup-win32-ia32-msvc": "4.52.3", + "@rollup/rollup-win32-x64-gnu": "4.52.3", + "@rollup/rollup-win32-x64-msvc": "4.52.3", "fsevents": "~2.3.2" } }, "node_modules/rollup-plugin-dts": { "version": "6.2.3", + "resolved": "https://registry.npmjs.org/rollup-plugin-dts/-/rollup-plugin-dts-6.2.3.tgz", + "integrity": "sha512-UgnEsfciXSPpASuOelix7m4DrmyQgiaWBnvI0TM4GxuDh5FkqW8E5hu57bCxXB90VvR1WNfLV80yEDN18UogSA==", "dev": true, "license": "LGPL-3.0-only", "dependencies": { @@ -13526,11 +10752,15 @@ }, "node_modules/rollup/node_modules/@types/estree": { "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", "dev": true, "license": "MIT" }, "node_modules/router": { "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", "devOptional": true, "license": "MIT", "dependencies": { @@ -13546,6 +10776,8 @@ }, "node_modules/run-applescript": { "version": "7.1.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", + "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", "dev": true, "license": "MIT", "engines": { @@ -13557,6 +10789,8 @@ }, "node_modules/run-async": { "version": "4.0.6", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-4.0.6.tgz", + "integrity": "sha512-IoDlSLTs3Yq593mb3ZoKWKXMNu3UpObxhgA/Xuid5p4bbfi2jdY1Hj0m1K+0/tEuQTxIGMhQDqGjKb7RuxGpAQ==", "dev": true, "license": "MIT", "engines": { @@ -13565,6 +10799,8 @@ }, "node_modules/run-parallel": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", "funding": [ { "type": "github", @@ -13587,13 +10823,18 @@ }, "node_modules/rxjs": { "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", "license": "Apache-2.0", + "peer": true, "dependencies": { "tslib": "^2.1.0" } }, "node_modules/safe-buffer": { "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "funding": [ { "type": "github", @@ -13612,13 +10853,18 @@ }, "node_modules/safer-buffer": { "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "devOptional": true, "license": "MIT" }, "node_modules/sass": { "version": "1.90.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.90.0.tgz", + "integrity": "sha512-9GUyuksjw70uNpb1MTYWsH9MQHOHY6kwfnkafC24+7aOMZn9+rVMBxRbLvw756mrBFbIsFg6Xw9IkR2Fnn3k+Q==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "chokidar": "^4.0.0", "immutable": "^5.0.2", @@ -13636,17 +10882,23 @@ }, "node_modules/sax": { "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", + "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", "dev": true, "license": "ISC", "optional": true }, "node_modules/secure-compare": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz", + "integrity": "sha512-AckIIV90rPDcBcglUwXPF3kg0P0qmPsPXAj6BBEENQE1p5yA1xfmDJzfi1Tappj37Pv2mVbKpL3Z1T+Nn7k1Qw==", "dev": true, "license": "MIT" }, "node_modules/semver": { "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "devOptional": true, "license": "ISC", "bin": { @@ -13658,11 +10910,15 @@ }, "node_modules/semver-compare": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", + "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==", "dev": true, "license": "MIT" }, "node_modules/semver-regex": { "version": "3.1.4", + "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-3.1.4.tgz", + "integrity": "sha512-6IiqeZNgq01qGf0TId0t3NvKzSvUsjcpdEO3AQNeIjR6A2+ckTnQlDpl4qu1bjRv0RzN3FP9hzFmws3lKqRWkA==", "dev": true, "license": "MIT", "engines": { @@ -13674,6 +10930,8 @@ }, "node_modules/send": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", + "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", "devOptional": true, "license": "MIT", "dependencies": { @@ -13695,6 +10953,8 @@ }, "node_modules/serve-static": { "version": "2.2.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", + "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", "devOptional": true, "license": "MIT", "dependencies": { @@ -13709,10 +10969,14 @@ }, "node_modules/set-blocking": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", "license": "ISC" }, "node_modules/set-function-length": { "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", @@ -13728,11 +10992,15 @@ }, "node_modules/setprototypeof": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "devOptional": true, "license": "ISC" }, "node_modules/sha.js": { "version": "2.4.12", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.12.tgz", + "integrity": "sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==", "license": "(MIT AND BSD-3-Clause)", "dependencies": { "inherits": "^2.0.4", @@ -13751,6 +11019,8 @@ }, "node_modules/shebang-command": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -13762,6 +11032,8 @@ }, "node_modules/shebang-regex": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "devOptional": true, "license": "MIT", "engines": { @@ -13770,6 +11042,8 @@ }, "node_modules/side-channel": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", "devOptional": true, "license": "MIT", "dependencies": { @@ -13788,6 +11062,8 @@ }, "node_modules/side-channel-list": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -13803,6 +11079,8 @@ }, "node_modules/side-channel-map": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -13820,6 +11098,8 @@ }, "node_modules/side-channel-weakmap": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", "devOptional": true, "license": "MIT", "dependencies": { @@ -13838,6 +11118,8 @@ }, "node_modules/signal-exit": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "license": "ISC", "engines": { "node": ">=14" @@ -13848,6 +11130,8 @@ }, "node_modules/sigstore": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-3.1.0.tgz", + "integrity": "sha512-ZpzWAFHIFqyFE56dXqgX/DkDRZdz+rRcjoIk/RQU4IX0wiCv1l8S7ZrXDHcCc+uaf+6o7w3h2l3g6GYG5TKN9Q==", "devOptional": true, "license": "Apache-2.0", "dependencies": { @@ -13864,6 +11148,8 @@ }, "node_modules/slash": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, "license": "MIT", "engines": { @@ -13872,6 +11158,8 @@ }, "node_modules/slice-ansi": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", "devOptional": true, "license": "MIT", "dependencies": { @@ -13887,6 +11175,8 @@ }, "node_modules/smart-buffer": { "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", "devOptional": true, "license": "MIT", "engines": { @@ -13896,6 +11186,8 @@ }, "node_modules/socks": { "version": "2.8.7", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz", + "integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==", "devOptional": true, "license": "MIT", "dependencies": { @@ -13909,6 +11201,8 @@ }, "node_modules/socks-proxy-agent": { "version": "8.0.5", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", + "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", "devOptional": true, "license": "MIT", "dependencies": { @@ -13922,6 +11216,8 @@ }, "node_modules/source-map": { "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", "license": "BSD-3-Clause", "engines": { "node": ">= 12" @@ -13929,6 +11225,8 @@ }, "node_modules/source-map-js": { "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -13937,6 +11235,8 @@ }, "node_modules/source-map-support": { "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "dev": true, "license": "MIT", "dependencies": { @@ -13946,6 +11246,8 @@ }, "node_modules/source-map-support/node_modules/source-map": { "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -13954,6 +11256,8 @@ }, "node_modules/spdx-correct": { "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", "devOptional": true, "license": "Apache-2.0", "dependencies": { @@ -13963,11 +11267,15 @@ }, "node_modules/spdx-exceptions": { "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", "devOptional": true, "license": "CC-BY-3.0" }, "node_modules/spdx-expression-parse": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", "devOptional": true, "license": "MIT", "dependencies": { @@ -13977,16 +11285,22 @@ }, "node_modules/spdx-license-ids": { "version": "3.0.22", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.22.tgz", + "integrity": "sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==", "devOptional": true, "license": "CC0-1.0" }, "node_modules/sprintf-js": { "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "dev": true, "license": "BSD-3-Clause" }, "node_modules/ssri": { "version": "12.0.0", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-12.0.0.tgz", + "integrity": "sha512-S7iGNosepx9RadX82oimUkvr0Ct7IjJbEbs4mJcTxst8um95J3sDYU1RBEOvdu6oL1Wek2ODI5i4MAw+dZ6cAQ==", "devOptional": true, "license": "ISC", "dependencies": { @@ -13998,6 +11312,8 @@ }, "node_modules/statuses": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", "devOptional": true, "license": "MIT", "engines": { @@ -14006,6 +11322,8 @@ }, "node_modules/stdin-discarder": { "version": "0.2.2", + "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz", + "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==", "license": "MIT", "engines": { "node": ">=18" @@ -14014,8 +11332,25 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, "node_modules/string-argv": { "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", "dev": true, "license": "MIT", "engines": { @@ -14024,6 +11359,8 @@ }, "node_modules/string-width": { "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "license": "MIT", "dependencies": { "emoji-regex": "^10.3.0", @@ -14040,6 +11377,8 @@ "node_modules/string-width-cjs": { "name": "string-width", "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "devOptional": true, "license": "MIT", "dependencies": { @@ -14053,6 +11392,8 @@ }, "node_modules/string-width-cjs/node_modules/ansi-regex": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "devOptional": true, "license": "MIT", "engines": { @@ -14061,11 +11402,15 @@ }, "node_modules/string-width-cjs/node_modules/emoji-regex": { "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "devOptional": true, "license": "MIT" }, "node_modules/string-width-cjs/node_modules/is-fullwidth-code-point": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "devOptional": true, "license": "MIT", "engines": { @@ -14074,6 +11419,8 @@ }, "node_modules/string-width-cjs/node_modules/strip-ansi": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "devOptional": true, "license": "MIT", "dependencies": { @@ -14085,6 +11432,8 @@ }, "node_modules/strip-ansi": { "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" @@ -14099,6 +11448,8 @@ "node_modules/strip-ansi-cjs": { "name": "strip-ansi", "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "devOptional": true, "license": "MIT", "dependencies": { @@ -14110,6 +11461,8 @@ }, "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "devOptional": true, "license": "MIT", "engines": { @@ -14118,6 +11471,8 @@ }, "node_modules/strip-final-newline": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", "dev": true, "license": "MIT", "engines": { @@ -14129,6 +11484,8 @@ }, "node_modules/supports-color": { "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "license": "MIT", "dependencies": { @@ -14140,6 +11497,8 @@ }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "devOptional": true, "license": "MIT", "engines": { @@ -14151,6 +11510,8 @@ }, "node_modules/tar": { "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", "devOptional": true, "license": "ISC", "dependencies": { @@ -14167,6 +11528,8 @@ }, "node_modules/tar/node_modules/fs-minipass": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", "devOptional": true, "license": "ISC", "dependencies": { @@ -14178,6 +11541,8 @@ }, "node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "devOptional": true, "license": "ISC", "dependencies": { @@ -14189,6 +11554,8 @@ }, "node_modules/tar/node_modules/minipass": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", "devOptional": true, "license": "ISC", "engines": { @@ -14197,6 +11564,8 @@ }, "node_modules/tar/node_modules/minizlib": { "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", "devOptional": true, "license": "MIT", "dependencies": { @@ -14209,6 +11578,8 @@ }, "node_modules/tar/node_modules/minizlib/node_modules/minipass": { "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "devOptional": true, "license": "ISC", "dependencies": { @@ -14220,11 +11591,15 @@ }, "node_modules/tar/node_modules/yallist": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "devOptional": true, "license": "ISC" }, "node_modules/tinyglobby": { "version": "0.2.14", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", + "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", "devOptional": true, "license": "MIT", "dependencies": { @@ -14239,21 +11614,27 @@ } }, "node_modules/tldts": { - "version": "7.0.13", + "version": "7.0.17", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.17.tgz", + "integrity": "sha512-Y1KQBgDd/NUc+LfOtKS6mNsC9CCaH+m2P1RoIZy7RAPo3C3/t8X45+zgut31cRZtZ3xKPjfn3TkGTrctC2TQIQ==", "license": "MIT", "dependencies": { - "tldts-core": "^7.0.13" + "tldts-core": "^7.0.17" }, "bin": { "tldts": "bin/cli.js" } }, "node_modules/tldts-core": { - "version": "7.0.13", + "version": "7.0.17", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.0.17.tgz", + "integrity": "sha512-DieYoGrP78PWKsrXr8MZwtQ7GLCUeLxihtjC1jZsW1DnvSMdKPitJSe8OSYDM2u5H6g3kWJZpePqkp43TfLh0g==", "license": "MIT" }, "node_modules/to-buffer": { - "version": "1.2.1", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.2.tgz", + "integrity": "sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==", "license": "MIT", "dependencies": { "isarray": "^2.0.5", @@ -14264,8 +11645,16 @@ "node": ">= 0.4" } }, + "node_modules/to-buffer/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "license": "MIT" + }, "node_modules/to-regex-range": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "devOptional": true, "license": "MIT", "dependencies": { @@ -14277,6 +11666,8 @@ }, "node_modules/toidentifier": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "devOptional": true, "license": "MIT", "engines": { @@ -14285,10 +11676,14 @@ }, "node_modules/ts-matches": { "version": "6.5.0", + "resolved": "https://registry.npmjs.org/ts-matches/-/ts-matches-6.5.0.tgz", + "integrity": "sha512-MhuobYhHYn6MlOTPAF/qk3tsRRioPac5ofYn68tc3rAJaGjsw1MsX1MOSep52DkvNJPgNV0F73zfgcQfYTVeyQ==", "license": "MIT" }, "node_modules/ts-morph": { "version": "23.0.0", + "resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-23.0.0.tgz", + "integrity": "sha512-FcvFx7a9E8TUe6T3ShihXJLiJOiqyafzFKUO4aqIHDUCIvADdGNShcbc2W5PMr3LerXRv7mafvFZ9lRENxJmug==", "license": "MIT", "optional": true, "dependencies": { @@ -14298,6 +11693,8 @@ }, "node_modules/ts-node": { "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "dev": true, "license": "MIT", "dependencies": { @@ -14340,10 +11737,16 @@ }, "node_modules/tslib": { "version": "2.8.1", - "license": "0BSD" + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD", + "peer": true }, "node_modules/tslint": { "version": "6.1.3", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz", + "integrity": "sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==", + "deprecated": "TSLint has been deprecated in favor of ESLint. Please see https://github.com/palantir/tslint/issues/4534 for more information.", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -14373,6 +11776,8 @@ }, "node_modules/tslint/node_modules/ansi-styles": { "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "license": "MIT", "dependencies": { @@ -14384,6 +11789,8 @@ }, "node_modules/tslint/node_modules/argparse": { "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, "license": "MIT", "dependencies": { @@ -14392,6 +11799,8 @@ }, "node_modules/tslint/node_modules/brace-expansion": { "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, "license": "MIT", "dependencies": { @@ -14401,6 +11810,8 @@ }, "node_modules/tslint/node_modules/chalk": { "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "license": "MIT", "dependencies": { @@ -14414,6 +11825,8 @@ }, "node_modules/tslint/node_modules/color-convert": { "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dev": true, "license": "MIT", "dependencies": { @@ -14422,16 +11835,23 @@ }, "node_modules/tslint/node_modules/color-name": { "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true, "license": "MIT" }, "node_modules/tslint/node_modules/commander": { "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true, "license": "MIT" }, "node_modules/tslint/node_modules/glob": { "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, "license": "ISC", "dependencies": { @@ -14451,6 +11871,8 @@ }, "node_modules/tslint/node_modules/has-flag": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true, "license": "MIT", "engines": { @@ -14459,6 +11881,8 @@ }, "node_modules/tslint/node_modules/js-yaml": { "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "dev": true, "license": "MIT", "dependencies": { @@ -14471,6 +11895,8 @@ }, "node_modules/tslint/node_modules/minimatch": { "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "license": "ISC", "dependencies": { @@ -14482,6 +11908,8 @@ }, "node_modules/tslint/node_modules/mkdirp": { "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, "license": "MIT", "dependencies": { @@ -14493,6 +11921,8 @@ }, "node_modules/tslint/node_modules/semver": { "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, "license": "ISC", "bin": { @@ -14501,6 +11931,8 @@ }, "node_modules/tslint/node_modules/supports-color": { "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "license": "MIT", "dependencies": { @@ -14512,11 +11944,15 @@ }, "node_modules/tslint/node_modules/tslib": { "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true, "license": "0BSD" }, "node_modules/tsutils": { "version": "2.29.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", + "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", "dev": true, "license": "MIT", "dependencies": { @@ -14528,11 +11964,15 @@ }, "node_modules/tsutils/node_modules/tslib": { "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true, "license": "0BSD" }, "node_modules/tuf-js": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-3.1.0.tgz", + "integrity": "sha512-3T3T04WzowbwV2FDiGXBbr81t64g1MUGGJRgT4x5o97N+8ArdhVCAF9IxFrxuSJmM3E5Asn7nKHkao0ibcZXAg==", "devOptional": true, "license": "MIT", "dependencies": { @@ -14545,8 +11985,10 @@ } }, "node_modules/type-fest": { - "version": "0.21.3", - "devOptional": true, + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "dev": true, "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" @@ -14557,6 +11999,8 @@ }, "node_modules/type-is": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", "devOptional": true, "license": "MIT", "dependencies": { @@ -14570,6 +12014,8 @@ }, "node_modules/typed-array-buffer": { "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -14581,9 +12027,12 @@ } }, "node_modules/typescript": { - "version": "5.9.2", + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -14594,11 +12043,15 @@ }, "node_modules/undici-types": { "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", "dev": true, "license": "MIT" }, "node_modules/union": { "version": "0.5.0", + "resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz", + "integrity": "sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==", "dev": true, "dependencies": { "qs": "^6.4.0" @@ -14609,6 +12062,8 @@ }, "node_modules/unique-filename": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-4.0.0.tgz", + "integrity": "sha512-XSnEewXmQ+veP7xX2dS5Q4yZAvO40cBN2MWkJ7D/6sW4Dg6wYBNwM1Vrnz1FhH5AdeLIlUXRI9e28z1YZi71NQ==", "devOptional": true, "license": "ISC", "dependencies": { @@ -14620,6 +12075,8 @@ }, "node_modules/unique-slug": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-5.0.0.tgz", + "integrity": "sha512-9OdaqO5kwqR+1kVgHAhsp5vPNU0hnxRa26rBFNfNgM7M6pNtgzeBn3s/xbyCQL3dcjzOatcef6UUHpB/6MaETg==", "devOptional": true, "license": "ISC", "dependencies": { @@ -14631,6 +12088,8 @@ }, "node_modules/unpipe": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", "devOptional": true, "license": "MIT", "engines": { @@ -14638,7 +12097,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.1.3", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.4.tgz", + "integrity": "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==", "dev": true, "funding": [ { @@ -14668,6 +12129,8 @@ }, "node_modules/uri-js": { "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "devOptional": true, "license": "BSD-2-Clause", "dependencies": { @@ -14676,11 +12139,21 @@ }, "node_modules/url-join": { "version": "4.0.1", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", + "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", "dev": true, "license": "MIT" }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, "node_modules/uuid": { "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "license": "MIT", "bin": { "uuid": "dist/bin/uuid" @@ -14688,11 +12161,15 @@ }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", "dev": true, "license": "MIT" }, "node_modules/validate-npm-package-license": { "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", "devOptional": true, "license": "Apache-2.0", "dependencies": { @@ -14702,6 +12179,8 @@ }, "node_modules/validate-npm-package-name": { "version": "6.0.2", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-6.0.2.tgz", + "integrity": "sha512-IUoow1YUtvoBBC06dXs8bR8B9vuA3aJfmQNKMoaPG/OFsPmoQvw8xh+6Ye25Gx9DQhoEom3Pcu9MKHerm/NpUQ==", "devOptional": true, "license": "ISC", "engines": { @@ -14710,6 +12189,8 @@ }, "node_modules/vary": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", "devOptional": true, "license": "MIT", "engines": { @@ -14717,16 +12198,19 @@ } }, "node_modules/vite": { - "version": "7.1.2", + "version": "7.1.11", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.11.tgz", + "integrity": "sha512-uzcxnSDVjAopEUjljkWh8EIrg6tlzrjFUfMcR1EVsRDGwf/ccef0qQPRyOrROwhrTDaApueq+ja+KLPlzR/zdg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.25.0", - "fdir": "^6.4.6", + "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", - "tinyglobby": "^0.2.14" + "tinyglobby": "^0.2.15" }, "bin": { "vite": "bin/vite.js" @@ -14789,8 +12273,27 @@ } } }, + "node_modules/vite/node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, "node_modules/watchpack": { "version": "2.4.4", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.4.tgz", + "integrity": "sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==", "dev": true, "license": "MIT", "dependencies": { @@ -14803,12 +12306,16 @@ }, "node_modules/weak-lru-cache": { "version": "1.2.2", + "resolved": "https://registry.npmjs.org/weak-lru-cache/-/weak-lru-cache-1.2.2.tgz", + "integrity": "sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw==", "dev": true, "license": "MIT", "optional": true }, "node_modules/whatwg-encoding": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", + "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", "dev": true, "license": "MIT", "dependencies": { @@ -14818,8 +12325,23 @@ "node": ">=12" } }, + "node_modules/whatwg-encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/which": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "devOptional": true, "license": "ISC", "dependencies": { @@ -14834,10 +12356,14 @@ }, "node_modules/which-module": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", "license": "ISC" }, "node_modules/which-pm-runs": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.1.0.tgz", + "integrity": "sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA==", "dev": true, "license": "MIT", "engines": { @@ -14846,6 +12372,8 @@ }, "node_modules/which-typed-array": { "version": "1.1.19", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", + "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.7", @@ -14865,6 +12393,8 @@ }, "node_modules/wrap-ansi": { "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", @@ -14878,6 +12408,8 @@ "node_modules/wrap-ansi-cjs": { "name": "wrap-ansi", "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "devOptional": true, "license": "MIT", "dependencies": { @@ -14894,6 +12426,8 @@ }, "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "devOptional": true, "license": "MIT", "engines": { @@ -14902,6 +12436,8 @@ }, "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "devOptional": true, "license": "MIT", "dependencies": { @@ -14916,11 +12452,15 @@ }, "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "devOptional": true, "license": "MIT" }, "node_modules/wrap-ansi-cjs/node_modules/is-fullwidth-code-point": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "devOptional": true, "license": "MIT", "engines": { @@ -14929,6 +12469,8 @@ }, "node_modules/wrap-ansi-cjs/node_modules/string-width": { "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "devOptional": true, "license": "MIT", "dependencies": { @@ -14942,6 +12484,8 @@ }, "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "devOptional": true, "license": "MIT", "dependencies": { @@ -14953,6 +12497,8 @@ }, "node_modules/wrap-ansi/node_modules/ansi-regex": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "license": "MIT", "engines": { "node": ">=8" @@ -14960,6 +12506,8 @@ }, "node_modules/wrap-ansi/node_modules/ansi-styles": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -14973,10 +12521,14 @@ }, "node_modules/wrap-ansi/node_modules/emoji-regex": { "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "license": "MIT" }, "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "license": "MIT", "engines": { "node": ">=8" @@ -14984,6 +12536,8 @@ }, "node_modules/wrap-ansi/node_modules/string-width": { "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -14996,6 +12550,8 @@ }, "node_modules/wrap-ansi/node_modules/strip-ansi": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -15006,11 +12562,15 @@ }, "node_modules/wrappy": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "devOptional": true, "license": "ISC" }, "node_modules/wsl-utils": { "version": "0.1.0", + "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.1.0.tgz", + "integrity": "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==", "dev": true, "license": "MIT", "dependencies": { @@ -15025,6 +12585,8 @@ }, "node_modules/y18n": { "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "devOptional": true, "license": "ISC", "engines": { @@ -15033,24 +12595,15 @@ }, "node_modules/yallist": { "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true, "license": "ISC" }, - "node_modules/yaml": { - "version": "2.8.1", - "dev": true, - "license": "ISC", - "optional": true, - "peer": true, - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - } - }, "node_modules/yargs": { "version": "18.0.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz", + "integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==", "devOptional": true, "license": "MIT", "dependencies": { @@ -15067,6 +12620,8 @@ }, "node_modules/yargs-parser": { "version": "22.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", + "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", "devOptional": true, "license": "ISC", "engines": { @@ -15075,6 +12630,8 @@ }, "node_modules/yn": { "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", "dev": true, "license": "MIT", "engines": { @@ -15083,6 +12640,8 @@ }, "node_modules/yocto-queue": { "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, "license": "MIT", "engines": { @@ -15094,6 +12653,8 @@ }, "node_modules/yoctocolors-cjs": { "version": "2.1.3", + "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.3.tgz", + "integrity": "sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==", "devOptional": true, "license": "MIT", "engines": { @@ -15105,14 +12666,19 @@ }, "node_modules/zod": { "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", "devOptional": true, "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } }, "node_modules/zod-to-json-schema": { "version": "3.24.6", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.6.tgz", + "integrity": "sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg==", "devOptional": true, "license": "ISC", "peerDependencies": { @@ -15121,7 +12687,10 @@ }, "node_modules/zone.js": { "version": "0.15.1", - "license": "MIT" + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.15.1.tgz", + "integrity": "sha512-XE96n56IQpJM7NAoXswY3XRLcWFW83xe0BiAOeMD7K5k5xecOeul3Qcpx6GqEeeHNkW5DWL5zOyTbEfB4eti8w==", + "license": "MIT", + "peer": true } } } diff --git a/web/package.json b/web/package.json index 546eb64ad..7159f5e24 100644 --- a/web/package.json +++ b/web/package.json @@ -1,6 +1,6 @@ { "name": "startos-ui", - "version": "0.4.0-alpha.11", + "version": "0.4.0-alpha.12", "author": "Start9 Labs, Inc", "homepage": "https://start9.com/", "license": "MIT", @@ -12,11 +12,13 @@ "check:install": "tsc --project projects/install-wizard/tsconfig.json --noEmit --skipLibCheck", "check:setup": "tsc --project projects/setup-wizard/tsconfig.json --noEmit --skipLibCheck", "check:ui": "tsc --project projects/ui/tsconfig.json --noEmit --skipLibCheck", + "check:tunnel": "tsc --project projects/start-tunnel/tsconfig.json --noEmit --skipLibCheck", "build:deps": "rimraf .angular/cache && (cd ../sdk && make bundle) && (cd ../patch-db/client && npm ci && npm run build)", "build:install": "ng run install-wizard:build", "build:setup": "ng run setup-wizard:build", "build:ui": "ng run ui:build", "build:ui:dev": "ng run ui:build:development", + "build:tunnel": "ng run start-tunnel:build", "build:all": "npm run build:deps && npm run build:setup && npm run build:ui && npm run build:install", "build:shared": "ng build shared", "build:marketplace": "npm run build:shared && ng build marketplace", @@ -26,38 +28,39 @@ "start:install": "npm run-script build-config && ng serve --project install-wizard --host 0.0.0.0", "start:setup": "npm run-script build-config && ng serve --project setup-wizard --host 0.0.0.0", "start:ui": "npm run-script build-config && ng serve --project ui --host 0.0.0.0", + "start:tunnel": "ng serve --project start-tunnel --host 0.0.0.0", "start:ui:proxy": "npm run-script build-config && ng serve --project ui --host 0.0.0.0 --proxy-config proxy.conf.json", "build-config": "node build-config.js" }, "dependencies": { - "@angular/animations": "^20.1.0", + "@angular/animations": "^20.3.0", "@angular/cdk": "^20.1.0", - "@angular/common": "^20.1.0", - "@angular/compiler": "^20.1.0", - "@angular/core": "^20.1.0", - "@angular/forms": "^20.1.0", - "@angular/platform-browser": "^20.1.0", + "@angular/common": "^20.3.0", + "@angular/compiler": "^20.3.0", + "@angular/core": "^20.3.0", + "@angular/forms": "^20.3.0", + "@angular/platform-browser": "^20.3.0", "@angular/platform-browser-dynamic": "^20.1.0", - "@angular/pwa": "^20.1.0", - "@angular/router": "^20.1.0", - "@angular/service-worker": "^20.1.0", + "@angular/pwa": "^20.3.0", + "@angular/router": "^20.3.0", + "@angular/service-worker": "^20.3.0", "@materia-ui/ngx-monaco-editor": "^6.0.0", "@noble/curves": "^1.4.0", "@noble/hashes": "^1.4.0", "@start9labs/argon2": "^0.3.0", "@start9labs/start-sdk": "file:../sdk/baseDist", - "@taiga-ui/addon-charts": "4.52.0", - "@taiga-ui/addon-commerce": "4.52.0", - "@taiga-ui/addon-mobile": "4.52.0", - "@taiga-ui/addon-table": "4.52.0", - "@taiga-ui/cdk": "4.52.0", - "@taiga-ui/core": "4.52.0", + "@taiga-ui/addon-charts": "4.55.0", + "@taiga-ui/addon-commerce": "4.55.0", + "@taiga-ui/addon-mobile": "4.55.0", + "@taiga-ui/addon-table": "4.55.0", + "@taiga-ui/cdk": "4.55.0", + "@taiga-ui/core": "4.55.0", "@taiga-ui/dompurify": "4.1.11", "@taiga-ui/event-plugins": "4.7.0", - "@taiga-ui/experimental": "4.52.0", - "@taiga-ui/icons": "4.52.0", - "@taiga-ui/kit": "4.52.0", - "@taiga-ui/layout": "4.52.0", + "@taiga-ui/experimental": "4.55.0", + "@taiga-ui/icons": "4.55.0", + "@taiga-ui/kit": "4.55.0", + "@taiga-ui/layout": "4.55.0", "@taiga-ui/polymorpheus": "4.9.0", "ansi-to-html": "^0.7.2", "base64-js": "^1.5.1", diff --git a/web/projects/marketplace/src/pages/show/versions.component.ts b/web/projects/marketplace/src/pages/show/versions.component.ts index fe6f9d1d3..d40d6a187 100644 --- a/web/projects/marketplace/src/pages/show/versions.component.ts +++ b/web/projects/marketplace/src/pages/show/versions.component.ts @@ -32,7 +32,7 @@ import { MarketplaceItemComponent } from './item.component' let-completeWith="completeWith" > -