diff --git a/.github/workflows/startos-iso.yaml b/.github/workflows/startos-iso.yaml index bc0fb626e..3490936b4 100644 --- a/.github/workflows/startos-iso.yaml +++ b/.github/workflows/startos-iso.yaml @@ -78,7 +78,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v5 with: - python-version: '3.x' + python-version: "3.x" - uses: actions/setup-node@v4 with: @@ -156,7 +156,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v5 with: - python-version: '3.x' + python-version: "3.x" - name: Install dependencies run: | @@ -187,11 +187,27 @@ jobs: run: | mkdir -p web/node_modules mkdir -p web/dist/raw - touch core/startos/bindings - touch sdk/lib/osBindings + mkdir -p core/startos/bindings + mkdir -p sdk/base/lib/osBindings + mkdir -p container-runtime/node_modules mkdir -p container-runtime/dist + mkdir -p container-runtime/dist/node_modules + mkdir -p core/startos/bindings + mkdir -p sdk/dist + mkdir -p sdk/baseDist + mkdir -p patch-db/client/node_modules + mkdir -p patch-db/client/dist + mkdir -p web/.angular + mkdir -p web/dist/raw/ui + mkdir -p web/dist/raw/install-wizard + mkdir -p web/dist/raw/setup-wizard + mkdir -p web/dist/static/ui + mkdir -p web/dist/static/install-wizard + mkdir -p web/dist/static/setup-wizard PLATFORM=${{ matrix.platform }} make -t compiled-${{ env.ARCH }}.tar + - run: git status + - name: Run iso build run: PLATFORM=${{ matrix.platform }} make iso if: ${{ matrix.platform != 'raspberrypi' }} diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 0a5eb38e9..3f47a65a4 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -11,7 +11,7 @@ on: - next/* env: - NODEJS_VERSION: "18.15.0" + NODEJS_VERSION: "20.16.0" ENVIRONMENT: dev-unstable jobs: diff --git a/CLEARNET.md b/CLEARNET.md new file mode 100644 index 000000000..457a2e4f7 --- /dev/null +++ b/CLEARNET.md @@ -0,0 +1,40 @@ +# Setting up clearnet for a service interface + +NOTE: this guide is for HTTPS only! Other configurations may require a more bespoke setup depending on the service. Please consult the service documentation or the Start9 Community for help with non-HTTPS applications + +## Initialize ACME certificate generation + +The following command will register your device with an ACME certificate provider, such as letsencrypt + +This only needs to be done once. + +``` +start-cli net acme init --provider=letsencrypt --contact="mailto:me@drbonez.dev" +``` + +- `provider` can be `letsencrypt`, `letsencrypt-staging` (useful if you're doing a lot of testing and want to avoid being rate limited), or the url of any provider that supports the [RFC8555](https://datatracker.ietf.org/doc/html/rfc8555) ACME api +- `contact` can be any valid contact url, typically `mailto:` urls. it can be specified multiple times to set multiple contacts + +## Whitelist a domain for ACME certificate acquisition + +The following command will tell the OS to use ACME certificates instead of system signed ones for the provided url. In this example, `testing.drbonez.dev` + +This must be done for every domain you wish to host on clearnet. + +``` +start-cli net acme domain add "testing.drbonez.dev" +``` + +## Forward clearnet port + +Go into your router settings, and map port 443 on your router to port 5443 on your start-os device. This one port should cover most use cases + +## Add domain to service host + +The following command will tell the OS to route https requests from the WAN to the provided hostname to the specified service. In this example, we are adding `testing.drbonez.dev` to the host `ui-multi` on the package `hello-world`. To see a list of available host IDs for a given package, run `start-cli package host list` + +This must be done for every domain you wish to host on clearnet. + +``` +start-cli package host hello-world address ui-multi add testing.drbonez.dev +``` diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index cb9385f41..c3c555a05 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -27,6 +27,7 @@ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/master/install.sh | bash source ~/.bashrc nvm install 20 nvm use 20 +nvm alias default 20 # this prevents your machine from reverting back to another version ``` ## Cloning the repository diff --git a/Makefile b/Makefile index 113b18f98..132270636 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,8 @@ BASENAME := $(shell ./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) IMAGE_TYPE=$(shell if [ "$(PLATFORM)" = raspberrypi ]; then echo img; else echo iso; fi) -WEB_UIS := web/dist/raw/ui web/dist/raw/setup-wizard web/dist/raw/install-wizard +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 := $(shell git ls-files build) build/lib/depends build/lib/conflicts $(FIRMWARE_ROMS) DEBIAN_SRC := $(shell git ls-files debian/) @@ -16,7 +17,7 @@ COMPAT_SRC := $(shell git ls-files system-images/compat/) UTILS_SRC := $(shell git ls-files system-images/utils/) BINFMT_SRC := $(shell git ls-files system-images/binfmt/) CORE_SRC := $(shell git ls-files core) $(shell git ls-files --recurse-submodules patch-db) $(GIT_HASH_FILE) -WEB_SHARED_SRC := $(shell git ls-files web/projects/shared) $(shell ls -p web/ | grep -v / | sed 's/^/web\//g') web/node_modules/.package-lock.json web/config.json patch-db/client/dist web/patchdb-ui-seed.json sdk/dist +WEB_SHARED_SRC := $(shell git ls-files web/projects/shared) $(shell ls -p web/ | grep -v / | sed 's/^/web\//g') web/node_modules/.package-lock.json web/config.json patch-db/client/dist/index.js sdk/baseDist/package.json web/patchdb-ui-seed.json sdk/dist/package.json WEB_UI_SRC := $(shell git ls-files web/projects/ui) WEB_SETUP_WIZARD_SRC := $(shell git ls-files web/projects/setup-wizard) WEB_INSTALL_WIZARD_SRC := $(shell git ls-files web/projects/install-wizard) @@ -47,7 +48,7 @@ endif .DELETE_ON_ERROR: -.PHONY: all metadata install clean format cli uis ui reflash deb $(IMAGE_TYPE) squashfs sudo wormhole wormhole-deb test test-core test-sdk test-container-runtime +.PHONY: all metadata install clean format cli uis ui reflash deb $(IMAGE_TYPE) squashfs sudo wormhole wormhole-deb test test-core test-sdk test-container-runtime registry all: $(ALL_TARGETS) @@ -94,15 +95,18 @@ test: | test-core test-sdk test-container-runtime test-core: $(CORE_SRC) $(ENVIRONMENT_FILE) ./core/run-tests.sh -test-sdk: $(shell git ls-files sdk) sdk/lib/osBindings +test-sdk: $(shell git ls-files sdk) sdk/base/lib/osBindings/index.ts cd sdk && make test -test-container-runtime: container-runtime/node_modules $(shell git ls-files container-runtime/src) container-runtime/package.json container-runtime/tsconfig.json +test-container-runtime: container-runtime/node_modules/.package-lock.json $(shell git ls-files container-runtime/src) container-runtime/package.json container-runtime/tsconfig.json cd container-runtime && npm test cli: cd core && ./install-cli.sh +registry: + cd core && ./build-registrybox.sh + deb: results/$(BASENAME).deb debian/control: build/lib/depends build/lib/conflicts @@ -209,7 +213,7 @@ emulate-reflash: $(ALL_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 rm -f /media/startos/config/disk.guid') + $(call ssh,'sudo rm -f /media/startos/config/disk.guid /media/startos/config/overlay/etc/hostname') $(call ssh,'sudo /media/startos/next/usr/lib/startos/scripts/chroot-and-upgrade --no-sync "apt-get install -y $(shell cat ./build/lib/depends)"') upload-ota: results/$(BASENAME).squashfs @@ -218,34 +222,36 @@ upload-ota: results/$(BASENAME).squashfs container-runtime/debian.$(ARCH).squashfs: ARCH=$(ARCH) ./container-runtime/download-base-image.sh -container-runtime/node_modules: container-runtime/package.json container-runtime/package-lock.json sdk/dist +container-runtime/node_modules/.package-lock.json: container-runtime/package.json container-runtime/package-lock.json sdk/dist/package.json npm --prefix container-runtime ci - touch container-runtime/node_modules + touch container-runtime/node_modules/.package-lock.json -sdk/lib/osBindings: core/startos/bindings - mkdir -p sdk/lib/osBindings - ls core/startos/bindings/*.ts | sed 's/core\/startos\/bindings\/\([^.]*\)\.ts/export { \1 } from ".\/\1";/g' > core/startos/bindings/index.ts - npm --prefix sdk exec -- prettier --config ./sdk/package.json -w ./core/startos/bindings/*.ts - rsync -ac --delete core/startos/bindings/ sdk/lib/osBindings/ - touch sdk/lib/osBindings +sdk/base/lib/osBindings/index.ts: core/startos/bindings/index.ts + mkdir -p sdk/base/lib/osBindings + rsync -ac --delete core/startos/bindings/ sdk/base/lib/osBindings/ + touch sdk/base/lib/osBindings/index.ts -core/startos/bindings: $(shell git ls-files core) $(ENVIRONMENT_FILE) +core/startos/bindings/index.ts: $(shell git ls-files core) $(ENVIRONMENT_FILE) rm -rf core/startos/bindings ./core/build-ts.sh - touch core/startos/bindings + ls core/startos/bindings/*.ts | sed 's/core\/startos\/bindings\/\([^.]*\)\.ts/export { \1 } from ".\/\1";/g' | grep -v '"./index"' | tee core/startos/bindings/index.ts + npm --prefix sdk exec -- prettier --config ./sdk/base/package.json -w ./core/startos/bindings/*.ts + touch core/startos/bindings/index.ts -sdk/dist: $(shell git ls-files sdk) sdk/lib/osBindings +sdk/dist/package.json sdk/baseDist/package.json: $(shell git ls-files sdk) sdk/base/lib/osBindings/index.ts (cd sdk && make bundle) + touch sdk/dist/package.json + touch sdk/baseDist/package.json # TODO: make container-runtime its own makefile? -container-runtime/dist/index.js: container-runtime/node_modules $(shell git ls-files container-runtime/src) container-runtime/package.json container-runtime/tsconfig.json +container-runtime/dist/index.js: container-runtime/node_modules/.package-lock.json $(shell git ls-files container-runtime/src) container-runtime/package.json container-runtime/tsconfig.json npm --prefix container-runtime run build -container-runtime/dist/node_modules container-runtime/dist/package.json container-runtime/dist/package-lock.json: container-runtime/package.json container-runtime/package-lock.json sdk/dist container-runtime/install-dist-deps.sh +container-runtime/dist/node_modules/.package-lock.json container-runtime/dist/package.json container-runtime/dist/package-lock.json: container-runtime/package.json container-runtime/package-lock.json sdk/dist/package.json container-runtime/install-dist-deps.sh ./container-runtime/install-dist-deps.sh - touch container-runtime/dist/node_modules + 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 core/target/$(ARCH)-unknown-linux-musl/release/containerbox | sudo +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 | sudo ARCH=$(ARCH) ./container-runtime/update-image.sh build/lib/depends build/lib/conflicts: build/dpkg-deps/* @@ -263,7 +269,7 @@ system-images/utils/docker-images/$(ARCH).tar: $(UTILS_SRC) system-images/binfmt/docker-images/$(ARCH).tar: $(BINFMT_SRC) cd system-images/binfmt && make docker-images/$(ARCH).tar && touch docker-images/$(ARCH).tar -core/target/$(ARCH)-unknown-linux-musl/release/startbox: $(CORE_SRC) web/dist/static web/patchdb-ui-seed.json $(ENVIRONMENT_FILE) +core/target/$(ARCH)-unknown-linux-musl/release/startbox: $(CORE_SRC) $(COMPRESSED_WEB_UIS) web/patchdb-ui-seed.json $(ENVIRONMENT_FILE) ARCH=$(ARCH) ./core/build-startbox.sh touch core/target/$(ARCH)-unknown-linux-musl/release/startbox @@ -271,27 +277,28 @@ core/target/$(ARCH)-unknown-linux-musl/release/containerbox: $(CORE_SRC) $(ENVIR ARCH=$(ARCH) ./core/build-containerbox.sh touch core/target/$(ARCH)-unknown-linux-musl/release/containerbox -web/node_modules/.package-lock.json: web/package.json sdk/dist +web/node_modules/.package-lock.json: web/package.json sdk/baseDist/package.json npm --prefix web ci touch web/node_modules/.package-lock.json -web/.angular: patch-db/client/dist sdk/dist web/node_modules/.package-lock.json +web/.angular/.updated: patch-db/client/dist/index.js sdk/baseDist/package.json web/node_modules/.package-lock.json rm -rf web/.angular mkdir -p web/.angular + touch web/.angular/.updated -web/dist/raw/ui: $(WEB_UI_SRC) $(WEB_SHARED_SRC) web/.angular +web/dist/raw/ui/index.html: $(WEB_UI_SRC) $(WEB_SHARED_SRC) web/.angular/.updated npm --prefix web run build:ui - touch web/dist/raw/ui + touch web/dist/raw/ui/index.html -web/dist/raw/setup-wizard: $(WEB_SETUP_WIZARD_SRC) $(WEB_SHARED_SRC) web/.angular +web/dist/raw/setup-wizard/index.html: $(WEB_SETUP_WIZARD_SRC) $(WEB_SHARED_SRC) web/.angular/.updated npm --prefix web run build:setup - touch web/dist/raw/setup-wizard + touch web/dist/raw/setup-wizard/index.html -web/dist/raw/install-wizard: $(WEB_INSTALL_WIZARD_SRC) $(WEB_SHARED_SRC) web/.angular - npm --prefix web run build:install - touch web/dist/raw/install-wizard +web/dist/raw/install-wizard/index.html: $(WEB_INSTALL_WIZARD_SRC) $(WEB_SHARED_SRC) web/.angular/.updated + npm --prefix web run build:install-wiz + touch web/dist/raw/install-wizard/index.html -web/dist/static: $(WEB_UIS) $(ENVIRONMENT_FILE) +$(COMPRESSED_WEB_UIS): $(WEB_UIS) $(ENVIRONMENT_FILE) ./compress-uis.sh web/config.json: $(GIT_HASH_FILE) web/config-sample.json @@ -301,13 +308,14 @@ web/patchdb-ui-seed.json: web/package.json jq '."ack-welcome" = $(shell jq '.version' web/package.json)' web/patchdb-ui-seed.json > ui-seed.tmp mv ui-seed.tmp web/patchdb-ui-seed.json -patch-db/client/node_modules: patch-db/client/package.json +patch-db/client/node_modules/.package-lock.json: patch-db/client/package.json npm --prefix patch-db/client ci - touch patch-db/client/node_modules + touch patch-db/client/node_modules/.package-lock.json -patch-db/client/dist: $(PATCH_DB_CLIENT_SRC) patch-db/client/node_modules +patch-db/client/dist/index.js: $(PATCH_DB_CLIENT_SRC) patch-db/client/node_modules/.package-lock.json rm -rf patch-db/client/dist npm --prefix patch-db/client run build + touch patch-db/client/dist/index.js # used by github actions compiled-$(ARCH).tar: $(COMPILED_TARGETS) $(ENVIRONMENT_FILE) $(GIT_HASH_FILE) $(VERSION_FILE) diff --git a/build/dpkg-deps/depends b/build/dpkg-deps/depends index cd29714b2..f495df85d 100644 --- a/build/dpkg-deps/depends +++ b/build/dpkg-deps/depends @@ -9,6 +9,7 @@ ca-certificates cifs-utils cryptsetup curl +dnsutils dmidecode dosfstools e2fsprogs diff --git a/build/lib/scripts/chroot-and-upgrade b/build/lib/scripts/chroot-and-upgrade index 3af93f5ef..8c3da37b4 100755 --- a/build/lib/scripts/chroot-and-upgrade +++ b/build/lib/scripts/chroot-and-upgrade @@ -43,6 +43,8 @@ if [ -z "$NO_SYNC" ]; then mount -t overlay \ -olowerdir=/media/startos/current,upperdir=/media/startos/upper/data,workdir=/media/startos/upper/work \ overlay /media/startos/next + mkdir -p /media/startos/next/media/startos/root + mount --bind /media/startos/root /media/startos/next/media/startos/root fi if [ -n "$ONLY_CREATE" ]; then @@ -75,6 +77,7 @@ umount /media/startos/next/dev umount /media/startos/next/sys umount /media/startos/next/proc umount /media/startos/next/boot +umount /media/startos/next/media/startos/root if [ "$CHROOT_RES" -eq 0 ]; then @@ -84,7 +87,12 @@ if [ "$CHROOT_RES" -eq 0 ]; then echo 'Upgrading...' - time mksquashfs /media/startos/next /media/startos/images/next.squashfs -b 4096 -comp gzip + if ! time mksquashfs /media/startos/next /media/startos/images/next.squashfs -b 4096 -comp gzip; then + umount -R /media/startos/next + umount -R /media/startos/upper + rm -rf /media/startos/upper /media/startos/next + exit 1 + fi hash=$(b3sum /media/startos/images/next.squashfs | head -c 32) mv /media/startos/images/next.squashfs /media/startos/images/${hash}.rootfs ln -rsf /media/startos/images/${hash}.rootfs /media/startos/config/current.rootfs diff --git a/build/lib/scripts/prune-images b/build/lib/scripts/prune-images index 20356a28c..1203d2377 100755 --- a/build/lib/scripts/prune-images +++ b/build/lib/scripts/prune-images @@ -33,10 +33,11 @@ if [ -h /media/startos/config/current.rootfs ] && [ -e /media/startos/config/cur echo 'Pruning...' current="$(readlink -f /media/startos/config/current.rootfs)" while [[ "$(df -B1 --output=avail --sync /media/startos/images | tail -n1)" -lt "$needed" ]]; do - to_prune="$(ls -t1 /media/startos/images/*.rootfs /media/startos/images/*.squashfs | grep -v "$current" | tail -n1)" + to_prune="$(ls -t1 /media/startos/images/*.rootfs /media/startos/images/*.squashfs 2> /dev/null | grep -v "$current" | tail -n1)" if [ -e "$to_prune" ]; then echo " Pruning $to_prune" rm -rf "$to_prune" + sync else >&2 echo "Not enough space and nothing to prune!" exit 1 diff --git a/code b/code new file mode 100644 index 000000000..2a071fb30 --- /dev/null +++ b/code @@ -0,0 +1,690 @@ +{ + "id": 4228, + "value": { + "serverInfo": { + "arch": "x86_64", + "platform": "x86_64", + "id": "81260ce3-b6f2-471e-a77e-0250c11fb907", + "hostname": "tasty-mahogany", + "version": "0.3.6-alpha.7", + "lastBackup": null, + "lanAddress": "https://tasty-mahogany.local/", + "postInitMigrationTodos": [], + "torAddress": "https://4iqvmnjyqlqiq2nfavk7emhyjwhq6s454oubur4givisxblfdwxfj6ad.onion/", + "onionAddress": "4iqvmnjyqlqiq2nfavk7emhyjwhq6s454oubur4givisxblfdwxfj6ad", + "ipInfo": { + "enp8s0": { + "ipv4Range": "192.168.122.86/24", + "ipv6Range": null, + "ipv4": "192.168.122.86", + "ipv6": null + } + }, + "statusInfo": { + "backupProgress": null, + "updated": false, + "updateProgress": null, + "shuttingDown": false, + "restarting": false + }, + "wifi": { + "ssids": [], + "selected": null, + "interface": null, + "lastRegion": null + }, + "unreadNotificationCount": 0, + "passwordHash": "$argon2id$v=19$m=65536,t=3,p=1$qZNXS7Xk+qeOfi7ZO18OpA$VHr96ABySCvi/fa5p+N+SY8XJ/FyhxVp3LlBxmxQa6Y", + "pubkey": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIM1ThH4SGEGzCFoKlkmMw3tNXvx975xXKEn/dNnBDEGb", + "caFingerprint": "88:CF:91:19:FC:35:18:E8:B1:8E:B1:36:53:B2:22:6A:EA:5B:58:E6:35:7A:A5:82:1B:39:1:D5:E4:F8:57:3C", + "ntpSynced": true, + "zram": true, + "governor": null, + "smtp": null, + "devices": [ + { + "class": "processor", + "product": "AMD Ryzen 9 5950X 16-Core Processor" + }, + { + "class": "processor", + "product": "AMD Ryzen 9 5950X 16-Core Processor" + }, + { + "class": "processor", + "product": "AMD Ryzen 9 5950X 16-Core Processor" + }, + { + "class": "processor", + "product": "AMD Ryzen 9 5950X 16-Core Processor" + }, + { + "class": "processor", + "product": "AMD Ryzen 9 5950X 16-Core Processor" + }, + { + "class": "processor", + "product": "AMD Ryzen 9 5950X 16-Core Processor" + }, + { + "class": "display", + "product": "Virtio 1.0 GPU" + } + ], + "packageVersionCompat": ">=0.3.0:0 <=0.3.6-alpha.7:0", + "ram": 10285481984 + }, + "packageData": { + "vaultwarden": { + "stateInfo": { + "state": "installed", + "manifest": { + "id": "vaultwarden", + "title": "Vaultwarden", + "version": "1.32.1:0", + "satisfies": [], + "releaseNotes": "* Updated to the latest upstream code with notable changes:\n - Fixed syncing and login issues with native mobile clients\n* Full change log available [here](https://github.com/dani-garcia/vaultwarden/releases/tag/1.32.1)", + "canMigrateTo": "!", + "canMigrateFrom": "*", + "license": "AGPLv3", + "wrapperRepo": "https://github.com/Start9Labs/vaultwarden-startos", + "upstreamRepo": "https://github.com/dani-garcia/vaultwarden", + "supportSite": "https://vaultwarden.discourse.group/", + "marketingSite": "https://github.com/dani-garcia/vaultwarden/", + "donationUrl": "https://www.paypal.com/paypalme/DaniGG", + "description": { + "short": "Secure password management", + "long": "Vaultwarden is a lightweight and secure password manager for storing and auto-filling sensitive information such as usernames and passwords, credit cards, identities, and notes. It is an alternative implementation of the Bitwarden server API written in Rust and compatible with upstream Bitwarden clients. All data is stored in an encrypted vault on your server." + }, + "images": { + "main": { + "source": "packed", + "arch": [ + "aarch64", + "x86_64" + ], + "emulateMissingAs": null + } + }, + "assets": [], + "volumes": [ + "main" + ], + "alerts": { + "install": null, + "uninstall": null, + "restore": null, + "start": null, + "stop": null + }, + "dependencies": {}, + "hardwareRequirements": { + "device": [], + "ram": null, + "arch": [ + "aarch64", + "x86_64" + ] + }, + "gitHash": "74a504429097e933285782e1e4c425da5895d516\n", + "osVersion": "0.3.5.1" + } + }, + "dataVersion": null, + "status": { + "main": "error", + "debug": "Error { source: \n 0: \u001b[91minvalid type: map, expected a sequence at line 1 column 1353\u001b[0m\n\nLocation:\n \u001b[35m/home/rust/src/core/models/src/errors.rs\u001b[0m:\u001b[35m509\u001b[0m\n\n ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ SPANTRACE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n 0: \u001b[91mstartos::s9pk::v2\u001b[0m\u001b[91m::\u001b[0m\u001b[91mdeserialize\u001b[0m\n at \u001b[35mstartos/src/s9pk/v2/mod.rs\u001b[0m:\u001b[35m265\u001b[0m\n 1: \u001b[91mstartos::service\u001b[0m\u001b[91m::\u001b[0m\u001b[91mload\u001b[0m\n at \u001b[35mstartos/src/service/mod.rs\u001b[0m:\u001b[35m271\u001b[0m\n 2: \u001b[91mstartos::service::service_map\u001b[0m\u001b[91m::\u001b[0m\u001b[91mload\u001b[0m\n at \u001b[35mstartos/src/service/service_map.rs\u001b[0m:\u001b[35m80\u001b[0m\n\nBacktrace omitted. Run with RUST_BACKTRACE=1 environment variable to display it.\nRun with RUST_BACKTRACE=full to include source snippets., kind: Deserialization, revision: None }", + "message": "Deserialization Error: invalid type: map, expected a sequence at line 1 column 1353", + "onRebuild": "start" + }, + "registry": null, + "developerKey": "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAIwXjctXTc37QTXRYWxLxElY1r2NhoKJRrl604Nu/0l4=\n-----END PUBLIC KEY-----\n", + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAMAAADDpiTIAAAAflBMVEUAAADh4eHZ2dnZ2dna2trZ2dnc3NzZ2dna2trZ2dnZ2dnZ2dna2trc3Nza2trb29vZ2dna2trZ2dna2trZ2dna2trZ2dkAAAA2NjaHh4dra2vR0dEaGhqjo6NeXl7Ly8u9vb0oKChGRkaxsbGXl5dRUVF7e3vFxcWpqal0dHSQl0TIAAAAFnRSTlMADejca/IbzkXAsoBeJpJUnjqmdYgyp8THagAAKQJJREFUeNrs2ttygyAUBVBAkKsoak6mfenk/3+y6VMvYyeaqAGz1y+wOZcBBgDwEnidTJDex663tvqi6EpVV9pa23ed9zK0puEMDoM3JvjOakFLVNp2PiAKJeNJ+l4LeozQLkpTMyhIbWS0gtakdD8gBgU4taMTtBVlozwxyFMToqY96CgbBjnhZnCK9qScNxgQs8CNt/QcekQIniwtPXyE4Dhq6RTlQDmJ/WBvyVeUkyoaBjvhphOUH9UHNIPt8dDnUfgnOWRgUzw4yh0ysBXe5nz3f3ItMrC6FHPs+/9RMTFYT53ZzD9H5bEbrqTNv/FPs2gFj6vHkkr/X2LEs9FrXv5vtmVwHz6U1/mniAGd4A5NpOPo8I1koVR+7f/N4q1ggdbS8ejAYJag6ZiExDBwE5fHmPymCY8I3Dj+krf+ORQikNHxv13O58v7B+0IEfhk1852G4WhMABnmTRJN3X9f8MYDBgi9f1fcNqqKkkPsREYRoV81xE3xz5bfN7Y4bean7TFuDaXxUCD2zXGZfgtw8hWfxYXJ3ZbjE3xm8Lo1peh8MjjHuHYSqk0gU/EIxF87KEo4gQBbS+roS9XTwjHVPykDJwMT5h2X60MAtpfFsTvljcIyOT8khu4pDyRtv9qSA+XbvB2hZBislWsLH+waCDiT1YIajPzbvB1j6AyHilwnmLN2wcW5DATw9xbgeUDAjuw5rqtEYUI51Q8dkBo13N9PHi7Qmi6XWU3bGDQrOKJHOE9L2bobo/gbMtrnbLmOy2R7BbC287uFfnyBgNI2yV2y5ovspHjoIR0P695YLfGEDSFBJJiIwUpoaAxiPWMmsHlAwZRtrvXEWuedGHZoMQQZrQU2K0wjKpVZjc8y+CUZZMKA1nN4gV59+ufWLixkTY4kbLmLu9GsxHcTJKho6fpJ4HHNTqJNEkdG9dPKMmVoKWDxRGTe0uFZGK+KyJ0s5p4J7B8QTcV/Y83CrY5AYoOyh1//4rR6n51YuKdwOsW3VTeTZyztlcyTfgvd+XtFaRD72lx0uPAH3RkeaQwjgrgOwGGHkbEv30NMIUYQDt5WUzS1TW6SvnJXQZyOsT1l9zSNj/MHek/xMJoO8V/B/oMf7kIp5TR6a2M4rRQ9FJFGkflG50ySLE4Jd1tpjcQvqAHGSXjKL8jkI2IkWcL7cyiF7zao4eMLVa8miPS+CGhlKGP9ZTei/Xc/SUURBmwHJUV6V9K0MtmOu+Gn9HPgYIoAylHlYr0Lx3Q0/1iEpbX6MQf3BI1jkujVroOSXtTnQbu1uhL+e9hyZGV/tyj0Nvq9z8U2W3Qm+Y5eYYPptQcmS7/4kOWO7JEAL+9EXhGAO6baN8U/wv1j717XWobBqIAHALhkl4olJ6VbCv4Ipvw/i9YZihVA3IiOStnxfT7S2aSyR4irS7JcwdLe2CSTzUR+AEGHWWqA4ebfFcELq/AwVCmDFic5/plk7+WYFFQpgrwWOW5P3i7Ao+eMtWDS44XyC7ARVGmFI6U8w7xd7ChbIHP/SIrZ/cIVg+tUkON9z51AOpBKTU84pBMm4GzGwSz9KqvsSP/JmC8Dah7eqUR7jyfdeGY9k/TX70ZeUS2NHxM73lEgGUu7WDM6n9N/1IGf+XfBfr7QKPoXzXCrfLYGYhq/3vapTTeaymV3pq6NranVFq8pxXt2gD4XAm4WyGCovcq7XkIG//z6IqSUHBGnqfCYVktCcXVH/7SPKZvAopZxhnAefTHDHGknxaNXf4jP3cFrNSUgp1nqqlLuCtjfgiSy6LgLSLRmKJ+LX9FKVh/O8qveo1AXdAY7Mg8AbeIVdGovoZpKIkC83UbzRZ1v+fP2JV1An4imqI9Kkqjgleyp6M9FGLJ/U6pW8RTdAIWXpZOQMEjz88Af/0FBqCaMB45EgIgMgHX8JMXgA1GbCiAiAAI7AbvVpiip/lZQM4Y0GNEZgkIqr+QhX4DQfuOBcZllIBve+svLACiTh4UmErSqvC3Jfb5H4BxBaZaybk+fHmOvYQF4HMMAYLOB5xdYbKBDvvUAdA4SPoZoaDzX5Lec1FtoMERzkWcE1wjhKAAiFoIMggi+KTodwQRFAAy8l9LqPViIhlf/nSiN72BV0MhZAXg5DdGLnCcjk5hkDIfjbxBLG9rMPJnf2S03i+MkM8iIhxr+XVxOpdLHIuSatqiJ58urP590TaUFI624l0O4F8A6IbBYBQlo4ptOX7abwj5/Nd4UW4LRclglBl0Bw9BzeAaB7h7EKowcwag2djywHlPZXZepI/Gm9JuGkoCXuZP5iqLADeL0/iCwzQ5vhBsiV3V68eg6V2zMTVQm7HaDtjxpPuK2G29xXc0AvxYnMI1DrPk+EIwELNW1/4YxtP4qNYtMRu8xXcMPhLRCgTtADfkfAxB2TJX35bw08fW3yltS6z60hXfQ8FDwN7w2TkOq8n5GIJHRYyULjFOH19/p9S8r7x0xffoEGA5+77QGgEMzaR5fsJ+mqP+zlPR0EwsQlzN3Ar8hKAAbDocpnnq73QbmoUG5E0EryEmAG7gP0AzvuduOpCeQZiLBQPuFUBKrNIlgmnm+rvLi0kh1IwrgjcIpCilxpYA2BOgEaO0DaWk8ELYNOABoQpKR1nEGijAgFhWUToF/pAzDbhAMEOpKIMJNOv/v2MUpWIAR8Q0IGoLkNJoO0yjeevvdC2lAQ+2jcH0v/+oKIG2hgdLAjSipI+AQoz1DAl4QIyC2PU1jqG56+/UPbErEOVhkdrXFWIYIjn//QcToHGkWhEzgyjpf3L0CnGIl8XxNH/9HVsRK0RaJu4FvyCSIk4VOGjy0uAwECeFWPeLlO4QqyBWHThopvqnT3yBaCkHgbNzxDLEagMWA30wgMUTsTKIkH4Q+I54xKsEC0vvWPB4JlaYYL1I5RoTKGJlwMM0RE6zBZOGOClM4W4KnHwA4J8E9ODi9nJbAy41sSowxepy8UrAAMC/ElCCj3lu22cDRoWIz7u3QUDAACBzJSCdilhhkrdOQMIA8Ju8M21uGgbCMDmacpWrsCvLsmzLlhP+/x+kMxwephAdq1XW8Hxmir1S9nwll08CHAjmgkVRkAVPJfAGMtFYlhbkYrEoGvLgkAY8QC4dlqUBsbRYlg4yYTgo8AqyQfxfYsCMZYFcyp8YPUI2PRamB6l4QW/6pmwFcIBcWoUFER0DWiyMaiGbQ9Eg8AGycVgaBUKZsTQe8vlUUgUC2TRYnjPI5Mdel+Lt3tZTgQzeIOKonvD6iaZ7YloL48J8BZG0yMAET0zdE41+wqsnRkRUYWXcfseUAd78674jiIRgBg7vUC4P3O1lvTjiABJRWJkZApyq6IB7rI4GgZyRAMcPoVQ/8AS/IeGCRQMCWbA6CwQo8kmBT3Adh/W5gDxGrI6DAK9K6EDFhb4nLIhjwPooCPG+RAko0AMIHAlqrI+CEAf6XTASYx9iB9IwWJ8FghypU+B7kb4PPQhjQgKM5fD9Q/EmsIiPP4qLARbr4yGCN8QekND0R5o0sEUCjA6AKhE+Agh1AcJkIR0S4A2D70gOQOzbC4sBHgkwJ8InigMQ2gWXJgtpsT4KInlHcACCHaAoWciMBNgr4VN+D0DsIEyYNNBhdRREku8CHg4gdRQuLAa0SID/9Q9f8jMAwX0wQTGgweoYiCbbBRwAQLAJBEkDHZLg938nShNQrAsQIw3ssToGkvhMcgBSXYAYaSD13fkToLsMfeh7+IHYX4EYaaBCIvwl0JGkA5A6DxciDTxjiNu/+Z6YAch0AUKkgV+xOj2k8pb6USgWF6DMvyANHJGCUVVc32v+6wCG9Hfv9T8gDZyQhD7XSX4+8l8I5dN/wMM/MBLU1Ez2UkEOleoCdneQzpBRx4/bl4UYci2rq1Q/J/77IDJaucvmpYEXuq6zVTVy389Fm0D0majp4Ynz5mOALdDPPteQRN/tuB3AmJPBq43HgBZJqBw3MraQw5FUA4Zpshr5zcalgXOZlq5m3/YpaeAJMmhN1iy33XgM8GUev1UVXMBH4nnwgg7A9OsoddOykLaUAzuzv3XCrUF7SKJrtFPZLbx507IQ4tPP2dWEcrrpIJFd4Vuhp057Re3gtZuWhTgk0VLLCeV1N0Esj6VSwKFbrDKFArelFtI3pC3Yym4NYZ5gl26AIIcSDqCzY9ljXZcNx4Cm5DCrQSKjDW2Cl3QxuC2v5jTbjQGq6DhbsR8Xe0dWgngGIY/erCzkXPbJB+YDg3HdwC9hl1d4wYbNSgOXwpI2y35g6D1xEKyQjGlLX680wa0YC+/c1nAfl3hNawIMPAf7l43KQobi9cuMdOAqJ9IcqEcyjh5KxUgDNZI487hYuMqRdisgkhnokUWMNNAgBcXkYwe4xmuaFMggEV0itxQSAyYk0XB4lbA/PCUcB6GvVCAD3PZI0DI8ND0P1HCdIyEC0F1AV6alLkIWQh0E8ly2YXq4zj0hAtDdXltmqCZCGkhcqZlnX00Q4oGmBVuQwleAfyYGUKUgLOeMFgjySNSCOZbXtpuLAdRBIMufdRDiegzYQZjeIAFdRlwtQBo485SumpoAhDkRj4R3LC7AbC0GOJZirScnAGGO1M8DaiSgy/zRm0sDW0RxZtAQxau/q4EPFabgfZG++s1lIQ1Lu66vYYPDiXAnAP0xbZHJ2s1lIQopjBy5cA+RvCfLwTuG51yQxAJV6Vmetqc12WL5FNACMacBlkVdM0JVFhZ/ZTkTgJW7AgeCVPm3V9SoWhPFkbGcayVBHykpAN1ZWZa0SkNFziw1iyUF1gTeFDgSOhd3AS11DFoRzdG1GKq1Ql//OQLsIQUb8klKK5XkAhx1DFKPkaNv6QOGLKeI2D8EvhBJNoL/uRqdj4/X82ZkIROSmOMdgO/gO5MvlwH/pRB8AwGiPZYbYGVw+AzPEgNaYIRfCuKDhiyVAP/lgMgrSGSOTHGW2Ce2VLVJLQyDqxrChmyKzUIPL57zcAepmMh1aCKj4GUjMeDCMQh0EbXCXCr9vXsgFIEBl91EVXjDlkeClqFcmVIMSX/vt/QUAKCJz3Bd3D/Tm5CFUAeBFAu5Qu/9oUAKAD6+IdHHFW3DJmQhM0PLcoo05FBEEvnHJACSSXkWH7dY4xZigGMYWrgMQ65AOidqFwBgSunGTHH/ckEULwtpkcRCME/A6im8JacA85i0F+P89Rnlx4AGyw8CVY4hV8YZUvkcOBESYLKpMykVVw0pJNEDPw6LDwIvmYZcMXaCJO4JV8MNi0kfydm4d2xQegzoGZ5QhQ0ZrpTMMkACu0wtQN+MuEJ67sufA6xwaWCDxfPUjmbIlbHpIZaXWd8Ia1zuUF5HrpZD4dJAVT5LUdmu9DmugTge0wXhsyf8AlVkRTyjbGngGUnMkbW9I2xAP0MEHxLbQJM1+Bxa8qpjYoAwaeCCJFp4jqUYMjMlfNYKugukfSNRlTFcWa2AOWRJA0ekYKP/5ECUIozBlHAX/ZGw3mM0PilyRZVEoqSBA5K4RP+mLf1Msu7hGi9jR4H9iAn0KbVTGzMSFCUN1OUfrs00ZJixhys8xuaAHlPwKalrnI0lSQMNUtAJUd3yLMbKh0hBcIdpdAl/I87LCpKFXBDLJygEQ1J+DYfIPqCm/wSnv3rErY0ELTKUKIZgSEpVvIu7GMJhKnPstrWRlZYYaSB1EJgYYztyj0TBFb7EfSLAYTK2h5XeBnZKsNci58aoDp9Db1POBENSbHGMmwVrzMAO8J1BZ+i4ldQY4JGCyvjemv5lSFu8KH4Td0P4hFkYr7X2JuARI+ctQqSBLZJo0ruLqyEZwuHryEawRx7GNtrQQmQhM5NnakfkQcE19sEiINwIYmraOpkxwHHtywFZGHu4yi5QBPDugC7lpyZCFtLyRaYOV6qtPzzEigF6h6Uxa1d8M7KQhtEvXQyWxvUQ4GVgEsCYByypDRcJ0kDF2qFcsCwegjyuVWDdHaCDC3QRGAPOSOICAXqNBbEQ5kOKHKgpufxhjLwYsCB1EFhxCzQQZlUG30O9HWD7rLGrAGmgQmTXKfS24vrDfZokvEM69gxVhBdfoThnatEbx5n924Er+13ascCJf/lXRhQmDdTkB6q2BSaI5CHxTMBkkIAfIC3iypIGGmLZk8DgkYCZIJaXgVkgoSVEWP7V40qSBk5Vk5LBU9o/0RzXz4Uz7wA3QCoKRUkDbeWyZHD86w+PgVkgTSG84iYIwPxpfjqtqd6YmBym43tI4PO6AeLxrMu/0oqSBna3GE9NjlkM8zqoCKU7QxVY/o2MBO1tBtSTYs187gN9ILpzVgRPPAuSBrY3k6hcFGOg2Qf6QNQmjSItQitIGjjf0Bt1iq323QfUAERrzEDDyokBrmg+Isfgu6wN0FSqxC5ipIHtjSsStlrjy9oITGCpNZIzUqSBzY17EorncoQfrcAvkIitFYS1lBjgbtyV9Fz/0duAIIxkjgWoDEJkId+4OxO0xmEYCptSoIWB2Z+y703L/S84y8dMZiNO8qxGnf8AtDWyJOvZUrm2LvGs5fPeLOgSXRbnW//axrWQeG1lMiYuW4zy4BkZTy1GB5rextXAiBQCaTotr/fkuRFIVaZy0ByFX/rVv8URNLlW5fWd50YgdWGpBU9kIQY8r/4lTjICEweeZjWJjc9/JyNeffMBqFdPRVutj/wwwwO00Qqrnxq4FlKtfxitRHQUuP1kMbAs1jmGN7L61cBk/XJUqXD5epAD90quGDS8CtOCJxOGDh4IR8jHgetBDaa8/1IDuIRrISehSBECGYGIA4MHILw/WwFXntBFU6hZIG8AfBxwX7kmvD+/9uoz+kaxLwRyYSiGB68BVJEspEYYsnV3YKfpgfRPolGJEfwG0IoHtgBiXhI8CEMCD3RBjHwm4mkUXhLbr0EYKqHoQJEKRYUwNCpOyO8BElnfAMhC3AEUnTDU8MAYAJ8H+D1AvX7+qzCiQWHlteeXHLSs0PM22MABKNSQllUiwBE8/FkUf3BpBqAwpklJjPLnwZdmAEwIOIBCvzuXvu3FoOBDgN8M3VfYped3nn6HVuXoY/pWaoIRfPOiDBwDFYa1zsk/TWwB6hhYYgSfAbSZ2rrrn8X4VKwWhg48fChqMcKNtxRcrl4KDjyn4cKugtCl4AqjuK9sTItBWpNa9KvQBV7BkBi0+W4ApuVghVlNqsvOC4H8N/HLwZdzIURtWht/FZPYAGYuhGy+G4DlK2Fa8xr1A0+CgIgHqlns3vKlUD4dGzLhyxQCR74K5f2HEPDB8LVwrZnN/HMcMvNkC1K89x8M4B52H4aEatWdYj4HYegRkIrw/qPcW38aFqoom+OFyxMCPeko9zRs7zEAKg6cwKA/roMvP/J1UBOPQx/wgr3n4WtKgo0wxODQfx4+GMAWsygLBQOw16kvPZPBrdsg4ukfBmCoRYzW0D59j9MgKL3Wp24X9QgqFOKuuV6NzfkczjpNoggDeFbIg6xdCyktRQDlNnG3+A07jSLX7Ncck4eOsGRamedOtVVsiqCchKKEB+LUqT2sQC3wvF9kAC1RCWI448yGIyk+haVVq73eOs+VIMo9xghLcr7SzLMdIVB1wa+WzAso1lqH6nzF2dqMEPiNRGvFr53z6MGURtIgMPW55JnWjhDoOZJyjzH2ntHBxNAolYXoz/V/SewIgR7D54ZG7T1Do9ixcZiFmemtbLp5RGBkBGps3JNz82rBZa25EjbmN9MHzgiBOYqWBTw452kXzj0TyTELM4MbCmGIQTBHDOZHx76dNzq2XX0pUqFoAeDChEAAsdLv/Dk7+IowxKAVUSPDmzphaMDCO6Qc0/j8YgAbTCC2sBZnkQQPwtAhNJFWGLq5cs5pvgwQEGh45/wSIwBkBMoCbtwL91q7okJoCmE46HuZAqFp1b7HvXvhScsrxpiFjc69jTCcEJpezdifnJt2DiwnrgmfBBjo3Z0KQ4bgLF78Eh4e3Au7QOUfPgkw0L0/FoYE8+ANkigJ7dwLV9z/P+CVAANNGyJhqBCaVtQs4PNPA9horUiPmaw+wecoDDUIiBRgUR6wuXI/uOPqPwGTgNUbN/Uitgy+EVHywHfuJ+/Ugm4KAg1JsFR1MEeEJtUzyL37yYPHAi0lAbrNGythiBCck57De3A/2Vmem3rW9q2JgnVRPItoJQFb95PPtqemnfHddmYs4Glegfjs3JRjQCvW1qQRhmeM0P5n1p7jdTZXbmCvJo6dQHD2IQ6FMHQIzkkvAly7X3giCkHEhltlV1QXJAQiEdEqBL1zA+NqQJnYSoz1+rflwlCAgEgBFt4QHg4BfjWg6mtL24Lzi9kFRbtSllL3FcbZuV+4vYGHtsjMHI3YHq4XIwQuPfJmRQsfN7fuV+7gpztYiQFKXZw7Y0Lgwghw6DCBjRuY/joobiyUR7UkwcaYELjkdzYxJjHkgDPfBpRxbWBn1Bqn49SaEDjb09Vxiak8uN94j+lUfbZ2bOw1jsextaI35q1zX2EGO/cbV9eYQ1usmx0fhYIMuGykY087/rTPz+bW/c49ZtLV8jcXcT4W6cIbVQQC9lRad5jJUAf0K8J83TwFj34bv1gYYhCwOUmL2Xxyf/AesyE2HIFa0TYi/yIBeyrFfN64P3i8wQich2pAoNnK1x8BLuInHjCbm0c34BMEeTdcgkX/BWcvDB2CU2p++N79xRPmkl5GgJxokrUwpAhOr/fhQxnIUwpacEy9EEkwDltcLEDAFrsyzOetG/C/DuG9cAUO/T4uiTCcEJxKNf7cOkcnAZVMJwGHfienTAgyhCcRxf21d//gEzxMdFEXcVlGeuoyIG/fRI5D6xBDFYCpBBTEevPwV/gpa9KPcL1qDvLG/YPbDTwQx7AsBYH+I55MCGoEJ1U8hg5CACEHVFzazcM/41uUUZp9/VJiMsOrQEIOiERWdwEB1ZuCdCahSTPi5/jZun/yiMkkIgZcQDD9NiVNKTixbiL63v2bDSaSi4gBFxDsBkcuAxZM2+cAyL6sN25gUTW4NFIuD7ZxC2Nl4Jgpb/t5cq+wwzQiK7lyE0YPSK0JgbVuKHrjXuH2GlNIzChmXRjX3RkTAjvdetT1rXuND5hAbidZChQDDsYiQC0LaTGFvRtYoAiWmSwlR2iKEDEgNSYE5rKUrMQEPrpXedzAS2PpvHQKEQNyY0JgpJuPbB7d69zrlt9ahCYLkL4VtoTAVrkoeedG2MJDa6xkEqKHWWZLCIxEd49t3QhX/gTAVs2k4hP41pYQGIvoeqRHN8a9f8PZSplrITgAwLMpITAV0d1j926UrT/k2sqZe9oeI1NCYCGi6wK2bpSrKRmApTzwKAw5UJoSAluhwTiPzhExQGhqBCYSgoKMuRECUwsNRvngPLxRMADVPDAWggxo/psfMyktfXAeHhVax6vmgSm3Wqml31IKT4Mxrh+dj3cKMoVqHtgIQd9xix2WQt3D7p2XncL0KDoPVDPKiFrzDkFpheeAUd44L7d32hZQIyzCkAkBgpLWQlNglLsr5+cTRqmKWkhi8PCOU3W1V8kA6yLHOO/cBHbwUuV9ERF7p0RITrISJxCEzACzqOjzCl5u3rsp7DGRNk8OkYGtk8kqZGDhg2t0SPIWU7lzk9hiHnmcNDPtIEdIElmFBARsLhs1SZxjJlvnwTM+gohgqiXUSlahQkCO+lnU8CicSAND3WWPUgSklhWoQcCdAOoUS7h3E9lhCfF6/rMXfXSFwELfAQzNQYk0kDBizTTgKKroR7H8HL7n2k1miyV06y1gJGcnAgFnwB0WsXXT2WAJImulAbHMxlA1K430j5/+FJBPA6v1jlGp6KEvBBZnOX58cjN4v4EXvpKRIxiNKMILgVQCwHcG9VcB/aKwn2rNPKoTJfSFwKN+BWKKEMyfBBPxwKUBxmLAF/budT1tHAgDsAIBAoGk2TbfSLZ8toHc/w1utn265IB1sCQsk7x/66cQNJZHM7Lt75vzy9Qg75idDSwVwaupMbUEc/iSXKabNmeWtrCUBG+oxdQSPMKT7EJtiC2zNYeV4gIF9XhaghKelJdpqJ/eFB2sGCRoGHmAuWhaggn8OMgLVSFuGQs8BUjScW9sxNMSLOFFIS80BS1uGAs7BQg68bwUOGT7JHkRxwMQS0uwgtrhKF6SZJ8dEGwToICNBzbAbgVzkvxHQFq2Lx1/c1wTS0twD5Wmertj56UtU/UCMPwUMN+xIe6hEPQlXmkjkro6c2AZR0vwgH5lTZ9UdSKaNNRrj/R+sEGe5zDFfeVUxVHktaReWQwtQT5sWSfrXBwLX5ULDmPzZ8bCTgGZhzn1kO1zTloigpag23fg+T47ePi2mcME4HsK4ORKkqnj+OXg1MO9PZJccecJQO/BYQIIRRZjtwRro2VdeJnrBKB3s8B/4urFJmO3BNs4ilHUwcySDXcfXQnmVTryNSD1WQ4PX466Z2rutwh0dFli3JZgPn4WajUFLJmL+/gmAOrGbQkeozkTqITeT8bcp4BYKnB/SJuC5JV9+nt7xy6AeUcgri3Zo7YEE/SiS6uhdctcreILgGbMy1FpXAQIj0NndsNcbeNaBP6nHbElWEW0MZU66GyZu3VsOQAlI36ZfSRbUn7bQ2POPHiObRVA9YgtwUNMU2EBjTvmw0Nse/Kr8TISHseOlD+Efh+IF8sF1AT51rUNgFJ0dJbTdwn2m9NZnSgBNG0X4Lvo7Jgf99AoO05EFX/VJa9E9qrBq8zxLysSRSY+Qjk4tbwUJoVjbB7xqsleieRVx19VRCS70qEIHHB/qHtWVhd4q6zok3asRUltdyWsSrxV1P7TPEC/BHS3hZ6vAcnxQVFZ/SwtBdQCFqFeFa7NihoOtsyffzBYWtkubfURkEOBAoJCRx9Uju0Cxy3zK+bR0xyDHcgCN7q6cijkFEwOBU4flM6rlAOGm98xn35iOLJQmqX2UDhSMEebP1O4V03g4BfzarnBUBmZ6wx/3BQKkgKRUDgYHtyRuQyDbW6YX08YKiFzjeH/cVR/YCAJFI6GBzcuH2jukfn2gIG4h1OsMZhew9emSygIw1iGJGMcQz0w725mGMbhCnCiz8bC12QrnOhzT8DDuhgDLZbMv0cMkpG5xHQaqaGypyD2UOGmJ29C5jLoaLeBjF4MSEIEgITKgYI4QEWGCIAEg/xgQSwXGICHCABKNZ8ZAIdKSiECgGOQHQvjFgOQlwCodClW+JaggEpjnDAkZAFD3LJQNrCWkYUacKiyBG4JpjYxp00CAyYBKxbM0wq2ErKBHo3lxbEm72rLv7PRxHKwJGD1xMJ5hC1OevqA7yyHoyXvWsuQyzVTYrAk4CcL6QGWvJxmhXZNHv4akEKpoo8KLwkqFNxXAOHLQRnZaUwbfFDLybPcOuJy3cUsSBKw2LGwHmewkZCdqjD80UooHcmzI5RKw2AuKrKTwMpiy0K7hw1OljrDk6aFmiSvJAYkHY0mmQmQBPzDgrv5BxbIWmf22I2949Tj+UR8oTNk4eH+YdjYLJnCCAXBjOxVpVFC3+rmZK/KYauOVru/1W8S8Mwu4RbGEhoiKU8RxKlP1WrSco8qKKRtRX14dhr+gT8GzN2yy3iAKU7D1PssK7M2l6RStemFWoJ79EpFRSoyb7Myy/Y1DcNhbMMuZLeBIQpMivQiLcFD//BLCgymNjt2KbuFaQoQXt2mwVuCvG/urym8DIaemNIYaYCgi8ibwB8ucEaT00VkkSUANmlASxdSvRxCloNTfHR4qehCssgSAJtt4g314UmGgpNHXKShWoL1pwu/329eIEs49SnjqQC8tZzBAO8b/N/SOmg60JInbdALf53it54gqGBi8cwubTuDXnZ28E9eyLNaNKeh8n8FaPY1efaCk3NB0MLA7JFd3hYGRM/gB1wnyFqUXluCOX4rRS3JuyNOzgWBgIl7NoZfMNDK0+CfQ0HIThyAo7cxOohOUhA4ORMEPIOJBzaONUw0Yp+NUSqq8laSB7LNKwoGvbK9aGBkfsPG8byGQhy1wtjB3fqZjWW3gKXvAPAfAE9sPNsZrETweNXINHA027Ix3cJNRl9cBjuRLABOfsHYdwA4BUCc429xy+h3AAQIgDUb3dIwAr4DIEAA/Fiy8d2sYCyCR41HRsDBPIbxZ+xpDVMRPGI9MgmGWz+xOOxm0PgOgAABsIhl/Bl7XEHpOwACBMD8kcXjaQGF7wAIEQAxjT9jdzAy/qv2YtNhoFsWl0eYiOCVY5Hh6DOt8VdEwHcABAiAnyw+twuc8x0A/gNgEeP4D2sMcVKQdBWkawBEswMowBxQUa+uRHsFIVC1KDvFP+OzKc7/Q+cA6pOUeJWKiYeAFKnmzmB8NNnzf9AcQOedXraVTrpbsE97Xn92AkuL+PJ/lzng/FlTXMumMbxRCGkQABOe/wetBukTKa5nocDxnpDaQzC59b9bBHT0HhcRvJLXmxofCU7vdfjjasafsbsFzJX0Fs+uq12Q4KTnoTclPphQ/d9Lb1DQ/7qs54jJEjgn6xRHqKymMf6M7eY4MY2Arry+XWMZzjoVBlp8MJH+v87TBuaKPed8fxr+K7p3BL3KPef1voSFzXTGn7HlGra+VgDYW8Wx/8/9eaLmJr8O5PBnfcOm5eYXXE1+00gHb+6nNv6vbuFo8uvABL78YlO0ncOLliYqgx+rLZum5xl8aEhF0ogkqTTwYjal9P+95Qo+kEKLtM0ljUDmbaqeneBgsun/e8sHeCCpT1Xit6aiC6sa7SPgJXz4NcH0z3cqyKlHPl6e0OKvPMgqMJ7bv13dzeAq1w4CQJclDZLUHM4WU6n+h00E9nQOLxRBElqOk75n3u7har5j1+DmB9xkBovshsLRJ/hJkFXgZuKX/5PbOVyUJr+upAuSJjFawsl8Cps/TD3P4UI1/Y/yqIk9TnovA3Ayu2PXxK05VBnUWEtSemlFktectHidJ6J9IaUSJ32XgQqGrnz6/+t2hcFyeks2PVGikJjmirniQM3YNnLAIuALTP9/7VYwoc0C6wJnCZO+XEEahUkPUuCsovaUAsyf2VX6haFyg8VVYdSXFaQkjLrQBXrsvfSC/7m66f+vxzUG6hTTv3b/eFXghOu2cOjf81yjVyOdx3891d5f2FxQ1PQqKVSH6MZfXzBoYBIBAv2KRBKRFBhqPeXej8Pdg3plVkCNzpKFKqNU5W2FpLOg1mSwN5U7v9wtNwilM+rKF+bX9kaRUQSxuo7ar8Z2gRCMX+IvzJP7RlHi9e4rnP6BJwFpNlrcvH2b0ScSgay/xOkfdBLIzfK1hs4yfAFtjgCiv+/ft+eHBfxrDPP13KJ9LxRx4s/i4Qud/n/czeFfZXayFjbVnU5bBnY3u4aNH7Zu7uHd3jBdFzaL+07TCHT3cLWlP7XdBp6VhgU7cJsNfMoSv7vVlVb+TWzX8Kt7VwDs15hf2d+XBBN4deWVX5PrwAI+FZXR+H/KA3OH/9XB9Hd9u1v+gE9FR791heY4ekd3ND/9rz5tvlzur30Drbss+bedu01OGATCADywGEIghBDd0U4/ddr7H7HO9B/TmppEEmCfK+wK78rq+fx1wTGnIAGOeHk9Hj8vuCiZ19bXDB1gfMcgAcbGy/rm5zYmFMb2HrwXxqVE8Zf/jTQYx+U5WDKJJs0/fAhk0AJvTx/XXH/C6GzmSx9TVRZL4Cj6l9wCVP6xFthhxsp79EshC/yN7v5VsIFjfjgl//9jRmJegOb+O/UN5kOVuPAxW5tLHqTkNxUT6d8EMNDZP8fBY8o8PfjNxgbANMFAY98yepvgXEgf/iWxLq2hQBm6+X+kvTMwjdR09D9GlUAPSE1D3yNVesuTIVX/V4WcA2qg6sfCjN/WXLBrKPXF1uutHARga6r+KljnANfFXUeRf1WVWa0JeCMK/l3nllSdlRiXtIYi36awevCAMfBG052/UUEXUO2LxHphG1i89FZQ7VPCDkZ7yXEuLv1e9FT6VLG2FnunJL+77o3Tom6p8tmo2roTeu+8UnAVFhwApPJOa2HqnkZ7UohvgG87pEol7PoAAAAASUVORK5CYII=", + "lastBackup": null, + "currentDependencies": {}, + "actions": { + "config": { + "name": "Configure", + "description": "Customize Vaultwarden", + "warning": null, + "visibility": "enabled", + "allowedStatuses": "any", + "hasInput": true, + "group": null + }, + "properties": { + "name": "Properties", + "description": "Runtime information, credentials, and other values of interest", + "warning": null, + "visibility": "enabled", + "allowedStatuses": "any", + "hasInput": false, + "group": null + } + }, + "requestedActions": {}, + "serviceInterfaces": { + "main-8080": { + "id": "main-8080", + "name": "Web Interface/Bitwarden Protocol", + "description": "Main user interface for interacting with Vaultwarden in a web browser. Also serves the bitwarden protocol.", + "hasPrimary": false, + "masked": false, + "addressInfo": { + "username": null, + "hostId": "main", + "internalPort": 8080, + "scheme": "http", + "sslScheme": "https", + "suffix": "" + }, + "type": "ui" + } + }, + "hosts": { + "main": { + "kind": "multi", + "bindings": { + "8080": { + "enabled": false, + "options": { + "preferredExternalPort": 80, + "addSsl": { + "preferredExternalPort": 443, + "alpn": { + "specified": [ + "http/1.1" + ] + } + }, + "secure": null + }, + "lan": { + "assignedPort": null, + "assignedSslPort": 49152 + } + }, + "3443": { + "enabled": false, + "options": { + "preferredExternalPort": 443, + "addSsl": null, + "secure": null + }, + "lan": { + "assignedPort": null, + "assignedSslPort": null + } + } + }, + "addresses": [ + { + "kind": "onion", + "address": "mibog33n4dzldkve2uqm2muqkhrbnibkpu22rms6qrrhylwssuv7h2ad" + } + ], + "hostnameInfo": {} + } + }, + "storeExposedDependents": [] + }, + "bitcoind": { + "stateInfo": { + "state": "installed", + "manifest": { + "id": "bitcoind", + "title": "Bitcoin Core", + "version": "27.1.0:0", + "satisfies": [], + "releaseNotes": "* Update Bitcoin to [v27.1](https://github.com/bitcoin/bitcoin/releases/tag/v27.1)\n* Add 'Reindex Chainstate' Action\n* Improve config descriptions and instructions\n* Notice! If Bitcoin gets stuck in \"Stopping\" status after the update, the solution is to restart your server. System -> Restart.\n", + "canMigrateTo": "!", + "canMigrateFrom": "*", + "license": "MIT", + "wrapperRepo": "https://github.com/Start9Labs/bitcoind-startos", + "upstreamRepo": "https://github.com/bitcoin/bitcoin", + "supportSite": "https://github.com/bitcoin/bitcoin/issues", + "marketingSite": "https://bitcoincore.org/", + "donationUrl": null, + "description": { + "short": "A Bitcoin Full Node by Bitcoin Core", + "long": "Bitcoin is an innovative payment network and a new kind of money. Bitcoin uses peer-to-peer technology to operate with no central authority or banks; managing transactions and the issuing of bitcoins is carried out collectively by the network. Bitcoin is open-source; its design is public, nobody owns or controls Bitcoin and everyone can take part. Through many of its unique properties, Bitcoin allows exciting uses that could not be covered by any previous payment system." + }, + "images": { + "compat": { + "source": "packed", + "arch": [ + "aarch64", + "x86_64" + ], + "emulateMissingAs": null + }, + "main": { + "source": "packed", + "arch": [ + "aarch64", + "x86_64" + ], + "emulateMissingAs": null + } + }, + "assets": [ + "compat" + ], + "volumes": [ + "main" + ], + "alerts": { + "install": null, + "uninstall": "Uninstalling Bitcoin Core will result in permanent loss of data. Without a backup, any funds stored on your node's default hot wallet will be lost forever. If you are unsure, we recommend making a backup, just to be safe.", + "restore": "Restoring Bitcoin Core will overwrite its current data. You will lose any transactions recorded in watch-only wallets, and any funds you have received to the hot wallet, since the last backup.", + "start": null, + "stop": null + }, + "dependencies": {}, + "hardwareRequirements": { + "device": [], + "ram": null, + "arch": null + }, + "gitHash": "c995ed1b85f79135fde30a0c056fdb4ee465b50d\n", + "osVersion": "0.3.4.4" + } + }, + "dataVersion": null, + "status": { + "main": "error", + "debug": "Error { source: \n 0: \u001b[91minvalid type: map, expected a sequence at line 1 column 1985\u001b[0m\n\nLocation:\n \u001b[35m/home/rust/src/core/models/src/errors.rs\u001b[0m:\u001b[35m509\u001b[0m\n\n ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ SPANTRACE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n 0: \u001b[91mstartos::s9pk::v2\u001b[0m\u001b[91m::\u001b[0m\u001b[91mdeserialize\u001b[0m\n at \u001b[35mstartos/src/s9pk/v2/mod.rs\u001b[0m:\u001b[35m265\u001b[0m\n 1: \u001b[91mstartos::service\u001b[0m\u001b[91m::\u001b[0m\u001b[91mload\u001b[0m\n at \u001b[35mstartos/src/service/mod.rs\u001b[0m:\u001b[35m271\u001b[0m\n 2: \u001b[91mstartos::service::service_map\u001b[0m\u001b[91m::\u001b[0m\u001b[91mload\u001b[0m\n at \u001b[35mstartos/src/service/service_map.rs\u001b[0m:\u001b[35m80\u001b[0m\n\nBacktrace omitted. Run with RUST_BACKTRACE=1 environment variable to display it.\nRun with RUST_BACKTRACE=full to include source snippets., kind: Deserialization, revision: None }", + "message": "Deserialization Error: invalid type: map, expected a sequence at line 1 column 1985", + "onRebuild": "start" + }, + "registry": null, + "developerKey": "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAIwXjctXTc37QTXRYWxLxElY1r2NhoKJRrl604Nu/0l4=\n-----END PUBLIC KEY-----\n", + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAMAAADDpiTIAAAB0VBMVEUAAAD4kxr3kxopFxX4lBpCKQk+KAgzIgsgHBxDKgjzkRrghhhgQAsnJyckHRH3kxn4lBvchRdOMQuBTg5wRA33kxs7OzuQVxB9TRHxjxnPfBbzkRp/TQ8rHQ3qjBncgxidXxGaXBHkiBjQfRZrRAxfOwxJLgo1IQr3kxrujhrsjRrmiRm8cRR9TQ/ujxrQfBbAcxXAdRS2bRSRWg9uRA1jPAvniRm3bRO8cRSUWBCaXRFfOws6JAn2kxrliRizbBPchBe9cRS7cBSvbRKNVQ/OfxWVWBGSXw/EdhWSWBFwRQ3ZhBd8Sw3pixnZhhawaRS/gxGaZw/3kxr////4lBr//v7//vz//Pj4nC34njH3lR7/+fL/+/X6uGj//Pr4ozv+9+35qUj/+/f4pD781qj4pkH81KP7zZT3liH3lh/5p0X4mSb+9er96c//+vP93rn++PD7y5H4min3lyL+69T83LT6umz6tWL5r1T+9uv+7dj7yo76wHr80qD8z5n7yIv6t2X3lyP+8uL+8N/7x4f6tF/5slr+9Oj+69X96tH82Kz4oTj95sn82a/7w3/5q0z+8+b827H6vXP4oDX+79z948T958z94b75rVD7xYT+9+/5HOTYAAAAUnRSTlMA/PYL/SUeFgki68wzBg/y+sAsY0v4BGlP6bHwWxLfxH5607ZBOTIZ9ObZ2JJV4b2hnY1kR0Xkmpl+bT4c8M+SyLGjhXeodFqob1K7cOq2jIRnsm3jFQAAGitJREFUeNrs3VtPE0EUB/CzbSmlhRYLgqIoKnIREEXr/Y4KeE3OjtYHo8FbovHyYNDEF2NiYmJijL75bW0RQi3t0m67u3Nm/r+v0Onuf8+cOUMWiXeO7bg1fTkzdTsXc5RSvE6V9MbOn5jae2W+bzQ/3ENgjnjHzNzsiZjipqjc1OWrhfEBArGGj89dmFDcokR69upYnECSZN+BXYrbKnHiSv8wge56zp6cVBwYZ2qkg0BTYyfTHAa1Z6SLQCvZvv0JDtX22f4UgQ46901yNNT+PqTDaMUHD3O01P4ZVA0icnavYi04Q3mCcMVHdrFWJgfxIAhNctFhDfUe7SQIXH6bJg/+WtQBlAkC1bGXdadmsQYCcu6Axv/9SmponKDNUtNavvfrcS6iTNROC5pl/kbkdhO0RfISC5XBnkHrlrazYM4+ghZ06p/6t5RJEvjTn2MjxJAG/JgT8tHXkJNoLmxOdhsbJoM6ceO69rCB0mMEjegW+NHfmNhxgq0UYmwwB3nQ245eNlziDIG9P3+ZwhKorSC65teMRB9BtW6j3/3VnB0ElZJptkysm2Bd/BBbKI22kTVDbKkL6Bop2ccWO0q2Oyiq06v9lN2VobiRRf/m5CzuFzjKULKN7DSaYPjnGNknhad/hV3WdQuMMPznCNlkfIKhimNRafAIg8VhsMuKTV8/1ChZ4BpDXRkyXRJ/f0/qIBntFMMWbpK5soYc9QmWY2xteJChIXNkJCu7PvxJGzhyLG/SUb/gGXeEZJqhKUNkkoGdDE2aMGgOcZ7B5tfAPIMvi2QEpH/fdpJ8w5Z3fbZGiZ8z1s/QAvHdYqj9t0j49yBe/20wSVKlrDrwGxwnSyJ1MLSJyHbBGYa2GSRxUPxvI4Fd48YNeoyWuG7BwwxtJasqOIBzHwHYLqZLJI7qbyASQu6vH2cIiIidAWz+V7GsIDDKEKACae4GQ6AWSGvHGGqwpii4xBC466Qtq0f+hec0aeo0Qy22rAD8/vXYsQLw+4dIwwtJrzOEaIk0g6PfjTG1W3iBIWQ3SCMFhtBpNFKsmyECedJEF0MkzpEWsgwR0WKEQA+mvkfG0eFWemuue9TRBEUOw18idZgilmGIUOQjxjH4PXLT1CQUgJm/v3jMxpih5qAAxFx0XfetMYugg5qAAkCZW2bOIkhRNMQeAFp2K7x99pSFi1EkJlmqFbfKQ+GL4BA1AXd+c9EtMWoRnKLG4ATAKreeh8+es0z91BDsAJYtu17+sEidFC7J0/9XXC8PWCSHGoAdgFVF1wsLFWoQXGTJXC/fWKp5Cs1xluyV6+Uri5WnkKRYtF8mRoBVAxQO4SOgfEWAL27x1yvW3E6qBxWgDf4iwG+3rLiyzDqbppoQADb4jQCf3BL9F0GeAtfDwvmLAPfcEv0XgaJaUAHY4DsCbFJ895P1c4gCdpelc7285to+uDU90m8RDFKgkiyddwT4zLWsRQAZiyBLm6AHZIPvCODhPuskRwG6w+L5jABe3rBWTlFgDrJ8PiOAl4+slyRVwh5wBf8RwMtL1ksvBeQSy/fD9AhQdo3+gzHQFZ4YHwHKumgVXgDVrIgAvOklgGug1tgRAcqO0DocA6sQSAS4xzoapxKUgKr4jADvpUWAv+zdd28TQRAF8KUX0bvoHQECBKKJjoQQgr94L3ZsxwTTS4BAaDEBQhIg9I4on5YzneCcb/fO3Mya30dIVr63s7Oz+GNyxP974D81SgSoWGgSNQpeCI8AXajukboIACR9Y3QOxGi/5/onb6AIEJhvAj7eAyOZeXzvLOzVJQI8hlRLTXIgRwcDbovAMQIcYZh7kGq4ScwhyPGCAcdFcKqBIkBgvZddIL38U+bxkYiLoLEiQMUw/xIgwCoy16IsggaLAEgsB66BIB0MuC4ChimjGr0RoGKZf4dALxgIWQRXMRjXCHCNYc5CsiEmAVsgSS8DjovgCcPkUY3mCBBY5N1FEEaReVRlEThGgLMMcw3C+TYMuINRXb77FAPUIQIcgXCzTUwrIMpt2mg5eR6/hEeAK6hGdwQA4m8Fx0KUXtpqff/wHAINGQECq/xqA6GTTN+LHFBswAiAuE3iQyFKG91dbsQIEBhrYpgFWW4zBqcI8Fh5BAiM86gPrI8xNGQEQKxR0nMhDOvE4wgQ2GRcSXsQro31UkJ19zg4HREgMN04OgxhpEWAq9Bhlic/AHWMANVfDvEiAgQmefIDgAzrqPnDwwIGOMcwj6DFLD9+ANpYb5lbtzvwkycRIDDJiy0AbvOfKP06RrroRQQIbPKgBuAQAdwVn5wHfIkAcKoFbII4Gf5Tze0fPYkAgXHaTwECbZTlBhSZYyxNgThvKIuiCBAYo38i7DuKoikCBObrvw2coSi3oMsExZ2A37y5JWoJqIoAgcnGwgzIVOj80EwheqCM3rsAA5w63cL0KYsAgQ06r4NXl79Soq3GjgBAk9LbgIPKn7nMFL16CGWmKS4CDeZGL1N08Sg0mWgi2gFNbhaZnuxpFX2h341SvAcMc/44U1TuhBYLfImAf7nLNGXuFKCDiWQ/9DnGdN3KQ4NtJopJUOgEU9byEfJNVzcSKrojTFurguLwSI/fBRFwWJh9A+H2eBkBv+mhAFnpvwIae0Gj6qMErbJ3hXN1DQW08pEyXJa8I5hjahgNvSjFM8F1gdEePw6dpRi3IdVudbcBouunHJc7INMQfb2AkV2kJF2QaYcJMxuKvacoJZl940v0zAW2I+0XIPAAAjWZEGOgWSulaYdAI8zglkAz2iu2sK5KAjeEC3z9ArykvftA/lNfhnWTzUEcX78A7bSXw1eFzvbjrJPzkGaKn3sApwiA37w9U2Y9iOsenuznFwC0148Bct1lulA1SqbJyyqQYwSo4umTZiZJ3sNCI011W6GZWwSornDjFZMk7Ij4gKluOjRrpj2E6HzH5DyFJENUvA5kxzEChHv4ilHpGicyzFQzFZq5RoBwhe4sE3Eckiwy1ayEZjEiQLgTfUzCMwgyx6tu0IqYESDc1XZGoGozqGQumA3au4CoCicZl6x3xrd7VwY8RnvdiK7Qzrh6IccCz5rBgOu0l4ONtl7WoKgm3KRnLlQkjhHAUmeGsWQhxzAz0EGoRnsXYO0ZQylqE5xpBtoFzdwigL0HjAVirPXsJNAtAjhoa2UM3RDDpxtBcIwAbl4xEunDBed5cyc04BgBHF1jJMKPBRf9jwBw9YjOLkCKtf8jAJz105mcLmGvjoLdIoC7LF3JmSEywfxuI1SjvQuIIU9XZUgx1aMbIS4RoAtxXGEt4ksBuzzqBntNeznE0syahDeHDf/fCxDHMTo6Ayk8mA34A+2VEVORtUg/FF5uflkEzc7TXhdiesAwGoqBW80vq6GZSwTIIy6G0ZACx0p+KNxCKhEAkeqBwhvEvcmAtFdGTOHfABXbAIw3P4yAZi4R4Apiu8owGs6DlnmSAZ/TXh7xMYSKYvAW88NiaHac9pCALJ3chxQrPWkIpr0yEtDCQemoBDX5kQFTigBAv/YFAPPdBGiWUgSI0hsmvTV4h/lmGjRLKwLgM528gBhTvZgMQnslJKGZNYifF7PEfDMfip2ivStIQoZOjkGMnT4UglOLAKAbQZMjm3zYBKQWAfIMo6EtFDBfDYNmtFdCEroZQsNpIH7cDlkOxVwiwBkkoZ+1iL8ijI2mYh8Ue8LqxEaAVxBkg6lYB8WKtIckvKSbkxBkl6kYC8Vor4Qk9HFQSk6DAxPV7wJTiwDnODglDUGBJvW7wNQiwHWG0LIJANQPB7qTyaTyLzjHUBquB381WvuQeNorIQG3GELJWWDFGGPMduiVVgR4wFA6CsEVs5SXAU7SXh6x9bAGLRHgayFgL/RKqQrQSlfXIMtk5beCaK+lgLiKdPYRsmw2xkyEWifoorX9GGLoaWUtar4AGKp7OtBJurp05y3cdLI2NV8ANOmuAxUZR6krB2vPGMdRSKN7ATC28pmnsHCFkag4Cv5G9XywE0xE84eHPYig5wmj0dAQ/MNoMw9qnWRyWj4cySFER1eRrsRGwMAozTeDi0xY5vKz7s5cAX9q+3inn0n4Qt59NSkRBVEAbnMqc7bMWoYylT7og2UOVVr6cg6D6w6CCpjQNccy55zzr5XFiLLA3Lmz043fL6B2G+bcMN1HoM8iWQizmJhgX3jw0d3XV8N9AX1R+QOAaYanBRZpy1kotEe2waoSTVG4BKhaLlthVQ9N0bYL/N0WGQ+raIq6TcDvRtntDmIrAuhpD1hvmayFUUdoSRk67ZUNMMpUBFDUFqTeWBkIo2jIKWg1UMbBpgLtUHYV+E8DzF4HMBQBzkCvjNkCsBMBDkIxuwVAK95DM7MFYCYCXIRqGasXgqxEgANQzmoB2IgAYQXaWS0AWqCnL3RfzBaAhQjw5DgMMFoA+iPAXWWvgTZmtgBC6nbqHIwwWgDULH9fUzPIpqwWQIHR3bhz6VSWicvfMPPlr7JaAC4R4Bl6HSqFTM6py4a++1VmdwJDRodful7eC5iIQM9EqM4uAEYXos7xB8+zTMA+Rd3gO7cAnCIA/tF95UOW3t29A0MyJieG3WB0BTTUfflxwIjM3v9qYLLJK2HOEaCxc2d76NXh/bBiickOMYwuRHMP7jGCzvkR2CDTYc4zRncDLR16Qn8OGlkPrrXYJMw1ArT26hrj0jgcqon5MgrmeI4A9S6F9OQWDBhvsU8kowvRvsob+vEB+m2V5bDGJQIcQSQHDtOHu1Bvm+yBNW4RIKLiI7bB9I3wmokyDdY4RYDout4zvhDKLTQ4NK7f/g9d99iK+d+AIbIYxrhFADeFHrZg/L0QzLI3N9QtArg6wBaMvxky2l6r2DOMDjF8YEyXoJjBXsGMrgdxnAjoROuYmDr22sW7RwB3jxnLPqiVEZHJMMUtAsT0krG8gFZjRax1iXKKALGVGYva+wHLRGQOTGF0PYivkmUTZveDtojIGljiFgE86M4zhsvQabuIrIAlNxldET50Z9k3m42CgfUixgYGOEUAPypswmijiGEixrYCGV0PPCnSXR4qTbE2Pv4doyvBl/t0V4RGIsZ2gtwigDev6ewaFBosvZbADqcI4M9xutI5MGak9NoIOxhdDh4dZUuWVoKrpNcmmOEWAXwK6Ooe9NkuvSbBjJQjANqZHWrpGbBIeg2DGWfS/7uzJUOnwoNEbK0DGV0Oft1jRJoHx4rYWgemHwGAh3T1GNoMlho7U2PSjwBVbMXOZuBa+W4VjFAQAYAsazR8lLi2So2d6bGMLgff3EOAujfGp8l3Q2HDK0ZXgm8lNmdoGTBGRNMy4BxaCBldEb5dZytmOgaIqFoG9DC8uR99O0AH8O4yXd2GLgPkp6VQYD9rTn45h4bu0EEO3j2kq+vQZZn8tA4KXOMv79/eQT3XO3kleHebLZiZHzFXflqP9HWzTvD4Ul0RFAO6KMO7l2zBTM+YIfLTcKTvCP8RvH/ZhZrie7qBf0/ZhKlfABFRtAxgH4JcmKerHPy7x2YMZYCM/DYSabvEJJTgX5bNmbkSMlt+W4207WMSyvCPTRnaB5grv6TfJ6bARACaPqmyNwRHyG9TkLK7TEIO/pXoTNkYOanSshd4nol4Cv/ydKTtNHCc/Gk+UnWRiSjDu3N0FkCVVfKnqUgVkwH/TtORunfEJ8mfZiFN15mIHPyju09QZbSIaNkKyjIRT+HdUbrTNVEsIzUqDgQPMRll+NZNZ9rug8yXenORnpNMBrw7pevjxDFR6g1DaipMxmH49pDO1DWLGySiJQR8YCL8R4AK4zgNTTLyt5VICxNyAp7lGccraDJf/rYLKbnFpORPH4JHhxmDtgiwQv42BinJMkm5UgFeVPKM5TBUGS29NBwHXGHivh7dn/7HvAFNBsi/NiMVIfvFyVtdiOE549F2FjxD/rUeaehi/zl4swAn1xmTupOgCVKlYiF4iv0r/+FyBdG8zDIudTMEpZEN6H/dTEN48UEF7Sl8pAfa2gSOlBoFu8E3mZr8taOvKmjmzoFrrOm4J8BUqVKxEAyYsiB8fOTtoa5jqFMpX/90hk4sbANiuDQ0GP3tMhUJgmw2nw0CeqftJHCcNLYD/S3H/4Oy7jCrpbER6Gfv+J9Q1iBsmNRo2Awsl/6LHwGokpG+zEEaih1fBM+hygLpywSko9OL4BxUGSI1ajYDfyqWetiRTkKVjPyg50Dot+KRDiwCXbuAGC+i8BnwS+cVwRnoMkRE6TPgD4UjITtFGapkpCGFXWMLNzqiCJQlAMyQhpQ2DX1mvwh03QQBFssPWs4DWiqYzgTK9gAwQBrS1TLwX+UX+2iTtg7Rm6QJ3XNEX33K0xxlncGA4dLCWCjW/fBjlpYchDIbpE9Whgccu3Qt9WskbatAmZlSY2EroG8KLhJZfQBAWhsF9c7TBn3zgkfJH7RcC4nuEk1Qdg+o1whpwzho95gmKDsFrhog7dgJ7WxEgM9QZ55U2Y+BNiKAvgBYHwE13wpo4QANOAt9Rkl7FkO3C2zmLjW4CYWGSpuWQLWATWSBrpupHyFq/P5joLRrNzQ7xmY+oqb8Zh/Toq0n5Df27r03hiiM4/hvW/S2LqVKUZdQtyCuCY2QEPcEeWapSwX9g6IoWiqVEtFSKSGlwqvVuHTT7uzsnNm5PM85z+ct7GT2O2fOeea/NSjB54CAgeAEGKUZQxOXvQyw+zLEfwjvKDE2YPD69drow9SfGbvYvQD4aw/+kP8kWCEBSvTeGEjvImA3CqKoFaWYnREKoXIC+Op97KVkjJhqQhlsZgWE9KZCAvi75aViitiqg5G1xNV4pB1YXhq6bxJbjTAzn7gySICiq17yLo8SY5thaDXxdC/SLfiul7QuZp+FnKMGpjqIJ54J8JbZ8Z8SLTC2nFh66AW5R/68INWOBeoa5rb3u0QO5lqIpQQS4CPRzXfjXV4kj4aZrvvMsgwR5Iih4AR4SP7uhjq9ee/+z4nrJneDnkFeHwEoax6i2EkMvfCC+IdYpQSg2R7c/vz4bU/whXDp1uPn/HZ8ldUJ2HILSCABuqmMpzfHXo0MTn3r63/U3dPT0329/8uHH3deDU32kiwFwJpbwOUkEsB2nfAhc39wxASQNMAhbjMFYMWDQPwJwG2IXwKWIbIaYib2BGD3MZ/45TBD/nJgAgnwiSy3ElVoJFauRUqAJ04nQA3KkndQcFQTwFgeVdlOnExpAphqRAnBW4MCE+AS+XE9AQ6jShuJD00AY0fgS+gG4eAEeEN+HE+Aephg8zExX5oA5vZgFunvhDQBDBVgjM03ZX0EJ8A4+QtOgPtkszWIxTbiYSxSArx0NwEW4x9LHgUnvCC95MfpBFiAmOwmFjQBzDSjAmHHxTUBDCE++4mB4AS4QX5cToB9iNEuyp4mgJHViFM9ZS+BBPhK9qpDrI5T1oITYID8OJwAu+FL8O6wIU0AAznE7TBlbnKkP94E6CJr5RG7E8TB9EWgCVBZM+aw6qXQ5MivsAkw7GYCFBCK5KEhk3dvaQKUtQmJWEW8XC1eBM/Ij6sJ0IQZlv4JFE1fBJoAcxQQwKZN4sWL4Dv5cTUBOpCYPSSLkwlwDnNYtRxkws0EyCFJ7STJFS/IIFmpAYnqJEGGJQ51r9JRGLNlhmypPvcSoBFlWLY7KJzhPucSYCESlydJrrzucykBWpCCgyTMlXfvHUmAVUhFG8kzfRHYnwA1SEcryTR9EdidALUoz+EMmOXpzy/WJsB+pGYvSTZ9EdiYAKdRkV3bxKsiaNBvSG0Iweo3w24rIF11pFhpQMpWkmJkH8JxeG+A1VYhFA1BS8USgNZ8Vso9OWSjlhQLi5CRpaQYyCMzp0hlbgUytINUxnYjU+tIZaoJkdk1RNBRbcicsKMCdlmO7LXOI5WRwkIwwGWQqIPawcICUploABOCt4hJlgcbB0ilrgWM6JJg6k6BlRWkUtUJZk6SStFJsHOIVGoOgaGLpPy58fvrFVCOK78/h5HiTtgAtjaQ8mF9/xWdIZWwfWBNV4QSdhbMtZBK0Caw10EqMUshAKux8nY5DBHaBU2SkyRXCyEW6qGxBGxthRwSB4kxtwuiNJGKVTOEOUYqRjsgji4KxmgNBNIFgdjMh0jtOkosFsvrIZU+DMRgOwQ7T6pKByGa7ha2afd/FPN1XbgKOSan/6rRqiHg5t8/tw/PC3QBltBNItIPf1arVseIGGuT9PJPnwf/cnvxX/8G4lMQsffLTH0jqVCsqX+dKhnRCliqQd8OhbB1Eex1jlQg8Wv/lXToynCgJWwmf82iuwVTcgIO2KQ3gTKWCN35oyPG45D54Pc05XW+cImaLXCJviGcYz0cU7eY1Iy1cvd96m6x6s0TcOo/Ec2kfrd3fz0Jw0AAwLvBGKJz4AQWQZibgIiAgEIi4gR58EFfmn7/zyIxMTHGqIv70+vd72nv7dpr73bDFfx9VaB9gI/AfPSdiCbySwGtw7C75ohJ3PIvPUWfI3XCyLt7lLUilyqnfaPqoKsaLRUY+WyIqlhEV6jkOzYzNAeC6i0j37lDMQU0lxG8U6BMw/8zR+lYQKfF/3eusm0mGxT6/c2BkvcCLfXrPePTU650tELXPtHUJlwdYspIdE1Frgdt8H1+MlNQYCdo4yr2jJ0H+lhYle4XvwAZYJeBR0r4xMQBWDrWANngWVrFENRWoIUY67wT1guAJApEAOTnTvAYAArJ2wq295GJIfM6ICo0+ikwJ1LGA9ozBf2pseqS5YsaHu7vO7JwFEiyEIj2kpFMWENf8GyN6vTqZyvnZDYJ+mcmIzKwjsdlnqq8P6MEv2T2vJbgaSgtuoxIyvAGGk+M6C86FiOyO3Q3rTyPlVgFDh3zYcl1t+PSv+eBsB/CG4r1AKuZy+16YAseidDnlenQoJyeSqxT49x52oz9+eqiLHb4h92zptuvg/311YvbNTEN+xv+iIU0EItw3wAAAABJRU5ErkJggg==", + "lastBackup": null, + "currentDependencies": {}, + "actions": { + "delete-coinstatsindex": { + "name": "Delete Coinstats Index", + "description": "Deletes the Coinstats Index (coinstatsindex) in case it gets corrupted.", + "warning": "The Coinstats Index will be rebuilt once Bitcoin Core is started again, unless you deactivate it in the config settings. Please don't do this unless instructed to by Start9 support staff.", + "visibility": "enabled", + "allowedStatuses": "only-stopped", + "hasInput": true, + "group": null + }, + "delete-peers": { + "name": "Delete Peer List", + "description": "Deletes the Peer List (peers.dat) in case it gets corrupted.", + "warning": null, + "visibility": "enabled", + "allowedStatuses": "only-stopped", + "hasInput": true, + "group": null + }, + "delete-txindex": { + "name": "Delete Transaction Index", + "description": "Deletes the Transaction Index (txindex) in case it gets corrupted.", + "warning": "The Transaction Index will be rebuilt once Bitcoin Core is started again, unless you deactivate it in the config settings. Please don't do this unless instructed to by Start9 support staff.", + "visibility": "enabled", + "allowedStatuses": "only-stopped", + "hasInput": true, + "group": null + }, + "reindex": { + "name": "Reindex Blockchain", + "description": "Rebuilds the block and chainstate databases starting from genesis. If blocks already exist on disk, these are used rather than being redownloaded. For pruned nodes, this means downloading the entire blockchain over again.", + "warning": "Blocks not stored on disk will be redownloaded in order to rebuild the database. If your node is pruned, this action is equivalent to syncing the node from scratch, so this process could take weeks on low-end hardware.", + "visibility": "enabled", + "allowedStatuses": "any", + "hasInput": true, + "group": null + }, + "reindex-chainstate": { + "name": "Reindex Chainstate", + "description": "Rebuilds the chainstate database using existing block index data; as the block index is not rebuilt, 'reindex_chainstate' should be strictly faster than 'reindex'. This action should only be used in the case of chainstate corruption; if the blocks stored on disk are corrupted, the 'reindex' action will need to be run instead.", + "warning": "While faster than 'Reindex', 'Reindex Chainstate' can still take several days or more to complete. Pruned nodes do not allow 'reindex-chainstate'; if you are running a pruned node and suspect chainstate corruption the 'reindex' action (requiring redownloading the entire Blockchain) should be run instead.", + "visibility": "enabled", + "allowedStatuses": "any", + "hasInput": true, + "group": null + }, + "config": { + "name": "Configure", + "description": "Customize Bitcoin Core", + "warning": null, + "visibility": "enabled", + "allowedStatuses": "any", + "hasInput": true, + "group": null + }, + "properties": { + "name": "Properties", + "description": "Runtime information, credentials, and other values of interest", + "warning": null, + "visibility": "enabled", + "allowedStatuses": "any", + "hasInput": false, + "group": null + } + }, + "requestedActions": {}, + "serviceInterfaces": { + "peer-8333": { + "id": "peer-8333", + "name": "Peer Interface", + "description": "Listens for incoming connections from peers on the bitcoin network", + "hasPrimary": false, + "masked": false, + "addressInfo": { + "username": null, + "hostId": "peer", + "internalPort": 8333, + "scheme": null, + "sslScheme": null, + "suffix": "" + }, + "type": "api" + }, + "rpc-8332": { + "id": "rpc-8332", + "name": "RPC Interface", + "description": "Listens for JSON-RPC commands", + "hasPrimary": false, + "masked": false, + "addressInfo": { + "username": null, + "hostId": "rpc", + "internalPort": 8332, + "scheme": "http", + "sslScheme": "https", + "suffix": "" + }, + "type": "api" + }, + "zmq-28332": { + "id": "zmq-28332", + "name": "ZeroMQ Interface", + "description": "Listens for subscriptions to the ZeroMQ raw block and raw transaction event streams", + "hasPrimary": false, + "masked": false, + "addressInfo": { + "username": null, + "hostId": "zmq", + "internalPort": 28332, + "scheme": null, + "sslScheme": null, + "suffix": "" + }, + "type": "api" + } + }, + "hosts": { + "peer": { + "kind": "multi", + "bindings": { + "8333": { + "enabled": false, + "options": { + "preferredExternalPort": 8333, + "addSsl": null, + "secure": null + }, + "lan": { + "assignedPort": null, + "assignedSslPort": null + } + } + }, + "addresses": [ + { + "kind": "onion", + "address": "m27eb66v4tndzhowirshkysxt6rmt6iubmjxxc2l2leca7lphcbs7sid" + } + ], + "hostnameInfo": {} + }, + "rpc": { + "kind": "multi", + "bindings": { + "8332": { + "enabled": false, + "options": { + "preferredExternalPort": 8332, + "addSsl": { + "preferredExternalPort": 443, + "alpn": { + "specified": [ + "http/1.1" + ] + } + }, + "secure": null + }, + "lan": { + "assignedPort": null, + "assignedSslPort": 49153 + } + } + }, + "addresses": [ + { + "kind": "onion", + "address": "4dc6awce5nc4ldc36b4naibuzzsj5dwgyfvp43uc3mjp2nnvprchniyd" + } + ], + "hostnameInfo": {} + }, + "zmq": { + "kind": "multi", + "bindings": { + "28332": { + "enabled": false, + "options": { + "preferredExternalPort": 28332, + "addSsl": null, + "secure": null + }, + "lan": { + "assignedPort": null, + "assignedSslPort": null + } + }, + "28333": { + "enabled": false, + "options": { + "preferredExternalPort": 28333, + "addSsl": null, + "secure": null + }, + "lan": { + "assignedPort": null, + "assignedSslPort": null + } + } + }, + "addresses": [ + { + "kind": "onion", + "address": "dmdx34vr7mpjgtmxuhj67vmec7xvh7omxaxyunqpg35dvcbs4pvdh7id" + } + ], + "hostnameInfo": {} + } + }, + "storeExposedDependents": [] + }, + "hello-world": { + "stateInfo": { + "state": "installed", + "manifest": { + "id": "hello-world", + "title": "Hello World", + "version": "0.3.6:0", + "satisfies": [], + "releaseNotes": "Revamped for StartOS 0.3.6", + "canMigrateTo": "=0.3.6:0", + "canMigrateFrom": "=0.3.6:0 || <0.3.6:0", + "license": "mit", + "wrapperRepo": "https://github.com/Start9Labs/hello-world-wrapper", + "upstreamRepo": "https://github.com/Start9Labs/hello-world", + "supportSite": "https://docs.start9.com/", + "marketingSite": "https://start9.com/", + "donationUrl": "https://donate.start9.com/", + "description": { + "short": "Bare bones example of a StartOS service", + "long": "Hello World is a template service that provides examples of basic StartOS features." + }, + "images": { + "main": { + "source": "packed", + "arch": [ + "aarch64", + "x86_64" + ], + "emulateMissingAs": "aarch64" + } + }, + "assets": [], + "volumes": [ + "main" + ], + "alerts": { + "install": "Optional alert to display before installing the service", + "uninstall": null, + "restore": null, + "start": null, + "stop": null + }, + "dependencies": {}, + "hardwareRequirements": { + "device": [], + "ram": null, + "arch": null + }, + "gitHash": null, + "osVersion": "0.3.6" + } + }, + "dataVersion": "0.3.6:0", + "status": { + "main": "error", + "debug": "Error { source: \n 0: \u001b[91minvalid type: map, expected a sequence at line 1 column 922\u001b[0m\n\nLocation:\n \u001b[35m/home/rust/src/core/models/src/errors.rs\u001b[0m:\u001b[35m509\u001b[0m\n\n ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ SPANTRACE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n 0: \u001b[91mstartos::s9pk::v2\u001b[0m\u001b[91m::\u001b[0m\u001b[91mdeserialize\u001b[0m\n at \u001b[35mstartos/src/s9pk/v2/mod.rs\u001b[0m:\u001b[35m265\u001b[0m\n 1: \u001b[91mstartos::service\u001b[0m\u001b[91m::\u001b[0m\u001b[91mload\u001b[0m\n at \u001b[35mstartos/src/service/mod.rs\u001b[0m:\u001b[35m271\u001b[0m\n 2: \u001b[91mstartos::service::service_map\u001b[0m\u001b[91m::\u001b[0m\u001b[91mload\u001b[0m\n at \u001b[35mstartos/src/service/service_map.rs\u001b[0m:\u001b[35m80\u001b[0m\n 3: \u001b[91mstartos::service::service_map\u001b[0m\u001b[91m::\u001b[0m\u001b[91minit\u001b[0m\n at \u001b[35mstartos/src/service/service_map.rs\u001b[0m:\u001b[35m60\u001b[0m\n 4: \u001b[91mstartos::context::rpc\u001b[0m\u001b[91m::\u001b[0m\u001b[91mcleanup_and_initialize\u001b[0m\n at \u001b[35mstartos/src/context/rpc.rs\u001b[0m:\u001b[35m300\u001b[0m\n 5: \u001b[91mstartos::context::rpc\u001b[0m\u001b[91m::\u001b[0m\u001b[91minit\u001b[0m\n at \u001b[35mstartos/src/context/rpc.rs\u001b[0m:\u001b[35m118\u001b[0m\n 6: \u001b[91mstartos::bins::start_init\u001b[0m\u001b[91m::\u001b[0m\u001b[91msetup_or_init\u001b[0m\n at \u001b[35mstartos/src/bins/start_init.rs\u001b[0m:\u001b[35m21\u001b[0m\n 7: \u001b[91mstartos::bins::start_init\u001b[0m\u001b[91m::\u001b[0m\u001b[91mmain\u001b[0m\n at \u001b[35mstartos/src/bins/start_init.rs\u001b[0m:\u001b[35m204\u001b[0m\n 8: \u001b[91mstartos::bins::startd\u001b[0m\u001b[91m::\u001b[0m\u001b[91minner_main\u001b[0m\n at \u001b[35mstartos/src/bins/startd.rs\u001b[0m:\u001b[35m21\u001b[0m\n\nBacktrace omitted. Run with RUST_BACKTRACE=1 environment variable to display it.\nRun with RUST_BACKTRACE=full to include source snippets., kind: Deserialization, revision: None }", + "message": "Deserialization Error: invalid type: map, expected a sequence at line 1 column 922", + "onRebuild": "start" + }, + "registry": null, + "developerKey": "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAhUw/T99KgSZQYh1mp1FzDaZCOLmSG9qYSMNjw5WCfP4=\n-----END PUBLIC KEY-----\n", + "icon": "data:image/png;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8LCwkMEQ8SEhEPERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJBweHx7/2wBDAQUFBQcGBw4ICA4eFBEUHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh7/wgARCAFaAVoDASIAAhEBAxEB/8QAHAAAAwADAQEBAAAAAAAAAAAAAAECBQYHBAgD/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAAB6CAAAAAAAAAAAAwBghskoJKCSkJUhDBAAAAAAAAAAAAAAAAAAAAMYmwTbJbBFBLYSUElBKoJVBBSJGCAAAAAAAAAAAAAAYDYm2JsE2xDZLYIbJGElBKoJVIkpEqkSqQgAAAAAAAAAAYMYMYMYMYDYhsQ2SUElBKoJVBKpEq0QrRCuSVSEAAAAAAAA2qBjChgxgxgNiYxE4oy5rf4m1GsewzZ+HoJVolUiVSJVIlUiFSJVIQAAAADGFKgYxsYMoTfkPX4+eaWdF1XCbGa2uk5o44u5/scHO6+E4vld8149u48Z859Drj3STLqkTNySqRCpEzckjQAADCkx0mNjGxhS0s93KvNsRgt93jIHi9wxNgigkoIKR+Gm7yjgnh+g+aHr6B887kdTmkSqRCpEKkTNIQANMdKgpUNqhteYwPI/Tmj3dWLGxgxibZLYSUEqkSqRKpGi8u+iecn4dI+e+xGwzckzckzckzSJAG0x0mU1Q2qHzfo/BT8u6886mNjGxgyhNsQwSoJVImbklUiI/RHDa37kx9CrD5glVJM3JM0iU0OpodTQ6TKaownFurcoOx7Rj8gYX89bwx0/B4zUTqGExmtm8bLom5mG3v5x+kCdC3/AOaj6M/TyewxWoaDvpkdt4dv5+e08X7QX8+/RHCDdt85h08maRM1IpqSU0OpodJlNUOpo0/lXYePnfvZg84c+03e/Ka9+PTNEMlrO46UbL0TjXQzk30j8+UfQPzV0fTjt/r4HnTTPoHStKM9lNV66aP0XjXWj08M7n8+m19S510UU1JKaJmpFNSOpodTRTTKqaPNwT6F48bPv/CO6n6VNDqaKc0VUUU5BoQk5EnIpqRS0YHiO66mdU2iLFLRKcimpFNSOpZVTQ6minNFa/sDPnnpWJ00+ia1vYy3LLcspyynIMSHIgQhS0LXvfxM8XRNS7WUnIk5FNSKWiU0Nyy3NFOaKc0VUUePgvX+QHUt7wWcKc0U4ZbhlEsYkNCBHmP3wWpc+PbPp7AGQciTkSciTkU1Ik0DTKc0U5ZblluWc80TOo7NceQrj/m8Zsm48zxh9C+z5uyB9AnDv2O1nEfCd217i6N70utxNH3re8kfj+jkEISEJCEhCloQAADqWVUsqoooWKONbxoHUDa+NLyB2ac2Vh8uzR8R09nIfx7IHHvZ1UOf57YQmkhpIciBCEhBLkJchLQAAADTKcsqoorH+9nAa6zrxpvYrypbhlOQskKEDEikgaSGhAhAiQQglyCEIAAAAAAbllVDLcspyynLKcMpyFOQokKJBiQxIaECECECEEuQQAAAAAAAAA3LKcspyynLKcMpyFEsokKSBiQxIaENJDSQ0kCAAAAAAAAAAAABuWU4ZTllOGU4ZRIUIGJFEgxIaENJDQgQAAAAAAAAAAAAAAAA0FEsollEsokKJCiQpIGSDSBpAAAAAAAAAAAAAAAAAAAAAAAAMQMQUSFEgxAxAAAAAAAAAAAAAAf/xAAvEAABBAIBAgQEBgMBAAAAAAAEAQIDBQAGQBMUEBESFRYzNDUgISMwMVAiMoAk/9oACAEBAAEFAv8Ap572RpJaV0eOva1M+IK7Evq1cZb1r8ingl/oyixhWl7I1MIt7CfHKrl/EPYnD4LscqYFZhF84omAWKx2CaXHuc9zWq5w1HYTZBrLMjoa1mNq65udgDjqyvdklJWPybWhlwnXjo8nhlgdlfcli5XWQxycq4t4gsKImJlhikmkr9cVcFFHFb+zLGyVh+vDyYaESG9qq11Pe+fJvrft8VVVaipmPUEMcOL92WOOWO4oXReFFbqMqfmnFv7LsoV/NaGo7vGtRreBfUyTJmtWfodxC52DDFTyEkUVd3xLURreFs9Z5eFAd3ofD20v1SxMdLJXCsDE4bkRzbgPsTqQvs7DhKqNaVMpBOpDdQvi7WN1QMpCO5rODeydKozWIelU5a2UVclVaw2ElgUwIQC+HLLtrWGud8TiZ8UCYLYRz1kezCvk8H7OK10T0kiywOGBY/aIPMPYAZ35LsQ0cokyEDTxpNC5Fa7T5POHg7Y7yq8rm+gDN0/01cscQnYLIEmr1v73u3zaeCvnX2/XccLGFRCfU+E/zAfocsynGHV2ujuEuwPbzNSJdMBeM6dsGzpiZat9FnqDv/dwdu+2r/Aa+Ymbp/pV181hJYUhQQut/e92+bT1ktkvwsVlinlVCfU+E/zAfoVTzSRqtcBK2YLcZWPsNLYvSuamcm18LlfO21H7jwdmZ66fKKTq1GbYPOQzUxSYCtjikmqKAEyK324YkiVgNozO0uMqoik1v2yxz26zzURS4Dpa2wWX26zygDOit9go5Jp2w2g2CU9gU+vFjCEtgDZLINFaH/GEP6pGnM/U4JcXXFVFRdOI84eLekdtV5q8PSq+FsY3b2dWUoZzVRzeJtZnWLGhcQRExsUXCvwu8BzVbH1N4d5YIAIqqq6mF5cXZq7oStcrXUNh34vBsDIQhzipTCakF55UbGxx8SwVjQM06L0h8C1sxwGHFzGzgizGEV4cQI3F2eXp1OUcXRqf3iJ4h47PYlXHuc91bXzny14UAMHG3GX/AChYsszURqYYVCIOfamFTBbAdBguwgS5ASPOn4ZJGRoTeV0OGbIQ/J5pp5GtVzqvX3vyKOOGPj7HL1bfXIurb4YVCIPZnzHziwSkzlgFi+MRpkWNurNue+2mOu7RcksT5McquXB4JyHBa5O/AQBQk5Hn5JPIss2nRfqGExCQWZ0x84sEpM9TXxV8GE1gBGTa0M7JNZJTHa9YpnsNnia/ZLjNaMXIdZjTB6WthxqNa3lXEnSq8pJIgKKzOlOnFglJnqa+ICD+msoFJAVFRVe5WiwSkzVVfEBD/UWdQOY5utyequAgBj/7X//EABQRAQAAAAAAAAAAAAAAAAAAAID/2gAIAQMBAT8Bcn//xAAUEQEAAAAAAAAAAAAAAAAAAACA/9oACAECAQE/AXJ//8QAQRAAAgECAQcIBgkDBAMAAAAAAQIDABEEEBIhIjFBURMjMkBSYXFyMzRikbHBFEJjc4GSodHhMFCCIICDkzVTov/aAAgBAQAGPwL/AHPXkdU8xtWtjIvwN69K58IzW2b/AK69JIPGOtGLQea4rmpo38rf2O+ImVO7fVsLAW9qTR+lacQUHBNWrsSx7/8AXzWJkA4E3FWxMCuOKaDVopgH7DaD17lJ5Ai/GimEHIp2j0v4os7FmO81mqCTwFXMQiHGQ2/SufxTHuRbVpid/M5rRgofdXqcH5BWnBQflr1fN8rEVzOIlTx1qvEY5h3GxrNmjeM+0LZArNy0fZf965prPvRtvWzFHaSfhuXxoyzyF2oRxIzudwoPjZLfZp+9ZuHhWPw2/wBLMkRXXgwvRbCtyLdk6VrNxEZXgdxoMpII2EUIccdO6X9+snDYU899Zux/NXNZ/o4N78fCsyCPN4nef6xjlQOh2g0ZsFd03x7x4ccgw+JN4Nx7H8VcaR1bk4jz77PZHGrmhiMQCINw7f8AFBVAAGwDqLYnCLaXayD6/wDOQYKdtU+jPDu6q88nRQU88p1mNXf0CdPv7qCqAANg6mcdAv3o+eTXPPR6H7+/qiYNToXWfx3UsaC7MbAUkCbtp4nqhVhcHaKaL6h1k8KRydRtV/DqZZtg0mpJ22u16fEsNEQsPE9W5cDWhN/w35IZCdYDNbxHUsQw2lc335IzvkJfJGZI3fPv0adI4pEzFvrU2IdWZQRoFJhkglVn3m1RiWKR88EjNr1af9K9Wn/Smx6o4QBjmnbopUGGn1iBuykfRp9HhSSDQGUHJnYiS19ijSTWphJSO9gKCSZ8BPb2e/I8Zw811JU7KjnVSodbgGnibY6laKnaNFYiHgwbqQHGQZMOvCNfhkwvi3yqZsRKIwyWF/GpIoMQruSuix41hvE/A1hfK1SfT8SYLWzdNr1/5Nvzj9qnghZmQROQW8Kh86/HLJ5jWH+6X4ZJZ2O06vcN1JJimkMji9lNgtckGLIwzlJpoXNzCbDwrFL9oTUMfZjUfpkxK8JTUy8Yvn1JPvR8DkhP2a/DJhfFvlTpCyKUFznU2IkkiKi3RJrDeJ+BrC+VqkEcipydukK9ah/KaxA4QN8Kh86/HLJ5jWH+6X4VamQ7QSKhljN1KCo41NzHHre+sTJuJUU08Zi5Ns293se+tGTFfeGpD9l8x1KQ9khsmGbgub7smG5CF5LFr5ovbZU5ngkjBjFs5bb6kjiRnfOXQo76w8kmFmRATcle6sMYIJJbK181b2rUwuLXwBFehx3/ANVPFMkvLESWVtteo4j8lep4r8pqVsRBNGpj0Fx305+hYjpH6lep4r8pqB5cNOiAm5YG2ymxWDALNpePv4iiiR4yK+0KGrTC0ana8milw8ewbTxPGsS6YSZlaQ2ITbUKsLERrcfhVzUkvbYmsTL3BepSw9tSKsdtTYUnSpz16tM19ZhmL4nIHO2Vi3U3YDUl1x86jn+qNDeFBlNwdIPVRhkOpDt81RwJ0nNqWNOiosOpnMHOx6yftk+gSnSPRH5dUuDzz6Ix86uTcmmx0g26sfzPVfpcK8051vZNBlJBGkEUS+iWPQ/f39SM0x8q72NNPMdJ2DgOFCMaEGl24CljQZqqLAdVnaRQyiM3ByTTdt7e7qOvrynoxjbRlna53DcKEMK3O87gONCGL/Ju0erOu+RguTDpvK5x/HT/AF+UmkWNeJNGPArb7RvkKLuxZjtJrNiFlHSc7BXJQjzMdrdXw8Hi5pIhtdgtBRsGjIZpmso/Wi/KvEn1URrWrNltiF9rb7653PgPtC499Xhnjk8rf6ryOqD2javTcqeEYvVsLEsQ7TaxrlJpGkbixoKoJJ2AUJMdeNf/AFjafHhQjiQIg2AdYl4JZKh4Jd/dkM0zWUfrXKSaFHQTctLDCuc7Vz8DqO1tHvy83ipl/wAzXrbnxANesD8gr1ojwUVr4yc/5VdiWPfkzYInkPsis7FyCIdldJrmIgDvY6WP49Zudgp5T9diaxE/ABBRmmayj9a5STQo6CdmlhhXOdqzV1pG6b8f4yXkwyX4rqmuanlj8daubxMLeIIrQIW/5K9Cn/YK6EQ/5K15oF95rnsW7eVbV6vyh4yG9ZqgKOA63iHG3Mt79GT6TObB2Ld54VykmhR0V7NLDCuc7VmrrSN034/x/Z5oBtZdHjViLEbaCliVXYL7KWGFc5zWautIem/H+08qCYpd7Df41rYpM3uWs2Iax6THaf8Aex//xAAsEAEAAQEFBwUBAAMBAAAAAAABABEQITFBUWFxgZGhsfAgMEDB0fFQgOFg/9oACAEBAAE/If8AwNP9XaQBqPdLkqNPqTB5R4T9mOb2S7twO4QHkaxNf8FslNN7cYypbeFHJK8PcujpfNv+HV6+oualzrKRRn/JMp+qV0m6UVg8fPhKfNZZaVx2AziSeBjP6jEKQlVhZbwCqwsQ/AXwNFHRdTMeHyXUnfBX3sm7ACdp4nnGVlR0IPqVHwKB/ZsbzYrnTzLzdiJQtHMkf3h8I9kUG1/BsiMDm5GgZEws6HVgGpat/H8SnRZovb3FlPZWKeNIhq+/D7JfOmDfu2PhaqKIyrPMGU+c5iVGp7D7Z6bvrgPoPFIgRVaq5wKqk3hyDPtKKwcW/fvvYaiXUYGYt7X/AFnXfY+17nx8uUQCCFRM/U+6W0k1PxOkSiKt6uLHQxdNfjjCwtQFAPYp7JJB0TaPFY1G+5jXmdHz/Vy9La+otLSLviKauRxlYBXOzQNhGpKUVasj5hDgNQC4NPhkKZp+ePOYMopWodpxd/Sx9gtLUuC98sHAv4yjf7XLKLTTXnb8NhgDUTBIodcZc3+YS4M50z4N8bG19RCHpcChqbCY0i/PSHVTzNoV52HxBPus3fRsSqXQR+RjY2voLCEIQjsKUXipYFFvRzodCEqEqC5dSmu+O+Aai++mUNOo0a3tM4iiEFoLlydkR4VhLqb5/Z/c/p/uJhUUNr2hKCKrnaa2pNK0xy8YTSEjiVK2DazgnBkBTqr9SCBcw0PKw4zGlM5jo/GMaawHlsYCDdVBxKTFBVbyOg4TxKPa1jaxtIQhCEJsH/RY3DBNyXRCef0gpxUC1dyLVKDeU2izV47UlMQNycyuI7LCi3AAq3pynitFmc8TqzyOmMaMig0cELxnGRfTC+bWbUphRi+B1dZUOF8oNoON/wBzx4BYIeFDzrKWUrch+2MY2tpCEIQtFV0kYm6Edgp0Qnn9IBrGtcK0yIgPwlRe0zLNXntSUReTUa1rpulzBqfiCfFaLfE6s8jplY1FIP8ARybS6F4wrrS8hGaJRktVOUKourvBfsmVyjhQC5LtzKMJJIroHBjGxjG0hCELSUSL+vU+7DqFWq3qkIcJ7IyCS6JgsNDSFYsVOQjgX4YOJVYhK/fuN+crGURdgtdS7GFz3dgVCyFEFp1gwYaF/WUIVO9QoX5eplDSvguiWQgA8oNq59lfeyqK3q4tjDG0XEEcQYTJoimQC9n9yVrHcgG4q/UYxjGMbSEIekWfvUuiAaBom2B0iI3PWnOFhCFhD1MbKurG1lIaOgDtWymynAOB2jGMYx9BCEIWFhLuDm7g595ftUombx/eEOAYBma2EPbbWMYwq+ZHNY8i7nCpuZ2bYI1B7sIxjH1EIWEIQhENU4lrxH1YQ5vTMz4coQtPfSGam0fQiJCKq5sYZiq6eBz9bH0HsEVcopm/T3jd3qF46xzIopYaOL4LNmwDgCZeCDDKErFeNGbAxiCyCMYxjGMfQQhCEIWEWUTgG6GEqIZbcP1+Ay+agqi9tdCZdQDB0CVRzenFIQ1c0x1GNr7RaWllNHoOtXtZXIpxJ/0tPcSDui/sPWOFK/6N7FITVVVZfSrzN7smMC34g1fz0trH1HpLahHA7A+5ggg4tJckjRuLMpdDNaG2GwxvADhi7YAIXd5X3BA8UKJRitgy/Mlbd023+HulfBn/AEMJXfKhyOsdbXR/I2NqAqsXViROc/rdDOTQdA9Da2vsHqpAaiHAv6rLxFahwXdaQmUugYvQ2ysTCA3H7ti58IabXQjbsQKvBdZg1MdZgN6EMK8kYTyf6nZY/qH0E0rO02uYVbOKSmUjw88jrKF9c0Da+yepLYRV3TEcR4tZUQdwXvYmH+AGL0NsqkwgNw/dsVPgDTa6EuwZI5DSMqZMWavyuxK07OIPqYQvk4zoyfoswx7eRMIXY/RKM7APqaygoBzHThDQ7gND5b58Dv8A+ll1jMcEGuEqcwBtw/dsUDgDTa6Eu0ZI5DT45+B9COrzqRm5FA5Mrf4rXKsaaRSOBNNroS6JkzkND/Eq0vA1N19zC3qVY2W+LcDZ/lq/7Rf/2gAMAwEAAgADAAAAEPPPPPPPNBCMMBFMPPPPPPPPPPPPIJILMLOIGCIOPPPPPPPPOEMBMCJCDOGDIBEPPPPPPOBHPDEGCMIGGDMMNOPPPPPCHIADECENODMDDDALEPPPIKPAONJEIHBPFBAFKOFNPOJBFFLGNLJEIJIACFIKKGPLIKCDOHABIJMDDACFFEEGPBJEGABFBOMDGAFIOHJIEGFAKJECBCHOGGJGFGEFCOHBPKNEKANDEGPNLAGDKENAKFFKOFIPHAKGCBIJJECFFCLFFBIOGBCJFAOIJHAOGAJJECNDEGGKBIEDCGJAAJEBJJIEFKEFFFDCCNKDAKEAFAKKKGPPIIKEGCAMCEMOJDHAKFFFPPOAKFCFDJBMJEBAIBKFAPPPPCLAMIDJIDDJJMMOAFPPPPPPONOMCIOAEJJMDDDPPPPPPPPCDMCCHMNCIMDAPPPPPPPPPPLGGGBDDECGDPPPPPPPPPPPPPPDPDDLDPPPPPPPPP/EABQRAQAAAAAAAAAAAAAAAAAAAID/2gAIAQMBAT8Qcn//xAAUEQEAAAAAAAAAAAAAAAAAAACA/9oACAECAQE/EHJ//8QAKBABAQEAAQIGAgIDAQEAAAAAAQARITFBEFFhcYGhIJEwsUDB8NFQ/9oACAEBAAE/EP8AByyyyyyyyyz/AOBllllllngyyyyyyyz/ACsggggsssssssssskskkks/xwgggsgsgssssssskkkkkkkks/xAggssggssssssssskkskkkkkkk/wQgggggsggsssssssssskkkskkkkkk/nIIIIIIIIILLLLLLLLLJJJJJJJJJJJJP5SCCCCCCCCCCyCyyyyyyySSSSSSSSSSSST+Mggggggggggggsssssssskkkkkkkkkkkkkn+IIIIIIIIIIIIIIOSeAvYH2JhRHVD+rNJi+d/sJNwT2Ua+Q/0dmBO9v6UIg6nTT/Q7IOBHySSSSSSSSSSSSSSf4AgiCIIIIIIILJxTdr2XV+ptkOD5qcj8pNdgxYeW8nyyJQ6tb50x5WPlfMc3JcHieg4T5sB0Q/tiSvTY/OOZfCSXaEeTyB4+RlDjw+Ukkkkkkkkkkn5kERBBBBBBBADXCet5LlehLFW4APmdfg19SXImvu9V5ZJv4/7YOW587ctns39gje7wJ+1fqIMx3VvxhHhxe+/7MGYZ/8AXaCxn/J0Rjmz3wvsfUX2Cf7dfccA+hv/AKx+Fcnr65PtvD8bf6ZvgEbU/wDoHT0tutTN5pOx9deuSSSSSSTJJM/kEIggggiCJoRPeeizv6efPC4cmi8eUuPQJTY823r6Hq8TxQ5gvs6Z7B97gQ2fs135GMQWWWWWSSRd5wFfhlxLkRd5f+KnpEdvz9afD7cPpDWc1G7icjCqLMuJ2AdPbx5h1hAAhojonnJJJJJMkJ/EggiIRBBBc1SdSA/s/wCueiMXKKp6qvVfOSDBa6jqrq9ej1eLCaDrD59d9uh2CCCCCCyyyySSSSMrmD/Ge/r1IGDLCfurqHl0TpIxjllH7fOe440h7iX0CaInUTvJMzJCSSfwIiIIPAER7Keznsr9eoPPXtLBdQ1HlV7u3W4qEB556geF9h3Yrzzg3QA4CCCCCCyzwZJJJJJJJnJFlBCzzA7enp7uoQBBxExG6j6P1e58z4PHRMSZnwJJ4H8DwBB4CPBkwSw89IfVIHvbuKI6Hp5IMD2nzZB425R5vVe3qSFCPJCMAdgIIIIIIILLLLJJJJJJJIow3R8c8ZPr4eaF0FEeEcRkIeSuoz6xz6HzmZnxEnxIjwEeAi4jiMei5Pk9x8pKAId1gXQnJnKcv7vTyAO0EEEEEEEEFlkkkkkkkkJIMydUYieScRXr1GDhvmtXt6zrS8943D6HwYf8SeBnwMz4H4AiILbYIdg1f0M/Spx7C8PjB8WboVTjJN+H9EHgIIIIIIILLJJJJJJmZtSmkhyuB8P6GTdHo8NyOPF5V2vuC+fEfAz4HwPAfkDMACnmX9VuNwkLht8x/ov78Bj0yzwp3RFakageA087OHEsNIZoO83pZnLmcnSIkUAgYO6PPtHhUCIhOjc1gxzno5sYjgAkF8nMnKb0YNQ82XZLpzKT+lm7E3AgOd+ZIP8At6QOuPb1cDzmmg8OH4DH7lSgDJfJT9gHrGcwzGI8c97WvIMlSz4SwVLNnTc42IAMXyb/AGgSzSfMx+y4yhXyG+wzPiM/gH8ABiHr3qH+kS0eQsR2H3g/b4gGKLHoaTg9owiyiAV0Dg8SmcfcF6lfNGZ+1gawTsXwXY5AZzxx4Pk5fdg4e54ssODq4d3yJ45heHIPkZz7q95oZ85CDqKBNXje0wkWcDarDhRE06iMoNKtd3ygD0w7WQMML0IYAhmyeoD9y46duYmcwXov/abZ6gev/qT+AZ8D/AARKKcbPkLkHq/qY/h3jACDWoArgNOdkLbUNIZidXz8Sj9Xd1KWDPRv9yiOoZ/wTsNQudcZ4f8Az92zk9/Hlgy9xbfuZMhSLqIo/ZYYQnlgInkiInpYAga3eC9eCnqTCBL80X6+y60OSxyBz0PmePIc8jy7XIma0z/SH+oTHG35/CD+AfF0fgCPA2wezwK+ld8biQP01f1DwMD2K4OG503H9R7CKC2gvVzmRXqwwVQPI5mDpHuiavTlD5lQDICXBzpuMo+A9vOm8Nv+D/1GLIi7oQ0u9oAskD/vPBXl7dhlwe7BZgZaMUWj0gGBB0yXTC7YiavHVCSdOMfeV4V7pOeTrlusXJr59r7zVoE6TeuOX7HPmWO6oOc0md17dgDtOMqkB4Rzkh+zTiRInZHiG0B6PYOX6ncd/TqPplAcveqP0P4AD+QERF0bxd7I1+8mSLO7BxP3cJREvXPH2C8A/AHiDDbLPiNhwB7Ny5ZnwH30/wCe6PbT4gDA6dCTqq4dv+tPz+YDP5gPAX6T5FtQ4Ez4tvsI1fA2x9w4eonXnLoxoPREY8QiIhttlll8DP4hyhztcC/0Pcx8Ck+p59ga/FhH7eQA/r8QZmfxB+QN3PRDnJ/5HqTp576lgLJV9f3OT5jTsS8BDKGGGG2WWWWZmZihWrzncz1N9XDzmPAW1R1V7q82JTAh7D9+mMzMz4j4HgIiIiLsRbJxx/x33ovPpo7kGhuME6B7I2EEJ5qaJ24OnZHtkMQxDDDDbbLLLLLPg4tPLJwuC/t6ByxFXlLjfoH26vW4yeOd/ofoD3egwQZr4NgH8IA+B/AAHwGgvfR3gnvkHA9c5nzJF/P/ANb+oYYYYYYbbbZZZZZZSoH4U4v3vL2G2ip0ff7Y+15b7EBBL2D9rwc3FQuRmXn+oOxxKWZTMzM+J4BjwDD4BuKQaef+i+9vd6d7iwE/Vf6D9Qw2noL7EMMMNttttsst1qwGD6HdehrMq+rn/Vv9j0JvTHfnyvK3FVwFz8v6Bz7HMLVwDHrT+hwftVmZZSz4jPieAYiPAQ3ZI56qfUQ1NADzL/aJrFE7Bh9EN0l7Dl/Q+6+urwXolAabVD5y+MLiU1nFPTmfg24b69X+X7CJJHQX/W6fqcdQ9yB2tlh3jl7T4AOTH2ITuRfb78P7gHPwIe6HH6o6Pd6z0Ow9DC0quOvyA5bimD4PBwPQ2OPNpI/9815e8ssspZfAz4H8CGHwEREOF/eQFoN19hZ/ZFdJSeZ2p919dXgmfOeiT/a793thKBLhcAdU6B3Ww7bx7lGn7ZCJo6eYxw8Q6DhPmIAR0xv0qRQCH/M0Mzb1aBYymwUOoL+szFg6vf7d8DT64jE93ofKS/WCuKeS00PBivkLkPQw9JcllllllLL4FmfxGUMMMMM2OId7A1+iY/Wp9b/a6KTz1T9X7LzaNDtT7r66vBMec9E3t6rv3ewEkFMDgHdOx1W44sL4X9B2O/V56bqXQxOz7w4XWd7m5352WSHoS/2+5Be0Bb6BN8R5kf0STmvqf+8xnrn+uM2eftM/QPuS8wDP7V9TnRg5L7s+l0U5KfwYSyyyyyyyyyzLM/kQwwxDDPEmpOyEBnB26R3BwGruX3I/bdeJfzrrvK+q793sBJmTA4B3TsdVuDKC+F/Qdjv1eegwwww2222yyyyyyyyyyyyyymZfzGGIYYbMXab6aA/IHzLI4XiTiJ2R4uS7DnduC5rvkjZeDgHdOx1W4/qL4X9D2Pl5hhhhhtttttllllllllllllllln+AhhhhhhhdDwKvNc19CPnskG85XT2UPuCdhqHLoKcB2HHu8wwwww2222222yyyyyyyyyyyyyyz/CQwwwwwwwwwwwww222+DZZZZZZZZZZZZZZZf4xhhhhhhhhhthttttttttlllllllllllll/lGGGGGGGGGG222222222WWWWWWWWWWWX+cYYYYYYYYbbbbbbbbZZZZZZZZZZZZf8EYYYYYYbbbbbbbbbbZZZZZZZZZZf8QYYYYYYbbbbbbbbZZZZZZZZZf8AG22GGG22222222222WWW2X/K2G22222222222W223/P222222222223/AO7/AP/Z", + "lastBackup": null, + "currentDependencies": {}, + "actions": { + "set-name": { + "name": "Set Name", + "description": "Set your name so Hello World can say hello to you", + "warning": null, + "visibility": "enabled", + "allowedStatuses": "any", + "hasInput": true, + "group": null + }, + "show-secret-phrase": { + "name": "Show Secret Phrase", + "description": "Reveal the secret phrase for Hello World", + "warning": null, + "visibility": "enabled", + "allowedStatuses": "any", + "hasInput": false, + "group": null + }, + "name-to-logs": { + "name": "Print name to Logs", + "description": "Prints \"Hello [Name]\" to the service logs.", + "warning": null, + "visibility": "enabled", + "allowedStatuses": "only-running", + "hasInput": false, + "group": null + } + }, + "requestedActions": {}, + "serviceInterfaces": { + "ui": { + "id": "ui", + "name": "Web UI", + "description": "The web interface of Hello World", + "hasPrimary": false, + "masked": false, + "addressInfo": { + "username": null, + "hostId": "ui-multi", + "internalPort": 80, + "scheme": "http", + "sslScheme": "https", + "suffix": "" + }, + "type": "ui" + } + }, + "hosts": { + "ui-multi": { + "kind": "multi", + "bindings": { + "80": { + "enabled": false, + "options": { + "preferredExternalPort": 80, + "addSsl": { + "preferredExternalPort": 443, + "alpn": { + "specified": [ + "http/1.1" + ] + } + }, + "secure": null + }, + "lan": { + "assignedPort": null, + "assignedSslPort": 49154 + } + } + }, + "addresses": [ + { + "kind": "onion", + "address": "b5vx4e3liq2twdeuqqp5bcuvqvoh2hil3yyci7re4ioeiwz4q3qlg2qd" + } + ], + "hostnameInfo": {} + } + }, + "storeExposedDependents": [] + } + }, + "ui": { + "name": null, + "ack-welcome": "0.3.5.1", + "marketplace": { + "selected-url": "https://registry.start9.com/", + "known-hosts": { + "https://registry.start9.com/": { + "name": "Start9 Registry" + }, + "https://community-registry.start9.com/": { + "name": "Community Registry" + } + } + }, + "dev": {}, + "gaming": { + "snake": { + "high-score": 0 + } + }, + "ack-instructions": {}, + "theme": "Dark", + "widgets": [], + "ackWelcome": "0.3.6-alpha.7" + } + } +} diff --git a/container-runtime/package-lock.json b/container-runtime/package-lock.json index 73d95bdae..696de8bf9 100644 --- a/container-runtime/package-lock.json +++ b/container-runtime/package-lock.json @@ -20,7 +20,6 @@ "node-fetch": "^3.1.0", "ts-matches": "^5.5.1", "tslib": "^2.5.3", - "tslog": "^4.9.3", "typescript": "^5.1.3", "yaml": "^2.3.1" }, @@ -38,20 +37,29 @@ }, "../sdk/dist": { "name": "@start9labs/start-sdk", - "version": "0.4.0-rev0.lib0.rc8.beta10", + "version": "0.3.6-alpha8", "license": "MIT", "dependencies": { + "@iarna/toml": "^2.2.5", + "@noble/curves": "^1.4.0", + "@noble/hashes": "^1.4.0", "isomorphic-fetch": "^3.0.0", - "ts-matches": "^5.4.1" + "lodash.merge": "^4.6.2", + "mime": "^4.0.3", + "ts-matches": "^5.5.1", + "yaml": "^2.2.2" }, "devDependencies": { "@iarna/toml": "^2.2.5", "@types/jest": "^29.4.0", + "@types/lodash.merge": "^4.6.2", "copyfiles": "^2.4.1", "jest": "^29.4.3", + "peggy": "^3.0.2", "prettier": "^3.2.5", "ts-jest": "^29.0.5", "ts-node": "^10.9.1", + "ts-pegjs": "^4.2.1", "tsx": "^4.7.1", "typescript": "^5.0.4", "yaml": "^2.2.2" @@ -59,9 +67,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": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" @@ -72,9 +79,8 @@ }, "node_modules/@babel/code-frame": { "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", - "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/highlight": "^7.24.7", "picocolors": "^1.0.0" @@ -85,18 +91,16 @@ }, "node_modules/@babel/compat-data": { "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.2.tgz", - "integrity": "sha512-bYcppcpKBvX4znYaPEeFau03bp89ShqNMLs+rmdptMw+heSZh9+z84d2YG+K7cYLbWwzdjtDoW/uqZmPjulClQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz", - "integrity": "sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==", "dev": true, + "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.24.7", @@ -124,9 +128,8 @@ }, "node_modules/@babel/core/node_modules/debug": { "version": "4.3.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", - "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.1.2" }, @@ -141,24 +144,21 @@ }, "node_modules/@babel/core/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 + "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": { "semver": "bin/semver.js" } }, "node_modules/@babel/generator": { "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.0.tgz", - "integrity": "sha512-3LEEcj3PVW8pW2R1SR1M89g/qrYk/m/mB/tLqn7dn4sbBUQyTqnlod+II2U4dqiGtUmkcnAmkMDralTFZttRiw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.25.0", "@jridgewell/gen-mapping": "^0.3.5", @@ -171,9 +171,8 @@ }, "node_modules/@babel/helper-compilation-targets": { "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz", - "integrity": "sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/compat-data": "^7.25.2", "@babel/helper-validator-option": "^7.24.8", @@ -187,33 +186,29 @@ }, "node_modules/@babel/helper-compilation-targets/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": { "yallist": "^3.0.2" } }, "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": { "semver": "bin/semver.js" } }, "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/@babel/helper-module-imports": { "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", - "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/traverse": "^7.24.7", "@babel/types": "^7.24.7" @@ -224,9 +219,8 @@ }, "node_modules/@babel/helper-module-transforms": { "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz", - "integrity": "sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.24.7", "@babel/helper-simple-access": "^7.24.7", @@ -242,18 +236,16 @@ }, "node_modules/@babel/helper-plugin-utils": { "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz", - "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-simple-access": { "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", - "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/traverse": "^7.24.7", "@babel/types": "^7.24.7" @@ -264,36 +256,32 @@ }, "node_modules/@babel/helper-string-parser": { "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", - "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", - "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz", - "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.0.tgz", - "integrity": "sha512-MjgLZ42aCm0oGjJj8CtSM3DB8NOOf8h2l7DCTePJs29u+v7yO/RBX9nShlKMgFnRks/Q4tBAe7Hxnov9VkGwLw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/template": "^7.25.0", "@babel/types": "^7.25.0" @@ -304,9 +292,8 @@ }, "node_modules/@babel/highlight": { "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", - "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.24.7", "chalk": "^2.4.2", @@ -319,9 +306,8 @@ }, "node_modules/@babel/highlight/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": { "color-convert": "^1.9.0" }, @@ -331,9 +317,8 @@ }, "node_modules/@babel/highlight/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": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -345,42 +330,37 @@ }, "node_modules/@babel/highlight/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": { "color-name": "1.1.3" } }, "node_modules/@babel/highlight/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 + "dev": true, + "license": "MIT" }, "node_modules/@babel/highlight/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": { "node": ">=0.8.0" } }, "node_modules/@babel/highlight/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": { "node": ">=4" } }, "node_modules/@babel/highlight/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": { "has-flag": "^3.0.0" }, @@ -390,9 +370,8 @@ }, "node_modules/@babel/parser": { "version": "7.25.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.3.tgz", - "integrity": "sha512-iLTJKDbJ4hMvFPgQwwsVoxtHyWpKKPBrxkANrSYewDPaPpT5py5yeVkgPIJ7XYXhndxJpaA3PyALSXQ7u8e/Dw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.25.2" }, @@ -405,9 +384,8 @@ }, "node_modules/@babel/plugin-syntax-async-generators": { "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -417,9 +395,8 @@ }, "node_modules/@babel/plugin-syntax-bigint": { "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -429,9 +406,8 @@ }, "node_modules/@babel/plugin-syntax-class-properties": { "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.12.13" }, @@ -441,9 +417,8 @@ }, "node_modules/@babel/plugin-syntax-import-meta": { "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -453,9 +428,8 @@ }, "node_modules/@babel/plugin-syntax-json-strings": { "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -465,9 +439,8 @@ }, "node_modules/@babel/plugin-syntax-jsx": { "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.7.tgz", - "integrity": "sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -480,9 +453,8 @@ }, "node_modules/@babel/plugin-syntax-logical-assignment-operators": { "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -492,9 +464,8 @@ }, "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -504,9 +475,8 @@ }, "node_modules/@babel/plugin-syntax-numeric-separator": { "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -516,9 +486,8 @@ }, "node_modules/@babel/plugin-syntax-object-rest-spread": { "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -528,9 +497,8 @@ }, "node_modules/@babel/plugin-syntax-optional-catch-binding": { "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -540,9 +508,8 @@ }, "node_modules/@babel/plugin-syntax-optional-chaining": { "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -552,9 +519,8 @@ }, "node_modules/@babel/plugin-syntax-top-level-await": { "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -567,9 +533,8 @@ }, "node_modules/@babel/plugin-syntax-typescript": { "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.7.tgz", - "integrity": "sha512-c/+fVeJBB0FeKsFvwytYiUD+LBvhHjGSI0g446PRGdSVGZLRNArBUno2PETbAly3tpiNAQR5XaZ+JslxkotsbA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -582,9 +547,8 @@ }, "node_modules/@babel/template": { "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz", - "integrity": "sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==", "dev": true, + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.24.7", "@babel/parser": "^7.25.0", @@ -596,9 +560,8 @@ }, "node_modules/@babel/traverse": { "version": "7.25.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.3.tgz", - "integrity": "sha512-HefgyP1x754oGCsKmV5reSmtV7IXj/kpaE1XYY+D9G5PvKKoFfSbiS4M77MdjuwlZKDIKFCffq9rPU+H/s3ZdQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.24.7", "@babel/generator": "^7.25.0", @@ -614,9 +577,8 @@ }, "node_modules/@babel/traverse/node_modules/debug": { "version": "4.3.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", - "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.1.2" }, @@ -631,15 +593,13 @@ }, "node_modules/@babel/traverse/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 + "dev": true, + "license": "MIT" }, "node_modules/@babel/types": { "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.2.tgz", - "integrity": "sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.24.8", "@babel/helper-validator-identifier": "^7.24.7", @@ -651,9 +611,8 @@ }, "node_modules/@bcoe/v8-coverage": { "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@iarna/toml": { "version": "2.2.5", @@ -661,9 +620,8 @@ }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", "dev": true, + "license": "ISC", "dependencies": { "camelcase": "^5.3.1", "find-up": "^4.1.0", @@ -677,18 +635,16 @@ }, "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": { "node": ">=8" } }, "node_modules/@jest/console": { "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", - "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", "dev": true, + "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", "@types/node": "*", @@ -703,9 +659,8 @@ }, "node_modules/@jest/core": { "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", - "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", "dev": true, + "license": "MIT", "dependencies": { "@jest/console": "^29.7.0", "@jest/reporters": "^29.7.0", @@ -750,9 +705,8 @@ }, "node_modules/@jest/environment": { "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", - "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", "dev": true, + "license": "MIT", "dependencies": { "@jest/fake-timers": "^29.7.0", "@jest/types": "^29.6.3", @@ -765,9 +719,8 @@ }, "node_modules/@jest/expect": { "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", - "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", "dev": true, + "license": "MIT", "dependencies": { "expect": "^29.7.0", "jest-snapshot": "^29.7.0" @@ -778,9 +731,8 @@ }, "node_modules/@jest/expect-utils": { "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", - "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", "dev": true, + "license": "MIT", "dependencies": { "jest-get-type": "^29.6.3" }, @@ -790,9 +742,8 @@ }, "node_modules/@jest/fake-timers": { "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", - "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", "dev": true, + "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", "@sinonjs/fake-timers": "^10.0.2", @@ -807,9 +758,8 @@ }, "node_modules/@jest/globals": { "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", - "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", "dev": true, + "license": "MIT", "dependencies": { "@jest/environment": "^29.7.0", "@jest/expect": "^29.7.0", @@ -822,9 +772,8 @@ }, "node_modules/@jest/reporters": { "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", - "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", "dev": true, + "license": "MIT", "dependencies": { "@bcoe/v8-coverage": "^0.2.3", "@jest/console": "^29.7.0", @@ -865,9 +814,8 @@ }, "node_modules/@jest/schemas": { "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", - "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", "dev": true, + "license": "MIT", "dependencies": { "@sinclair/typebox": "^0.27.8" }, @@ -877,9 +825,8 @@ }, "node_modules/@jest/source-map": { "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", - "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "^0.3.18", "callsites": "^3.0.0", @@ -891,9 +838,8 @@ }, "node_modules/@jest/test-result": { "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", - "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", "dev": true, + "license": "MIT", "dependencies": { "@jest/console": "^29.7.0", "@jest/types": "^29.6.3", @@ -906,9 +852,8 @@ }, "node_modules/@jest/test-sequencer": { "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", - "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", "dev": true, + "license": "MIT", "dependencies": { "@jest/test-result": "^29.7.0", "graceful-fs": "^4.2.9", @@ -921,9 +866,8 @@ }, "node_modules/@jest/transform": { "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", - "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/core": "^7.11.6", "@jest/types": "^29.6.3", @@ -947,9 +891,8 @@ }, "node_modules/@jest/types": { "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", "dev": true, + "license": "MIT", "dependencies": { "@jest/schemas": "^29.6.3", "@types/istanbul-lib-coverage": "^2.0.0", @@ -964,9 +907,8 @@ }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -978,33 +920,29 @@ }, "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": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/set-array": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -1082,9 +1020,8 @@ }, "node_modules/@sinclair/typebox": { "version": "0.27.8", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", - "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@sindresorhus/is": { "version": "4.6.0", @@ -1099,18 +1036,16 @@ }, "node_modules/@sinonjs/commons": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", - "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "type-detect": "4.0.8" } }, "node_modules/@sinonjs/fake-timers": { "version": "10.3.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", - "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "@sinonjs/commons": "^3.0.0" } @@ -1218,9 +1153,8 @@ }, "node_modules/@types/babel__core": { "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", - "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", @@ -1231,18 +1165,16 @@ }, "node_modules/@types/babel__generator": { "version": "7.6.8", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", - "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.0.0" } }, "node_modules/@types/babel__template": { "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", "dev": true, + "license": "MIT", "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" @@ -1250,9 +1182,8 @@ }, "node_modules/@types/babel__traverse": { "version": "7.20.6", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", - "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.20.7" } @@ -1270,9 +1201,8 @@ }, "node_modules/@types/graceful-fs": { "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", - "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -1284,33 +1214,29 @@ }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", - "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/istanbul-lib-report": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", - "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", "dev": true, + "license": "MIT", "dependencies": { "@types/istanbul-lib-coverage": "*" } }, "node_modules/@types/istanbul-reports": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", - "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/istanbul-lib-report": "*" } }, "node_modules/@types/jest": { "version": "29.5.12", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.12.tgz", - "integrity": "sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw==", "dev": true, + "license": "MIT", "dependencies": { "expect": "^29.0.0", "pretty-format": "^29.0.0" @@ -1318,9 +1244,8 @@ }, "node_modules/@types/jsonpath": { "version": "0.2.4", - "resolved": "https://registry.npmjs.org/@types/jsonpath/-/jsonpath-0.2.4.tgz", - "integrity": "sha512-K3hxB8Blw0qgW6ExKgMbXQv2UPZBoE2GqLpVY+yr7nMD2Pq86lsuIzyAaiQ7eMqFL5B6di6pxSkogLJEyEHoGA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/keyv": { "version": "3.1.4", @@ -1348,24 +1273,21 @@ }, "node_modules/@types/stack-utils": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/yargs": { "version": "17.0.33", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", - "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", "dev": true, + "license": "MIT", "dependencies": { "@types/yargs-parser": "*" } }, "node_modules/@types/yargs-parser": { "version": "21.0.3", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", - "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/accepts": { "version": "1.3.8", @@ -1380,9 +1302,8 @@ }, "node_modules/ansi-escapes": { "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", "dev": true, + "license": "MIT", "dependencies": { "type-fest": "^0.21.3" }, @@ -1395,18 +1316,16 @@ }, "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==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "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": { "color-convert": "^2.0.1" }, @@ -1419,9 +1338,8 @@ }, "node_modules/anymatch": { "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, + "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -1451,9 +1369,8 @@ }, "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": { "sprintf-js": "~1.0.2" } @@ -1464,15 +1381,13 @@ }, "node_modules/async": { "version": "3.2.5", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", - "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/babel-jest": { "version": "29.7.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", - "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", "dev": true, + "license": "MIT", "dependencies": { "@jest/transform": "^29.7.0", "@types/babel__core": "^7.1.14", @@ -1491,9 +1406,8 @@ }, "node_modules/babel-plugin-istanbul": { "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@istanbuljs/load-nyc-config": "^1.0.0", @@ -1507,9 +1421,8 @@ }, "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { "version": "5.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", - "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "@babel/core": "^7.12.3", "@babel/parser": "^7.14.7", @@ -1523,18 +1436,16 @@ }, "node_modules/babel-plugin-istanbul/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": { "semver": "bin/semver.js" } }, "node_modules/babel-plugin-jest-hoist": { "version": "29.6.3", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", - "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/template": "^7.3.3", "@babel/types": "^7.3.3", @@ -1547,9 +1458,8 @@ }, "node_modules/babel-preset-current-node-syntax": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-bigint": "^7.8.3", @@ -1570,9 +1480,8 @@ }, "node_modules/babel-preset-jest": { "version": "29.6.3", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", - "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", "dev": true, + "license": "MIT", "dependencies": { "babel-plugin-jest-hoist": "^29.6.3", "babel-preset-current-node-syntax": "^1.0.0" @@ -1784,8 +1693,6 @@ }, "node_modules/browserslist": { "version": "4.23.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz", - "integrity": "sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==", "dev": true, "funding": [ { @@ -1801,6 +1708,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { "caniuse-lite": "^1.0.30001646", "electron-to-chromium": "^1.5.4", @@ -1816,9 +1724,8 @@ }, "node_modules/bs-logger": { "version": "0.2.6", - "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", - "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", "dev": true, + "license": "MIT", "dependencies": { "fast-json-stable-stringify": "2.x" }, @@ -1828,18 +1735,16 @@ }, "node_modules/bser": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { "node-int64": "^0.4.0" } }, "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 + "dev": true, + "license": "MIT" }, "node_modules/bytes": { "version": "3.1.2", @@ -1906,26 +1811,22 @@ }, "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": { "node": ">=6" } }, "node_modules/camelcase": { "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/caniuse-lite": { "version": "1.0.30001650", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001650.tgz", - "integrity": "sha512-fgEc7hP/LB7iicdXHUI9VsBsMZmUmlVJeQP2qqQW+3lkqVhbmjEU8zp+h5stWeilX+G7uXuIUIIlWlDw9jdt8g==", "dev": true, "funding": [ { @@ -1940,13 +1841,13 @@ "type": "github", "url": "https://github.com/sponsors/ai" } - ] + ], + "license": "CC-BY-4.0" }, "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": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -1960,17 +1861,14 @@ }, "node_modules/char-regex": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" } }, "node_modules/ci-info": { "version": "3.9.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", - "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", "dev": true, "funding": [ { @@ -1978,21 +1876,20 @@ "url": "https://github.com/sponsors/sibiraj-s" } ], + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/cjs-module-lexer": { "version": "1.3.1", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.3.1.tgz", - "integrity": "sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/cliui": { "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, + "license": "ISC", "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", @@ -2015,9 +1912,8 @@ }, "node_modules/co": { "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", "dev": true, + "license": "MIT", "engines": { "iojs": ">= 1.0.0", "node": ">= 0.12.0" @@ -2025,15 +1921,13 @@ }, "node_modules/collect-v8-coverage": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", - "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", - "dev": true + "dev": true, + "license": "MIT" }, "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==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -2043,9 +1937,8 @@ }, "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==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/commander": { "version": "7.2.0", @@ -2057,9 +1950,8 @@ }, "node_modules/concat-map": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/content-disposition": { "version": "0.5.4", @@ -2080,9 +1972,8 @@ }, "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 + "dev": true, + "license": "MIT" }, "node_modules/cookie": { "version": "0.6.0", @@ -2097,9 +1988,8 @@ }, "node_modules/create-jest": { "version": "29.7.0", - "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", - "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", "dev": true, + "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", "chalk": "^4.0.0", @@ -2167,9 +2057,8 @@ }, "node_modules/dedent": { "version": "1.5.3", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz", - "integrity": "sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==", "dev": true, + "license": "MIT", "peerDependencies": { "babel-plugin-macros": "^3.1.0" }, @@ -2181,14 +2070,12 @@ }, "node_modules/deep-is": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" + "license": "MIT" }, "node_modules/deepmerge": { "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -2233,18 +2120,16 @@ }, "node_modules/detect-newline": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/diff-sequences": { "version": "29.6.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", - "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", "dev": true, + "license": "MIT", "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } @@ -2255,9 +2140,8 @@ }, "node_modules/ejs": { "version": "3.1.10", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", - "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", "dev": true, + "license": "Apache-2.0", "dependencies": { "jake": "^10.8.5" }, @@ -2270,15 +2154,13 @@ }, "node_modules/electron-to-chromium": { "version": "1.5.5", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.5.tgz", - "integrity": "sha512-QR7/A7ZkMS8tZuoftC/jfqNkZLQO779SSW3YuZHP4eXpj3EffGLFcB/Xu9AAZQzLccTiCV+EmUo3ha4mQ9wnlA==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/emittery": { "version": "0.13.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", - "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -2288,9 +2170,8 @@ }, "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==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/encodeurl": { "version": "1.0.2", @@ -2309,9 +2190,8 @@ }, "node_modules/error-ex": { "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "dev": true, + "license": "MIT", "dependencies": { "is-arrayish": "^0.2.1" } @@ -2339,9 +2219,8 @@ }, "node_modules/escalade": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -2363,8 +2242,7 @@ }, "node_modules/escodegen": { "version": "1.14.3", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", - "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", + "license": "BSD-2-Clause", "dependencies": { "esprima": "^4.0.1", "estraverse": "^4.2.0", @@ -2384,8 +2262,7 @@ }, "node_modules/escodegen/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==", + "license": "BSD-3-Clause", "optional": true, "engines": { "node": ">=0.10.0" @@ -2393,8 +2270,7 @@ }, "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==", + "license": "BSD-2-Clause", "bin": { "esparse": "bin/esparse.js", "esvalidate": "bin/esvalidate.js" @@ -2405,16 +2281,14 @@ }, "node_modules/estraverse": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } }, "node_modules/esutils": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" } @@ -2456,8 +2330,6 @@ }, "node_modules/exit": { "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", "dev": true, "engines": { "node": ">= 0.8.0" @@ -2465,9 +2337,8 @@ }, "node_modules/expect": { "version": "29.7.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", - "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", "dev": true, + "license": "MIT", "dependencies": { "@jest/expect-utils": "^29.7.0", "jest-get-type": "^29.6.3", @@ -2559,14 +2430,12 @@ }, "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==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-levenshtein": { "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" + "license": "MIT" }, "node_modules/fastq": { "version": "1.17.1", @@ -2578,9 +2447,8 @@ }, "node_modules/fb-watchman": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", - "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", "dev": true, + "license": "Apache-2.0", "dependencies": { "bser": "2.1.1" } @@ -2637,18 +2505,16 @@ }, "node_modules/filelist": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", - "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", "dev": true, + "license": "Apache-2.0", "dependencies": { "minimatch": "^5.0.1" } }, "node_modules/filelist/node_modules/minimatch": { "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -2712,9 +2578,8 @@ }, "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==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -2763,16 +2628,13 @@ }, "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 + "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" @@ -2790,18 +2652,16 @@ }, "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": { "node": ">=6.9.0" } }, "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==", "dev": true, + "license": "ISC", "engines": { "node": "6.* || 8.* || >= 10.*" } @@ -2825,9 +2685,8 @@ }, "node_modules/get-package-type": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8.0.0" } @@ -2842,10 +2701,8 @@ }, "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": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -2874,9 +2731,8 @@ }, "node_modules/glob/node_modules/brace-expansion": { "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -2884,9 +2740,8 @@ }, "node_modules/glob/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": { "brace-expansion": "^1.1.7" }, @@ -2896,9 +2751,8 @@ }, "node_modules/globals": { "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -2939,15 +2793,13 @@ }, "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==", - "dev": true + "dev": 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": { "node": ">=8" } @@ -2994,9 +2846,8 @@ }, "node_modules/html-escaper": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/http-cache-semantics": { "version": "4.1.1", @@ -3068,9 +2919,8 @@ }, "node_modules/import-local": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", - "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", "dev": true, + "license": "MIT", "dependencies": { "pkg-dir": "^4.2.0", "resolve-cwd": "^3.0.0" @@ -3087,19 +2937,16 @@ }, "node_modules/imurmurhash": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8.19" } }, "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": { "once": "^1.3.0", "wrappy": "1" @@ -3118,15 +2965,13 @@ }, "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 + "dev": true, + "license": "MIT" }, "node_modules/is-core-module": { "version": "2.15.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.0.tgz", - "integrity": "sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA==", "dev": true, + "license": "MIT", "dependencies": { "hasown": "^2.0.2" }, @@ -3147,18 +2992,16 @@ }, "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==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/is-generator-fn": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -3231,18 +3074,16 @@ }, "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": { "node": ">=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": { "@babel/core": "^7.23.9", "@babel/parser": "^7.23.9", @@ -3256,9 +3097,8 @@ }, "node_modules/istanbul-lib-report": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", - "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "istanbul-lib-coverage": "^3.0.0", "make-dir": "^4.0.0", @@ -3270,9 +3110,8 @@ }, "node_modules/istanbul-lib-source-maps": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "debug": "^4.1.1", "istanbul-lib-coverage": "^3.0.0", @@ -3284,9 +3123,8 @@ }, "node_modules/istanbul-lib-source-maps/node_modules/debug": { "version": "4.3.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", - "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.1.2" }, @@ -3301,24 +3139,21 @@ }, "node_modules/istanbul-lib-source-maps/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 + "dev": true, + "license": "MIT" }, "node_modules/istanbul-lib-source-maps/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": { "node": ">=0.10.0" } }, "node_modules/istanbul-reports": { "version": "3.1.7", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", - "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "html-escaper": "^2.0.0", "istanbul-lib-report": "^3.0.0" @@ -3329,9 +3164,8 @@ }, "node_modules/jake": { "version": "10.9.2", - "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.2.tgz", - "integrity": "sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==", "dev": true, + "license": "Apache-2.0", "dependencies": { "async": "^3.2.3", "chalk": "^4.0.2", @@ -3347,9 +3181,8 @@ }, "node_modules/jake/node_modules/brace-expansion": { "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -3357,9 +3190,8 @@ }, "node_modules/jake/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": { "brace-expansion": "^1.1.7" }, @@ -3369,9 +3201,8 @@ }, "node_modules/jest": { "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", - "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", "dev": true, + "license": "MIT", "dependencies": { "@jest/core": "^29.7.0", "@jest/types": "^29.6.3", @@ -3395,9 +3226,8 @@ }, "node_modules/jest-changed-files": { "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", - "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", "dev": true, + "license": "MIT", "dependencies": { "execa": "^5.0.0", "jest-util": "^29.7.0", @@ -3409,9 +3239,8 @@ }, "node_modules/jest-changed-files/node_modules/cross-spawn": { "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, + "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -3423,9 +3252,8 @@ }, "node_modules/jest-changed-files/node_modules/execa": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, + "license": "MIT", "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", @@ -3446,9 +3274,8 @@ }, "node_modules/jest-changed-files/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": { "node": ">=10" }, @@ -3458,9 +3285,8 @@ }, "node_modules/jest-changed-files/node_modules/is-stream": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -3470,9 +3296,8 @@ }, "node_modules/jest-changed-files/node_modules/npm-run-path": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, + "license": "MIT", "dependencies": { "path-key": "^3.0.0" }, @@ -3482,18 +3307,16 @@ }, "node_modules/jest-changed-files/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==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jest-changed-files/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==", "dev": true, + "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" }, @@ -3503,18 +3326,16 @@ }, "node_modules/jest-changed-files/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==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jest-changed-files/node_modules/which": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, + "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -3527,9 +3348,8 @@ }, "node_modules/jest-circus": { "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", - "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", "dev": true, + "license": "MIT", "dependencies": { "@jest/environment": "^29.7.0", "@jest/expect": "^29.7.0", @@ -3558,9 +3378,8 @@ }, "node_modules/jest-cli": { "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", - "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", "dev": true, + "license": "MIT", "dependencies": { "@jest/core": "^29.7.0", "@jest/test-result": "^29.7.0", @@ -3591,9 +3410,8 @@ }, "node_modules/jest-config": { "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", - "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/core": "^7.11.6", "@jest/test-sequencer": "^29.7.0", @@ -3636,9 +3454,8 @@ }, "node_modules/jest-diff": { "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", - "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^4.0.0", "diff-sequences": "^29.6.3", @@ -3651,9 +3468,8 @@ }, "node_modules/jest-docblock": { "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", - "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", "dev": true, + "license": "MIT", "dependencies": { "detect-newline": "^3.0.0" }, @@ -3663,9 +3479,8 @@ }, "node_modules/jest-each": { "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", - "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", "dev": true, + "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", "chalk": "^4.0.0", @@ -3679,9 +3494,8 @@ }, "node_modules/jest-environment-node": { "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", - "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", "dev": true, + "license": "MIT", "dependencies": { "@jest/environment": "^29.7.0", "@jest/fake-timers": "^29.7.0", @@ -3696,18 +3510,16 @@ }, "node_modules/jest-get-type": { "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", - "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", "dev": true, + "license": "MIT", "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-haste-map": { "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", - "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", "dev": true, + "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", "@types/graceful-fs": "^4.1.3", @@ -3730,9 +3542,8 @@ }, "node_modules/jest-leak-detector": { "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", - "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", "dev": true, + "license": "MIT", "dependencies": { "jest-get-type": "^29.6.3", "pretty-format": "^29.7.0" @@ -3743,9 +3554,8 @@ }, "node_modules/jest-matcher-utils": { "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", - "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^4.0.0", "jest-diff": "^29.7.0", @@ -3758,9 +3568,8 @@ }, "node_modules/jest-message-util": { "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", - "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", "dev": true, + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.12.13", "@jest/types": "^29.6.3", @@ -3778,9 +3587,8 @@ }, "node_modules/jest-mock": { "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", - "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", "dev": true, + "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", "@types/node": "*", @@ -3792,9 +3600,8 @@ }, "node_modules/jest-pnp-resolver": { "version": "1.2.3", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", - "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" }, @@ -3809,18 +3616,16 @@ }, "node_modules/jest-regex-util": { "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", - "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", "dev": true, + "license": "MIT", "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-resolve": { "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", - "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^4.0.0", "graceful-fs": "^4.2.9", @@ -3838,9 +3643,8 @@ }, "node_modules/jest-resolve-dependencies": { "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", - "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", "dev": true, + "license": "MIT", "dependencies": { "jest-regex-util": "^29.6.3", "jest-snapshot": "^29.7.0" @@ -3851,9 +3655,8 @@ }, "node_modules/jest-runner": { "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", - "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", "dev": true, + "license": "MIT", "dependencies": { "@jest/console": "^29.7.0", "@jest/environment": "^29.7.0", @@ -3883,9 +3686,8 @@ }, "node_modules/jest-runtime": { "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", - "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", "dev": true, + "license": "MIT", "dependencies": { "@jest/environment": "^29.7.0", "@jest/fake-timers": "^29.7.0", @@ -3916,9 +3718,8 @@ }, "node_modules/jest-snapshot": { "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", - "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/core": "^7.11.6", "@babel/generator": "^7.7.2", @@ -3947,9 +3748,8 @@ }, "node_modules/jest-util": { "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", - "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", "dev": true, + "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", "@types/node": "*", @@ -3964,9 +3764,8 @@ }, "node_modules/jest-validate": { "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", - "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", "dev": true, + "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", "camelcase": "^6.2.0", @@ -3981,9 +3780,8 @@ }, "node_modules/jest-validate/node_modules/camelcase": { "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -3993,9 +3791,8 @@ }, "node_modules/jest-watcher": { "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", - "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", "dev": true, + "license": "MIT", "dependencies": { "@jest/test-result": "^29.7.0", "@jest/types": "^29.6.3", @@ -4012,9 +3809,8 @@ }, "node_modules/jest-worker": { "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", - "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*", "jest-util": "^29.7.0", @@ -4027,9 +3823,8 @@ }, "node_modules/jest-worker/node_modules/supports-color": { "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -4042,15 +3837,13 @@ }, "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 + "dev": true, + "license": "MIT" }, "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": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -4061,9 +3854,8 @@ }, "node_modules/jsesc": { "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "dev": true, + "license": "MIT", "bin": { "jsesc": "bin/jsesc" }, @@ -4078,15 +3870,13 @@ }, "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 + "dev": true, + "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": { "json5": "lib/cli.js" }, @@ -4096,8 +3886,7 @@ }, "node_modules/jsonpath": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/jsonpath/-/jsonpath-1.1.1.tgz", - "integrity": "sha512-l6Cg7jRpixfbgoWgkrl77dgEj8RPvND0wMH6TwQmi9Qs4TFfS9u5cUFnbeKTwj5ga5Y3BTGGNI28k117LJ009w==", + "license": "MIT", "dependencies": { "esprima": "1.2.2", "static-eval": "2.0.2", @@ -4106,8 +3895,6 @@ }, "node_modules/jsonpath/node_modules/esprima": { "version": "1.2.2", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.2.tgz", - "integrity": "sha512-+JpPZam9w5DuJ3Q67SqsMGtiHKENSMRVoxvArfJZK01/BfLEObtZ6orJa/MtoGNR/rfMgp5837T41PAmTwAv/A==", "bin": { "esparse": "bin/esparse.js", "esvalidate": "bin/esvalidate.js" @@ -4126,26 +3913,23 @@ }, "node_modules/kleur": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/leven": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/levn": { "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "license": "MIT", "dependencies": { "prelude-ls": "~1.1.2", "type-check": "~0.3.2" @@ -4156,15 +3940,13 @@ }, "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 + "dev": true, + "license": "MIT" }, "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==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^4.1.0" }, @@ -4174,9 +3956,8 @@ }, "node_modules/lodash.memoize": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lodash.merge": { "version": "4.6.2", @@ -4201,9 +3982,8 @@ }, "node_modules/make-dir": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", "dev": true, + "license": "MIT", "dependencies": { "semver": "^7.5.3" }, @@ -4216,15 +3996,13 @@ }, "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 + "dev": true, + "license": "ISC" }, "node_modules/makeerror": { "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "tmpl": "1.0.5" } @@ -4335,9 +4113,8 @@ }, "node_modules/natural-compare": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/negotiator": { "version": "0.6.3", @@ -4381,21 +4158,18 @@ }, "node_modules/node-int64": { "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/node-releases": { "version": "2.0.18", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", - "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/normalize-path": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -4463,8 +4237,7 @@ }, "node_modules/optionator": { "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "license": "MIT", "dependencies": { "deep-is": "~0.1.3", "fast-levenshtein": "~2.0.6", @@ -4506,9 +4279,8 @@ }, "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": { "yocto-queue": "^0.1.0" }, @@ -4521,9 +4293,8 @@ }, "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==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^2.2.0" }, @@ -4533,9 +4304,8 @@ }, "node_modules/p-locate/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==", "dev": true, + "license": "MIT", "dependencies": { "p-try": "^2.0.0" }, @@ -4548,18 +4318,16 @@ }, "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==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "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": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -4582,18 +4350,16 @@ }, "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==", "dev": true, + "license": "MIT", "engines": { "node": ">=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": { "node": ">=0.10.0" } @@ -4608,9 +4374,8 @@ }, "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==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/path-to-regexp": { "version": "0.1.7", @@ -4630,9 +4395,8 @@ }, "node_modules/picocolors": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", - "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.1", @@ -4655,18 +4419,16 @@ }, "node_modules/pirates": { "version": "4.0.6", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", - "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 6" } }, "node_modules/pkg-dir": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", "dev": true, + "license": "MIT", "dependencies": { "find-up": "^4.0.0" }, @@ -4676,8 +4438,6 @@ }, "node_modules/prelude-ls": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", "engines": { "node": ">= 0.8.0" } @@ -4698,9 +4458,8 @@ }, "node_modules/pretty-format": { "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, + "license": "MIT", "dependencies": { "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", @@ -4712,9 +4471,8 @@ }, "node_modules/pretty-format/node_modules/ansi-styles": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -4724,9 +4482,8 @@ }, "node_modules/prompts": { "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", "dev": true, + "license": "MIT", "dependencies": { "kleur": "^3.0.3", "sisteransi": "^1.0.5" @@ -4762,8 +4519,6 @@ }, "node_modules/pure-rand": { "version": "6.1.0", - "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", - "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", "dev": true, "funding": [ { @@ -4774,7 +4529,8 @@ "type": "opencollective", "url": "https://opencollective.com/fast-check" } - ] + ], + "license": "MIT" }, "node_modules/qs": { "version": "6.11.0", @@ -4841,9 +4597,8 @@ }, "node_modules/react-is": { "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/readable-stream": { "version": "3.6.2", @@ -4875,18 +4630,16 @@ }, "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==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/resolve": { "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dev": true, + "license": "MIT", "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", @@ -4906,9 +4659,8 @@ }, "node_modules/resolve-cwd": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", "dev": true, + "license": "MIT", "dependencies": { "resolve-from": "^5.0.0" }, @@ -4918,18 +4670,16 @@ }, "node_modules/resolve-from": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/resolve.exports": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", - "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" } @@ -5134,9 +4884,8 @@ }, "node_modules/sisteransi": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/slash": { "version": "3.0.0", @@ -5178,9 +4927,8 @@ }, "node_modules/source-map-support": { "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", "dev": true, + "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -5188,24 +4936,21 @@ }, "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": { "node": ">=0.10.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 + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/stack-utils": { "version": "2.0.6", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", - "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", "dev": true, + "license": "MIT", "dependencies": { "escape-string-regexp": "^2.0.0" }, @@ -5215,17 +4960,15 @@ }, "node_modules/stack-utils/node_modules/escape-string-regexp": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/static-eval": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/static-eval/-/static-eval-2.0.2.tgz", - "integrity": "sha512-N/D219Hcr2bPjLxPiV+TQE++Tsmrady7TqAJugLy7Xk1EumfDWS/f5dtBbkRCGE7wKKXuYockQoj8Rm2/pVKyg==", + "license": "MIT", "dependencies": { "escodegen": "^1.8.1" } @@ -5247,9 +4990,8 @@ }, "node_modules/string-length": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", "dev": true, + "license": "MIT", "dependencies": { "char-regex": "^1.0.2", "strip-ansi": "^6.0.0" @@ -5260,9 +5002,8 @@ }, "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==", "dev": true, + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -5274,9 +5015,8 @@ }, "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==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -5286,9 +5026,8 @@ }, "node_modules/strip-bom": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -5311,9 +5050,8 @@ }, "node_modules/strip-json-comments": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -5350,9 +5088,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": { "has-flag": "^4.0.0" }, @@ -5362,9 +5099,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==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -5374,9 +5110,8 @@ }, "node_modules/test-exclude": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", "dev": true, + "license": "ISC", "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", @@ -5388,9 +5123,8 @@ }, "node_modules/test-exclude/node_modules/brace-expansion": { "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -5398,9 +5132,8 @@ }, "node_modules/test-exclude/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": { "brace-expansion": "^1.1.7" }, @@ -5410,15 +5143,13 @@ }, "node_modules/tmpl": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/to-fast-properties": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -5474,9 +5205,8 @@ }, "node_modules/ts-jest": { "version": "29.2.4", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.2.4.tgz", - "integrity": "sha512-3d6tgDyhCI29HlpwIq87sNuI+3Q6GLTTCeYRHCs7vDz+/3GCMwEtV9jezLyl4ZtnBgx00I7hm8PCP8cTksMGrw==", "dev": true, + "license": "MIT", "dependencies": { "bs-logger": "0.x", "ejs": "^3.1.10", @@ -5528,21 +5258,9 @@ "version": "2.6.3", "license": "0BSD" }, - "node_modules/tslog": { - "version": "4.9.3", - "resolved": "https://registry.npmjs.org/tslog/-/tslog-4.9.3.tgz", - "integrity": "sha512-oDWuGVONxhVEBtschLf2cs/Jy8i7h1T+CpdkTNWQgdAF7DhRo2G8vMCgILKe7ojdEkLhICWgI1LYSSKaJsRgcw==", - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/fullstack-build/tslog?sponsor=1" - } - }, "node_modules/type-check": { "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "license": "MIT", "dependencies": { "prelude-ls": "~1.1.2" }, @@ -5552,18 +5270,16 @@ }, "node_modules/type-detect": { "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/type-fest": { "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", "dev": true, + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -5596,8 +5312,7 @@ }, "node_modules/underscore": { "version": "1.12.1", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.12.1.tgz", - "integrity": "sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==" + "license": "MIT" }, "node_modules/undici-types": { "version": "5.26.5", @@ -5613,8 +5328,6 @@ }, "node_modules/update-browserslist-db": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", - "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", "dev": true, "funding": [ { @@ -5630,6 +5343,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { "escalade": "^3.1.2", "picocolors": "^1.0.1" @@ -5655,9 +5369,8 @@ }, "node_modules/v8-to-istanbul": { "version": "9.3.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", - "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", "dev": true, + "license": "ISC", "dependencies": { "@jridgewell/trace-mapping": "^0.3.12", "@types/istanbul-lib-coverage": "^2.0.1", @@ -5676,9 +5389,8 @@ }, "node_modules/walker": { "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { "makeerror": "1.0.12" } @@ -5719,17 +5431,15 @@ }, "node_modules/word-wrap": { "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/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==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -5749,9 +5459,8 @@ }, "node_modules/write-file-atomic": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", - "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", "dev": true, + "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4", "signal-exit": "^3.0.7" @@ -5762,9 +5471,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==", "dev": true, + "license": "ISC", "engines": { "node": ">=10" } @@ -5786,9 +5494,8 @@ }, "node_modules/yargs": { "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, + "license": "MIT", "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", @@ -5804,18 +5511,16 @@ }, "node_modules/yargs-parser": { "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true, + "license": "ISC", "engines": { "node": ">=12" } }, "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": { "node": ">=10" }, diff --git a/container-runtime/readme.md b/container-runtime/readme.md deleted file mode 100644 index 023091463..000000000 --- a/container-runtime/readme.md +++ /dev/null @@ -1,86 +0,0 @@ -## Testing - -So, we are going to - -1. create a fake server -2. pretend socket server os (while the fake server is running) -3. Run a fake effects system (while 1/2 are running) - -In order to simulate that we created a server like the start-os and -a fake server (in this case I am using syncthing-wrapper) - -### TODO - -Undo the packing that I have done earlier, and hijack the embassy.js to use the bundle service + code - -Converting embassy.js -> service.js - -```sequence {theme="hand"} -startOs ->> startInit.js: Rpc Call -startInit.js ->> service.js: Rpc Converted into js code -``` - -### Create a fake server - -```bash -run_test () { - ( - set -e - libs=/home/jh/Projects/start-os/libs/start_init - sockets=/tmp/start9 - service=/home/jh/Projects/syncthing-wrapper - - docker run \ - -v $libs:/libs \ - -v $service:/service \ - -w /libs \ - --rm node:18-alpine \ - sh -c " - npm i && - npm run bundle:esbuild && - npm run bundle:service - " - - - - docker run \ - -v ./libs/start_init/:/libs \ - -w /libs \ - --rm node:18-alpine \ - sh -c " - npm i && - npm run bundle:esbuild - " - - - - rm -rf $sockets || true - mkdir -p $sockets/sockets - cd $service - docker run \ - -v $libs:/start-init \ - -v $sockets:/start9 \ - --rm -it $(docker build -q .) sh -c " - apk add nodejs && - node /start-init/bundleEs.js - " - ) -} -run_test -``` - -### Pretend Socket Server OS - -First we are going to create our fake server client with the bash then send it the json possible data - -```bash -sudo socat - unix-client:/tmp/start9/sockets/rpc.sock -``` - - -```json -{"id":"a","method":"run","params":{"methodName":"/dependencyMounts","methodArgs":[]}} -{"id":"a","method":"run","params":{"methodName":"/actions/test","methodArgs":{"input":{"id": 1}}}} -{"id":"b","method":"run","params":{"methodName":"/actions/test","methodArgs":{"id": 1}}} - -``` diff --git a/container-runtime/src/Adapters/EffectCreator.ts b/container-runtime/src/Adapters/EffectCreator.ts index e0390b1e1..0123b0cbc 100644 --- a/container-runtime/src/Adapters/EffectCreator.ts +++ b/container-runtime/src/Adapters/EffectCreator.ts @@ -4,7 +4,7 @@ import { object, string, number, literals, some, unknown } from "ts-matches" import { Effects } from "../Models/Effects" import { CallbackHolder } from "../Models/CallbackHolder" -import { MainEffects } from "@start9labs/start-sdk/cjs/lib/StartSdk" +import { asError } from "@start9labs/start-sdk/base/lib/util" const matchRpcError = object({ error: object( { @@ -35,7 +35,8 @@ let hostSystemId = 0 export type EffectContext = { procedureId: string | null - callbacks: CallbackHolder | null + callbacks?: CallbackHolder + constRetry: () => void } const rpcRoundFor = @@ -50,7 +51,7 @@ const rpcRoundFor = JSON.stringify({ id, method, - params: { ...params, procedureId }, + params: { ...params, procedureId: procedureId || undefined }, }) + "\n", ) }) @@ -67,7 +68,7 @@ const rpcRoundFor = let message = res.error.message console.error( "Error in host RPC:", - utils.asError({ method, params }), + utils.asError({ method, params, error: res.error }), ) if (string.test(res.error.data)) { message += ": " + res.error.data @@ -100,24 +101,64 @@ const rpcRoundFor = }) } -function makeEffects(context: EffectContext): Effects { +export function makeEffects(context: EffectContext): Effects { const rpcRound = rpcRoundFor(context.procedureId) const self: Effects = { + constRetry: context.constRetry, + clearCallbacks(...[options]: Parameters) { + return rpcRound("clear-callbacks", { + ...options, + }) as ReturnType + }, + action: { + clear(...[options]: Parameters) { + return rpcRound("action.clear", { + ...options, + }) as ReturnType + }, + export(...[options]: Parameters) { + return rpcRound("action.export", { + ...options, + }) as ReturnType + }, + getInput(...[options]: Parameters) { + return rpcRound("action.get-input", { + ...options, + }) as ReturnType + }, + request(...[options]: Parameters) { + return rpcRound("action.request", { + ...options, + }) as ReturnType + }, + run(...[options]: Parameters) { + return rpcRound("action.run", { + ...options, + }) as ReturnType + }, + clearRequests( + ...[options]: Parameters + ) { + return rpcRound("action.clear-requests", { + ...options, + }) as ReturnType + }, + }, bind(...[options]: Parameters) { return rpcRound("bind", { ...options, stack: new Error().stack, }) as ReturnType }, - clearBindings(...[]: Parameters) { - return rpcRound("clear-bindings", {}) as ReturnType< + clearBindings(...[options]: Parameters) { + return rpcRound("clear-bindings", { ...options }) as ReturnType< T.Effects["clearBindings"] > }, clearServiceInterfaces( - ...[]: Parameters + ...[options]: Parameters ) { - return rpcRound("clear-service-interfaces", {}) as ReturnType< + return rpcRound("clear-service-interfaces", { ...options }) as ReturnType< T.Effects["clearServiceInterfaces"] > }, @@ -127,27 +168,17 @@ function makeEffects(context: EffectContext): Effects { > }, subcontainer: { - createFs(options: { imageId: string }) { + createFs(options: { imageId: string; name: string }) { return rpcRound("subcontainer.create-fs", options) as ReturnType< T.Effects["subcontainer"]["createFs"] > }, - destroyFs(options: { guid: string }): Promise { + destroyFs(options: { guid: string }): Promise { return rpcRound("subcontainer.destroy-fs", options) as ReturnType< T.Effects["subcontainer"]["destroyFs"] > }, }, - executeAction(...[options]: Parameters) { - return rpcRound("execute-action", options) as ReturnType< - T.Effects["executeAction"] - > - }, - exportAction(...[options]: Parameters) { - return rpcRound("export-action", options) as ReturnType< - T.Effects["exportAction"] - > - }, exportServiceInterface: (( ...[options]: Parameters ) => { @@ -162,11 +193,6 @@ function makeEffects(context: EffectContext): Effects { T.Effects["exposeForDependents"] > }, - getConfigured(...[]: Parameters) { - return rpcRound("get-configured", {}) as ReturnType< - T.Effects["getConfigured"] - > - }, getContainerIp(...[]: Parameters) { return rpcRound("get-container-ip", {}) as ReturnType< T.Effects["getContainerIp"] @@ -230,19 +256,9 @@ function makeEffects(context: EffectContext): Effects { mount(...[options]: Parameters) { return rpcRound("mount", options) as ReturnType }, - clearActions(...[]: Parameters) { - return rpcRound("clear-actions", {}) as ReturnType< - T.Effects["clearActions"] - > - }, restart(...[]: Parameters) { return rpcRound("restart", {}) as ReturnType }, - setConfigured(...[configured]: Parameters) { - return rpcRound("set-configured", { configured }) as ReturnType< - T.Effects["setConfigured"] - > - }, setDependencies( dependencies: Parameters[0], ): ReturnType { @@ -268,7 +284,10 @@ function makeEffects(context: EffectContext): Effects { > }, - setMainStatus(o: { status: "running" | "stopped" }): Promise { + getStatus(...[o]: Parameters) { + return rpcRound("get-status", o) as ReturnType + }, + setMainStatus(o: { status: "running" | "stopped" }): Promise { return rpcRound("set-main-status", o) as ReturnType< T.Effects["setHealth"] > @@ -299,18 +318,3 @@ function makeEffects(context: EffectContext): Effects { } return self } - -export function makeProcedureEffects(procedureId: string): Effects { - return makeEffects({ procedureId, callbacks: null }) -} - -export function makeMainEffects(): MainEffects { - const rpcRound = rpcRoundFor(null) - return { - _type: "main", - clearCallbacks: () => { - return rpcRound("clearCallbacks", {}) as Promise - }, - ...makeEffects({ procedureId: null, callbacks: new CallbackHolder() }), - } -} diff --git a/container-runtime/src/Adapters/RpcListener.ts b/container-runtime/src/Adapters/RpcListener.ts index 860f1c066..3e86e60d1 100644 --- a/container-runtime/src/Adapters/RpcListener.ts +++ b/container-runtime/src/Adapters/RpcListener.ts @@ -14,17 +14,14 @@ import { anyOf, } from "ts-matches" -import { types as T } from "@start9labs/start-sdk" +import { types as T, utils } from "@start9labs/start-sdk" import * as fs from "fs" import { CallbackHolder } from "../Models/CallbackHolder" import { AllGetDependencies } from "../Interfaces/AllGetDependencies" import { jsonPath, unNestPath } from "../Models/JsonPath" -import { RunningMain, System } from "../Interfaces/System" -import { - MakeMainEffects, - MakeProcedureEffects, -} from "../Interfaces/MakeEffects" +import { System } from "../Interfaces/System" +import { makeEffects } from "./EffectCreator" type MaybePromise = T | Promise export const matchRpcResult = anyOf( object({ result: any }), @@ -45,6 +42,7 @@ export const matchRpcResult = anyOf( ), }), ) + export type RpcResult = typeof matchRpcResult._TYPE type SocketResponse = ({ jsonrpc: "2.0"; id: IdType } & RpcResult) | null @@ -55,73 +53,96 @@ const jsonrpc = "2.0" as const const isResult = object({ result: any }).test const idType = some(string, number, literal(null)) -type IdType = null | string | number -const runType = object({ - id: idType, - method: literal("execute"), - params: object( - { - id: string, - procedure: string, - input: any, - timeout: number, - }, - ["timeout"], - ), -}) -const sandboxRunType = object({ - id: idType, - method: literal("sandbox"), - params: object( - { - id: string, - procedure: string, - input: any, - timeout: number, - }, - ["timeout"], - ), -}) +type IdType = null | string | number | undefined +const runType = object( + { + id: idType, + method: literal("execute"), + params: object( + { + id: string, + procedure: string, + input: any, + timeout: number, + }, + ["timeout"], + ), + }, + ["id"], +) +const sandboxRunType = object( + { + id: idType, + method: literal("sandbox"), + params: object( + { + id: string, + procedure: string, + input: any, + timeout: number, + }, + ["timeout"], + ), + }, + ["id"], +) const callbackType = object({ method: literal("callback"), params: object({ - callback: number, + id: number, args: array, }), }) -const initType = object({ - id: idType, - method: literal("init"), -}) -const startType = object({ - id: idType, - method: literal("start"), -}) -const stopType = object({ - id: idType, - method: literal("stop"), -}) -const exitType = object({ - id: idType, - method: literal("exit"), -}) -const evalType = object({ - id: idType, - method: literal("eval"), - params: object({ - script: string, - }), -}) +const initType = object( + { + id: idType, + method: literal("init"), + }, + ["id"], +) +const startType = object( + { + id: idType, + method: literal("start"), + }, + ["id"], +) +const stopType = object( + { + id: idType, + method: literal("stop"), + }, + ["id"], +) +const exitType = object( + { + id: idType, + method: literal("exit"), + }, + ["id"], +) +const evalType = object( + { + id: idType, + method: literal("eval"), + params: object({ + script: string, + }), + }, + ["id"], +) const jsonParse = (x: string) => JSON.parse(x) const handleRpc = (id: IdType, result: Promise) => result - .then((result) => ({ - jsonrpc, - id, - ...result, - })) + .then((result) => { + return { + jsonrpc, + id, + ...result, + } + }) .then((x) => { if ( ("result" in x && x.result === undefined) || @@ -144,8 +165,7 @@ const hasId = object({ id: idType }).test export class RpcListener { unixSocketServer = net.createServer(async (server) => {}) private _system: System | undefined - private _makeProcedureEffects: MakeProcedureEffects | undefined - private _makeMainEffects: MakeMainEffects | undefined + private callbacks: CallbackHolder | undefined constructor(readonly getDependencies: AllGetDependencies) { if (!fs.existsSync(SOCKET_PARENT)) { @@ -198,7 +218,11 @@ export class RpcListener { .then((x) => this.dealWithInput(x)) .catch(mapError) .then(logData("response")) - .then(writeDataToSocket), + .then(writeDataToSocket) + .catch((e) => { + console.error(`Major error in socket handling: ${e}`) + console.debug(`Data in: ${a.toString()}`) + }), ) }) } @@ -208,18 +232,33 @@ export class RpcListener { return this._system } - private get makeProcedureEffects() { - if (!this._makeProcedureEffects) { - this._makeProcedureEffects = this.getDependencies.makeProcedureEffects() + private callbackHolders: Map = new Map() + private removeCallbackHolderFor(procedure: string) { + const prev = this.callbackHolders.get(procedure) + if (prev) { + this.callbackHolders.delete(procedure) + this.callbacks?.removeChild(prev) } - return this._makeProcedureEffects + } + private callbackHolderFor(procedure: string): CallbackHolder { + this.removeCallbackHolderFor(procedure) + const callbackHolder = this.callbacks!.child() + this.callbackHolders.set(procedure, callbackHolder) + return callbackHolder } - private get makeMainEffects() { - if (!this._makeMainEffects) { - this._makeMainEffects = this.getDependencies.makeMainEffects() + callCallback(callback: number, args: any[]): void { + if (this.callbacks) { + this.callbacks + .callCallback(callback, args) + .catch((error) => + console.error(`callback ${callback} failed`, utils.asError(error)), + ) + } else { + console.warn( + `callback ${callback} ignored because system is not initialized`, + ) } - return this._makeMainEffects } private dealWithInput(input: unknown): MaybePromise { @@ -227,40 +266,49 @@ export class RpcListener { .when(runType, async ({ id, params }) => { const system = this.system const procedure = jsonPath.unsafeCast(params.procedure) - const effects = this.getDependencies.makeProcedureEffects()(params.id) - const input = params.input - const timeout = params.timeout - const result = getResult(procedure, system, effects, timeout, input) + const { input, timeout, id: procedureId } = params + const result = this.getResult( + procedure, + system, + procedureId, + timeout, + input, + ) return handleRpc(id, result) }) .when(sandboxRunType, async ({ id, params }) => { const system = this.system const procedure = jsonPath.unsafeCast(params.procedure) - const effects = this.makeProcedureEffects(params.id) - const result = getResult( + const { input, timeout, id: procedureId } = params + const result = this.getResult( procedure, system, - effects, - params.input, - params.input, + procedureId, + timeout, + input, ) return handleRpc(id, result) }) - .when(callbackType, async ({ params: { callback, args } }) => { - this.system.callCallback(callback, args) + .when(callbackType, async ({ params: { id, args } }) => { + this.callCallback(id, args) return null }) .when(startType, async ({ id }) => { + const callbacks = this.callbackHolderFor("main") + const effects = makeEffects({ + procedureId: null, + callbacks, + constRetry: () => {}, + }) return handleRpc( id, - this.system - .start(this.makeMainEffects()) - .then((result) => ({ result })), + this.system.start(effects).then((result) => ({ result })), ) }) .when(stopType, async ({ id }) => { + this.removeCallbackHolderFor("main") return handleRpc( id, this.system.stop().then((result) => ({ result })), @@ -280,7 +328,20 @@ export class RpcListener { (async () => { if (!this._system) { const system = await this.getDependencies.system() - await system.containerInit() + this.callbacks = new CallbackHolder( + makeEffects({ + procedureId: null, + constRetry: () => {}, + }), + ) + const callbacks = this.callbackHolderFor("containerInit") + await system.containerInit( + makeEffects({ + procedureId: null, + callbacks, + constRetry: () => {}, + }), + ) this._system = system } })().then((result) => ({ result })), @@ -312,17 +373,20 @@ export class RpcListener { })(), ) }) - .when(shape({ id: idType, method: string }), ({ id, method }) => ({ - jsonrpc, - id, - error: { - code: -32601, - message: `Method not found`, - data: { - details: method, + .when( + shape({ id: idType, method: string }, ["id"]), + ({ id, method }) => ({ + jsonrpc, + id, + error: { + code: -32601, + message: `Method not found`, + data: { + details: method, + }, }, - }, - })) + }), + ) .defaultToLazy(() => { console.warn( @@ -341,98 +405,81 @@ export class RpcListener { } }) } -} -function getResult( - procedure: typeof jsonPath._TYPE, - system: System, - effects: T.Effects, - timeout: number | undefined, - input: any, -) { - const ensureResultTypeShape = ( - result: - | void - | T.ConfigRes - | T.PropertiesReturn - | T.ActionMetadata[] - | T.ActionResult, - ): { result: any } => { - if (isResult(result)) return result - return { result } - } - return (async () => { - switch (procedure) { - case "/backup/create": - return system.createBackup(effects, timeout || null) - case "/backup/restore": - return system.restoreBackup(effects, timeout || null) - case "/config/get": - return system.getConfig(effects, timeout || null) - case "/config/set": - return system.setConfig(effects, input, timeout || null) - case "/properties": - return system.properties(effects, timeout || null) - case "/actions/metadata": - return system.actionsMetadata(effects) - case "/init": - return system.packageInit( - effects, - string.optional().unsafeCast(input), - timeout || null, - ) - case "/uninit": - return system.packageUninit( - effects, - string.optional().unsafeCast(input), - timeout || null, - ) - default: - const procedures = unNestPath(procedure) - switch (true) { - case procedures[1] === "actions" && procedures[3] === "get": - return system.action(effects, procedures[2], input, timeout || null) - case procedures[1] === "actions" && procedures[3] === "run": - return system.action(effects, procedures[2], input, timeout || null) - case procedures[1] === "dependencies" && procedures[3] === "query": - return system.dependenciesAutoconfig( - effects, - procedures[2], - input, - timeout || null, - ) - - case procedures[1] === "dependencies" && procedures[3] === "update": - return system.dependenciesAutoconfig( - effects, - procedures[2], - input, - timeout || null, - ) - } + private getResult( + procedure: typeof jsonPath._TYPE, + system: System, + procedureId: string, + timeout: number | undefined, + input: any, + ) { + const ensureResultTypeShape = ( + result: void | T.ActionInput | T.ActionResult | null, + ): { result: any } => { + return { result } } - })().then(ensureResultTypeShape, (error) => - matches(error) - .when( - object( - { - error: string, - code: number, - }, - ["code"], - { code: 0 }, - ), - (error) => ({ + const callbacks = this.callbackHolderFor(procedure) + const effects = makeEffects({ + procedureId, + callbacks, + constRetry: () => {}, + }) + + return (async () => { + switch (procedure) { + case "/backup/create": + return system.createBackup(effects, timeout || null) + case "/backup/restore": + return system.restoreBackup(effects, timeout || null) + case "/packageInit": + return system.packageInit(effects, timeout || null) + case "/packageUninit": + return system.packageUninit( + effects, + string.optional().unsafeCast(input), + timeout || null, + ) + default: + const procedures = unNestPath(procedure) + switch (true) { + case procedures[1] === "actions" && procedures[3] === "getInput": + return system.getActionInput( + effects, + procedures[2], + timeout || null, + ) + case procedures[1] === "actions" && procedures[3] === "run": + return system.runAction( + effects, + procedures[2], + input.input, + timeout || null, + ) + } + } + })().then(ensureResultTypeShape, (error) => + matches(error) + .when( + object( + { + error: string, + code: number, + }, + ["code"], + { code: 0 }, + ), + (error) => ({ + error: { + code: error.code, + message: error.error, + }, + }), + ) + .defaultToLazy(() => ({ error: { - code: error.code, - message: error.error, + code: 0, + message: String(error), }, - }), - ) - .defaultToLazy(() => ({ - error: { - code: 0, - message: String(error), - }, - })), - ) + })), + ) + } } diff --git a/container-runtime/src/Adapters/Systems/SystemForEmbassy/DockerProcedureContainer.ts b/container-runtime/src/Adapters/Systems/SystemForEmbassy/DockerProcedureContainer.ts index 805f9b531..26e4dd8bf 100644 --- a/container-runtime/src/Adapters/Systems/SystemForEmbassy/DockerProcedureContainer.ts +++ b/container-runtime/src/Adapters/Systems/SystemForEmbassy/DockerProcedureContainer.ts @@ -8,7 +8,7 @@ import { CommandOptions, ExecOptions, ExecSpawnable, -} from "@start9labs/start-sdk/cjs/lib/util/SubContainer" +} from "@start9labs/start-sdk/package/lib/util/SubContainer" export const exec = promisify(cp.exec) export const execFile = promisify(cp.execFile) @@ -20,6 +20,7 @@ export class DockerProcedureContainer { packageId: string, data: DockerProcedure, volumes: { [id: VolumeId]: Volume }, + name: string, options: { subcontainer?: ExecSpawnable } = {}, ) { const subcontainer = @@ -29,6 +30,7 @@ export class DockerProcedureContainer { packageId, data, volumes, + name, )) return new DockerProcedureContainer(subcontainer) } @@ -37,8 +39,13 @@ export class DockerProcedureContainer { packageId: string, data: DockerProcedure, volumes: { [id: VolumeId]: Volume }, + name: string, ) { - const subcontainer = await SubContainer.of(effects, { id: data.image }) + const subcontainer = await SubContainer.of( + effects, + { id: data.image }, + name, + ) if (data.mounts) { const mounts = data.mounts @@ -144,7 +151,7 @@ export class DockerProcedureContainer { } } - async spawn(commands: string[]): Promise { + async spawn(commands: string[]): Promise { return await this.subcontainer.spawn(commands) } } diff --git a/container-runtime/src/Adapters/Systems/SystemForEmbassy/MainLoop.ts b/container-runtime/src/Adapters/Systems/SystemForEmbassy/MainLoop.ts index e5aaacfdb..b6fe39854 100644 --- a/container-runtime/src/Adapters/Systems/SystemForEmbassy/MainLoop.ts +++ b/container-runtime/src/Adapters/Systems/SystemForEmbassy/MainLoop.ts @@ -2,11 +2,10 @@ import { polyfillEffects } from "./polyfillEffects" import { DockerProcedureContainer } from "./DockerProcedureContainer" import { SystemForEmbassy } from "." import { T, utils } from "@start9labs/start-sdk" -import { Daemon } from "@start9labs/start-sdk/cjs/lib/mainFn/Daemon" +import { Daemon } from "@start9labs/start-sdk/package/lib/mainFn/Daemon" import { Effects } from "../../../Models/Effects" import { off } from "node:process" -import { CommandController } from "@start9labs/start-sdk/cjs/lib/mainFn/CommandController" -import { asError } from "@start9labs/start-sdk/cjs/lib/util" +import { CommandController } from "@start9labs/start-sdk/package/lib/mainFn/CommandController" const EMBASSY_HEALTH_INTERVAL = 15 * 1000 const EMBASSY_PROPERTIES_LOOP = 30 * 1000 @@ -62,6 +61,7 @@ export class MainLoop { this.system.manifest.id, this.system.manifest.main, this.system.manifest.volumes, + `Main - ${currentCommand.join(" ")}`, ) return CommandController.of()( this.effects, @@ -136,7 +136,7 @@ export class MainLoop { delete this.healthLoops await main?.daemon .stop() - .catch((e) => console.error(`Main loop error`, utils.asError(e))) + .catch((e: unknown) => console.error(`Main loop error`, utils.asError(e))) this.effects.setMainStatus({ status: "stopped" }) if (healthLoops) healthLoops.forEach((x) => clearInterval(x.interval)) } @@ -154,7 +154,7 @@ export class MainLoop { result: "starting", message: null, }) - .catch((e) => console.error(asError(e))) + .catch((e) => console.error(utils.asError(e))) const interval = setInterval(async () => { const actionProcedure = value const timeChanged = Date.now() - start @@ -162,21 +162,30 @@ export class MainLoop { const subcontainer = actionProcedure.inject ? this.mainSubContainerHandle : undefined - // prettier-ignore - const container = - await DockerProcedureContainer.of( - effects, - manifest.id, - actionProcedure, - manifest.volumes, - { - subcontainer, - } - ) - const executed = await container.exec( - [actionProcedure.entrypoint, ...actionProcedure.args], - { input: JSON.stringify(timeChanged) }, + const commands = [ + actionProcedure.entrypoint, + ...actionProcedure.args, + ] + const container = await DockerProcedureContainer.of( + effects, + manifest.id, + actionProcedure, + manifest.volumes, + `Health Check - ${commands.join(" ")}`, + { + subcontainer, + }, ) + const env: Record = actionProcedure.inject + ? { + HOME: "/root", + } + : {} + const executed = await container.exec(commands, { + input: JSON.stringify(timeChanged), + env, + }) + if (executed.exitCode === 0) { await effects.setHealth({ id: healthId, @@ -227,6 +236,18 @@ export class MainLoop { }) return } + if (executed.exitCode && executed.exitCode > 0) { + await effects.setHealth({ + id: healthId, + name: value.name, + result: "failure", + message: + executed.stderr.toString() || + executed.stdout.toString() || + `Program exited with code ${executed.exitCode}:`, + }) + return + } await effects.setHealth({ id: healthId, name: value.name, diff --git a/container-runtime/src/Adapters/Systems/SystemForEmbassy/__snapshots__/transformConfigSpec.test.ts.snap b/container-runtime/src/Adapters/Systems/SystemForEmbassy/__snapshots__/transformConfigSpec.test.ts.snap index 01e2d0763..2c3d4b167 100644 --- a/container-runtime/src/Adapters/Systems/SystemForEmbassy/__snapshots__/transformConfigSpec.test.ts.snap +++ b/container-runtime/src/Adapters/Systems/SystemForEmbassy/__snapshots__/transformConfigSpec.test.ts.snap @@ -264,7 +264,6 @@ exports[`transformConfigSpec transformConfigSpec(bitcoind) 1`] = ` "disabled": false, "immutable": false, "name": "Pruning Mode", - "required": true, "type": "union", "variants": { "automatic": { @@ -524,7 +523,6 @@ exports[`transformConfigSpec transformConfigSpec(embassyPages) 1`] = ` "disabled": false, "immutable": false, "name": "Type", - "required": true, "type": "union", "variants": { "index": { @@ -589,7 +587,6 @@ exports[`transformConfigSpec transformConfigSpec(embassyPages) 1`] = ` "disabled": false, "immutable": false, "name": "Folder Location", - "required": false, "type": "select", "values": { "filebrowser": "filebrowser", @@ -644,7 +641,6 @@ exports[`transformConfigSpec transformConfigSpec(embassyPages) 1`] = ` "disabled": false, "immutable": false, "name": "Type", - "required": true, "type": "union", "variants": { "redirect": { @@ -705,7 +701,6 @@ exports[`transformConfigSpec transformConfigSpec(embassyPages) 1`] = ` "disabled": false, "immutable": false, "name": "Folder Location", - "required": false, "type": "select", "values": { "filebrowser": "filebrowser", @@ -758,7 +753,6 @@ exports[`transformConfigSpec transformConfigSpec(nostr2) 1`] = ` "disabled": false, "immutable": false, "name": "Relay Type", - "required": true, "type": "union", "variants": { "private": { diff --git a/container-runtime/src/Adapters/Systems/SystemForEmbassy/index.ts b/container-runtime/src/Adapters/Systems/SystemForEmbassy/index.ts index 1e0c34189..531b30cd2 100644 --- a/container-runtime/src/Adapters/Systems/SystemForEmbassy/index.ts +++ b/container-runtime/src/Adapters/Systems/SystemForEmbassy/index.ts @@ -2,8 +2,8 @@ import { ExtendedVersion, types as T, utils } from "@start9labs/start-sdk" import * as fs from "fs/promises" import { polyfillEffects } from "./polyfillEffects" -import { Duration, duration, fromDuration } from "../../../Models/Duration" -import { System, Procedure } from "../../../Interfaces/System" +import { fromDuration } from "../../../Models/Duration" +import { System } from "../../../Interfaces/System" import { matchManifest, Manifest } from "./matchManifest" import * as childProcess from "node:child_process" import { DockerProcedureContainer } from "./DockerProcedureContainer" @@ -27,19 +27,12 @@ import { Parser, array, } from "ts-matches" -import { JsonPath, unNestPath } from "../../../Models/JsonPath" -import { RpcResult, matchRpcResult } from "../../RpcListener" -import { CT } from "@start9labs/start-sdk" -import { - AddSslOptions, - BindOptions, -} from "@start9labs/start-sdk/cjs/lib/osBindings" +import { AddSslOptions } from "@start9labs/start-sdk/base/lib/osBindings" import { BindOptionsByProtocol, - Host, MultiHost, -} from "@start9labs/start-sdk/cjs/lib/interfaces/Host" -import { ServiceInterfaceBuilder } from "@start9labs/start-sdk/cjs/lib/interfaces/ServiceInterfaceBuilder" +} from "@start9labs/start-sdk/base/lib/interfaces/Host" +import { ServiceInterfaceBuilder } from "@start9labs/start-sdk/base/lib/interfaces/ServiceInterfaceBuilder" import { Effects } from "../../../Models/Effects" import { OldConfigSpec, @@ -48,18 +41,16 @@ import { transformNewConfigToOld, transformOldConfigToNew, } from "./transformConfigSpec" -import { MainEffects } from "@start9labs/start-sdk/cjs/lib/StartSdk" -import { StorePath } from "@start9labs/start-sdk/cjs/lib/store/PathBuilder" +import { partialDiff } from "@start9labs/start-sdk/base/lib/util" type Optional = A | undefined | null function todo(): never { throw new Error("Not implemented") } -const execFile = promisify(childProcess.execFile) const MANIFEST_LOCATION = "/usr/lib/startos/package/embassyManifest.json" export const EMBASSY_JS_LOCATION = "/usr/lib/startos/package/embassy.js" -const EMBASSY_POINTER_PATH_PREFIX = "/embassyConfig" as StorePath +const EMBASSY_POINTER_PATH_PREFIX = "/embassyConfig" as utils.StorePath const matchResult = object({ result: any, @@ -144,6 +135,34 @@ type OldGetConfigRes = { spec: OldConfigSpec } +export type PropertiesValue = + | { + /** The type of this value, either "string" or "object" */ + type: "object" + /** A nested mapping of values. The user will experience this as a nested page with back button */ + value: { [k: string]: PropertiesValue } + /** (optional) A human readable description of the new set of values */ + description: string | null + } + | { + /** The type of this value, either "string" or "object" */ + type: "string" + /** The value to display to the user */ + value: string + /** A human readable description of the value */ + description: string | null + /** Whether or not to mask the value, for example, when displaying a password */ + masked: boolean | null + /** Whether or not to include a button for copying the value to clipboard */ + copyable: boolean | null + /** Whether or not to include a button for displaying the value as a QR code */ + qr: boolean | null + } + +export type PropertiesReturn = { + [key: string]: PropertiesValue +} + export type PackagePropertiesV2 = { [name: string]: PackagePropertyObject | PackagePropertyString } @@ -166,7 +185,7 @@ export type PackagePropertyObject = { const asProperty_ = ( x: PackagePropertyString | PackagePropertyObject, -): T.PropertiesValue => { +): PropertiesValue => { if (x.type === "object") { return { ...x, @@ -186,7 +205,7 @@ const asProperty_ = ( ...x, } } -const asProperty = (x: PackagePropertiesV2): T.PropertiesReturn => +const asProperty = (x: PackagePropertiesV2): PropertiesReturn => Object.fromEntries( Object.entries(x).map(([key, value]) => [key, asProperty_(value)]), ) @@ -223,6 +242,31 @@ const matchProperties = object({ data: matchPackageProperties, }) +function convertProperties( + name: string, + value: PropertiesValue, +): T.ActionResultMember { + if (value.type === "string") { + return { + type: "single", + name, + description: value.description, + copyable: value.copyable || false, + masked: value.masked || false, + qr: value.qr || false, + value: value.value, + } + } + return { + type: "group", + name, + description: value.description, + value: Object.entries(value.value).map(([name, value]) => + convertProperties(name, value), + ), + } +} + const DEFAULT_REGISTRY = "https://registry.start9.com" export class SystemForEmbassy implements System { currentRunning: MainLoop | undefined @@ -248,50 +292,38 @@ export class SystemForEmbassy implements System { readonly moduleCode: Partial, ) {} - async actionsMetadata(effects: T.Effects): Promise { - const actions = Object.entries(this.manifest.actions ?? {}) - return Promise.all( - actions.map(async ([actionId, action]): Promise => { - const name = action.name ?? actionId - const description = action.description - const warning = action.warning ?? null - const disabled = false - const input = (await convertToNewConfig(action["input-spec"] as any)) - .spec - const hasRunning = !!action["allowed-statuses"].find( - (x) => x === "running", - ) - const hasStopped = !!action["allowed-statuses"].find( - (x) => x === "stopped", - ) - // prettier-ignore - const allowedStatuses = - hasRunning && hasStopped ? "any": - hasRunning ? "onlyRunning" : - "onlyStopped" - - const group = null - return { - name, - description, - warning, - disabled, - allowedStatuses, - group, - input, - } - }), - ) + async containerInit(effects: Effects): Promise { + for (let depId in this.manifest.dependencies) { + if (this.manifest.dependencies[depId].config) { + await this.dependenciesAutoconfig(effects, depId, null) + } + } + await effects.setMainStatus({ status: "stopped" }) + await this.exportActions(effects) + await this.exportNetwork(effects) + await this.containerSetDependencies(effects) + } + async containerSetDependencies(effects: T.Effects) { + const oldDeps: Record = Object.fromEntries( + await effects + .getDependencies() + .then((x) => + x.flatMap((x) => + x.kind === "running" ? [[x.id, x?.healthChecks || []]] : [], + ), + ) + .catch(() => []), + ) + await this.setDependencies(effects, oldDeps) } - - async containerInit(): Promise {} async exit(): Promise { if (this.currentRunning) await this.currentRunning.clean() delete this.currentRunning } - async start(effects: MainEffects): Promise { + async start(effects: T.Effects): Promise { + effects.constRetry = utils.once(() => effects.restart()) if (!!this.currentRunning) return this.currentRunning = await MainLoop.of(this, effects) @@ -308,16 +340,26 @@ export class SystemForEmbassy implements System { } } - async packageInit( - effects: Effects, - previousVersion: Optional, - timeoutMs: number | null, - ): Promise { - if (previousVersion) - await this.migration(effects, previousVersion, timeoutMs) - await effects.setMainStatus({ status: "stopped" }) - await this.exportActions(effects) - await this.exportNetwork(effects) + async packageInit(effects: Effects, timeoutMs: number | null): Promise { + const previousVersion = await effects.getDataVersion() + if (previousVersion) { + if ( + (await this.migration(effects, previousVersion, timeoutMs)).configured + ) { + await effects.action.clearRequests({ only: ["needs-config"] }) + } + await effects.setDataVersion({ + version: ExtendedVersion.parseEmver(this.manifest.version).toString(), + }) + } else if (this.manifest.config) { + await effects.action.request({ + packageId: this.manifest.id, + actionId: "config", + severity: "critical", + replayId: "needs-config", + reason: "This service must be configured before it can be run", + }) + } } async exportNetwork(effects: Effects) { for (const [id, interfaceValue] of Object.entries( @@ -400,10 +442,75 @@ export class SystemForEmbassy implements System { ) } } + async getActionInput( + effects: Effects, + actionId: string, + timeoutMs: number | null, + ): Promise { + if (actionId === "config") { + const config = await this.getConfig(effects, timeoutMs) + return { spec: config.spec, value: config.config } + } else if (actionId === "properties") { + return null + } else { + const oldSpec = this.manifest.actions?.[actionId]?.["input-spec"] + if (!oldSpec) return null + return { + spec: transformConfigSpec(oldSpec as OldConfigSpec), + value: null, + } + } + } + async runAction( + effects: Effects, + actionId: string, + input: unknown, + timeoutMs: number | null, + ): Promise { + if (actionId === "config") { + await this.setConfig(effects, input, timeoutMs) + return null + } else if (actionId === "properties") { + return { + version: "1", + title: "Properties", + message: null, + result: { + type: "group", + value: Object.entries(await this.properties(effects, timeoutMs)).map( + ([name, value]) => convertProperties(name, value), + ), + }, + } + } else { + return this.action(effects, actionId, input, timeoutMs) + } + } async exportActions(effects: Effects) { const manifest = this.manifest - if (!manifest.actions) return - for (const [actionId, action] of Object.entries(manifest.actions)) { + const actions = { + ...manifest.actions, + } + if (manifest.config) { + actions.config = { + name: "Configure", + description: `Customize ${manifest.title}`, + "allowed-statuses": ["running", "stopped"], + "input-spec": {}, + implementation: { type: "script", args: [] }, + } + } + if (manifest.properties) { + actions.properties = { + name: "Properties", + description: + "Runtime information, credentials, and other values of interest", + "allowed-statuses": ["running", "stopped"], + "input-spec": null, + implementation: { type: "script", args: [] }, + } + } + for (const [actionId, action] of Object.entries(actions)) { const hasRunning = !!action["allowed-statuses"].find( (x) => x === "running", ) @@ -412,21 +519,22 @@ export class SystemForEmbassy implements System { ) // prettier-ignore const allowedStatuses = hasRunning && hasStopped ? "any": - hasRunning ? "onlyRunning" : - "onlyStopped" - await effects.exportAction({ + hasRunning ? "only-running" : + "only-stopped" + await effects.action.export({ id: actionId, metadata: { name: action.name, description: action.description, warning: action.warning || null, - input: action["input-spec"] as CT.InputSpec, - disabled: false, + visibility: "enabled", allowedStatuses, + hasInput: !!action["input-spec"], group: null, }, }) } + await effects.action.clear({ except: Object.keys(actions) }) } async packageUninit( effects: Effects, @@ -443,6 +551,7 @@ export class SystemForEmbassy implements System { ): Promise { const backup = this.manifest.backup.create if (backup.type === "docker") { + const commands = [backup.entrypoint, ...backup.args] const container = await DockerProcedureContainer.of( effects, this.manifest.id, @@ -451,8 +560,9 @@ export class SystemForEmbassy implements System { ...this.manifest.volumes, BACKUP: { type: "backup", readonly: false }, }, + `Backup - ${commands.join(" ")}`, ) - await container.execFail([backup.entrypoint, ...backup.args], timeoutMs) + await container.execFail(commands, timeoutMs) } else { const moduleCode = await this.moduleCode await moduleCode.createBackup?.(polyfillEffects(effects, this.manifest)) @@ -464,6 +574,7 @@ export class SystemForEmbassy implements System { ): Promise { const restoreBackup = this.manifest.backup.restore if (restoreBackup.type === "docker") { + const commands = [restoreBackup.entrypoint, ...restoreBackup.args] const container = await DockerProcedureContainer.of( effects, this.manifest.id, @@ -472,20 +583,15 @@ export class SystemForEmbassy implements System { ...this.manifest.volumes, BACKUP: { type: "backup", readonly: true }, }, + `Restore Backup - ${commands.join(" ")}`, ) - await container.execFail( - [restoreBackup.entrypoint, ...restoreBackup.args], - timeoutMs, - ) + await container.execFail(commands, timeoutMs) } else { const moduleCode = await this.moduleCode await moduleCode.restoreBackup?.(polyfillEffects(effects, this.manifest)) } } - async getConfig( - effects: Effects, - timeoutMs: number | null, - ): Promise { + async getConfig(effects: Effects, timeoutMs: number | null) { return this.getConfigUncleaned(effects, timeoutMs).then(convertToNewConfig) } private async getConfigUncleaned( @@ -495,20 +601,17 @@ export class SystemForEmbassy implements System { const config = this.manifest.config?.get if (!config) return { spec: {} } if (config.type === "docker") { + const commands = [config.entrypoint, ...config.args] const container = await DockerProcedureContainer.of( effects, this.manifest.id, config, this.manifest.volumes, + `Get Config - ${commands.join(" ")}`, ) // TODO: yaml return JSON.parse( - ( - await container.execFail( - [config.entrypoint, ...config.args], - timeoutMs, - ) - ).stdout.toString(), + (await container.execFail(commands, timeoutMs)).stdout.toString(), ) } else { const moduleCode = await this.moduleCode @@ -543,28 +646,25 @@ export class SystemForEmbassy implements System { const setConfigValue = this.manifest.config?.set if (!setConfigValue) return if (setConfigValue.type === "docker") { + const commands = [ + setConfigValue.entrypoint, + ...setConfigValue.args, + JSON.stringify(newConfig), + ] const container = await DockerProcedureContainer.of( effects, this.manifest.id, setConfigValue, this.manifest.volumes, + `Set Config - ${commands.join(" ")}`, ) const answer = matchSetResult.unsafeCast( JSON.parse( - ( - await container.execFail( - [ - setConfigValue.entrypoint, - ...setConfigValue.args, - JSON.stringify(newConfig), - ], - timeoutMs, - ) - ).stdout.toString(), + (await container.execFail(commands, timeoutMs)).stdout.toString(), ), ) const dependsOn = answer["depends-on"] ?? answer.dependsOn ?? {} - await this.setConfigSetConfig(effects, dependsOn) + await this.setDependencies(effects, dependsOn) return } else if (setConfigValue.type === "script") { const moduleCode = await this.moduleCode @@ -587,31 +687,60 @@ export class SystemForEmbassy implements System { }), ) const dependsOn = answer["depends-on"] ?? answer.dependsOn ?? {} - await this.setConfigSetConfig(effects, dependsOn) + await this.setDependencies(effects, dependsOn) return } } - private async setConfigSetConfig( + private async setDependencies( effects: Effects, - dependsOn: { [x: string]: readonly string[] }, + rawDepends: { [x: string]: readonly string[] }, ) { + const dependsOn: Record = { + ...Object.fromEntries( + Object.entries(this.manifest.dependencies || {})?.map((x) => [ + x[0], + null, + ]) || [], + ), + ...rawDepends, + } await effects.setDependencies({ - dependencies: Object.entries(dependsOn).flatMap(([key, value]) => { - const dependency = this.manifest.dependencies?.[key] - if (!dependency) return [] - const versionRange = dependency.version - const registryUrl = DEFAULT_REGISTRY - const kind = "running" - return [ - { - id: key, - versionRange, - registryUrl, - kind, - healthChecks: [...value], - }, - ] - }), + dependencies: Object.entries(dependsOn).flatMap( + ([key, value]): T.Dependencies => { + const dependency = this.manifest.dependencies?.[key] + if (!dependency) return [] + if (value == null) { + const versionRange = dependency.version + if (dependency.requirement.type === "required") { + return [ + { + id: key, + versionRange, + kind: "running", + healthChecks: [], + }, + ] + } + return [ + { + kind: "exists", + id: key, + versionRange, + }, + ] + } + const versionRange = dependency.version + const kind = "running" + return [ + { + id: key, + versionRange, + kind, + healthChecks: [...value], + }, + ] + }, + ), }) } @@ -619,7 +748,7 @@ export class SystemForEmbassy implements System { effects: Effects, fromVersion: string, timeoutMs: number | null, - ): Promise { + ): Promise<{ configured: boolean }> { const fromEmver = ExtendedVersion.parseEmver(fromVersion) const currentEmver = ExtendedVersion.parseEmver(this.manifest.version) if (!this.manifest.migrations) return { configured: true } @@ -652,23 +781,20 @@ export class SystemForEmbassy implements System { if (migration) { const [version, procedure] = migration if (procedure.type === "docker") { + const commands = [ + procedure.entrypoint, + ...procedure.args, + JSON.stringify(fromVersion), + ] const container = await DockerProcedureContainer.of( effects, this.manifest.id, procedure, this.manifest.volumes, + `Migration - ${commands.join(" ")}`, ) return JSON.parse( - ( - await container.execFail( - [ - procedure.entrypoint, - ...procedure.args, - JSON.stringify(fromVersion), - ], - timeoutMs, - ) - ).stdout.toString(), + (await container.execFail(commands, timeoutMs)).stdout.toString(), ) } else if (procedure.type === "script") { const moduleCode = await this.moduleCode @@ -690,25 +816,22 @@ export class SystemForEmbassy implements System { async properties( effects: Effects, timeoutMs: number | null, - ): Promise { + ): Promise { // TODO BLU-J set the properties ever so often const setConfigValue = this.manifest.properties if (!setConfigValue) throw new Error("There is no properties") if (setConfigValue.type === "docker") { + const commands = [setConfigValue.entrypoint, ...setConfigValue.args] const container = await DockerProcedureContainer.of( effects, this.manifest.id, setConfigValue, this.manifest.volumes, + `Properties - ${commands.join(" ")}`, ) const properties = matchProperties.unsafeCast( JSON.parse( - ( - await container.execFail( - [setConfigValue.entrypoint, ...setConfigValue.args], - timeoutMs, - ) - ).stdout.toString(), + (await container.execFail(commands, timeoutMs)).stdout.toString(), ), ) return asProperty(properties.data) @@ -735,13 +858,13 @@ export class SystemForEmbassy implements System { const actionProcedure = this.manifest.actions?.[actionId]?.implementation const toActionResult = ({ message, - value = "", + value, copyable, qr, }: U.ActionResult): T.ActionResult => ({ version: "0", message, - value, + value: value ?? null, copyable, qr, }) @@ -750,11 +873,18 @@ export class SystemForEmbassy implements System { const subcontainer = actionProcedure.inject ? this.currentRunning?.mainSubContainerHandle : undefined + + const env: Record = actionProcedure.inject + ? { + HOME: "/root", + } + : {} const container = await DockerProcedureContainer.of( effects, this.manifest.id, actionProcedure, this.manifest.volumes, + `Action ${actionId}`, { subcontainer, }, @@ -769,6 +899,7 @@ export class SystemForEmbassy implements System { JSON.stringify(formData), ], timeoutMs, + { env }, ) ).stdout.toString(), ), @@ -794,23 +925,20 @@ export class SystemForEmbassy implements System { const actionProcedure = this.manifest.dependencies?.[id]?.config?.check if (!actionProcedure) return { message: "Action not found", value: null } if (actionProcedure.type === "docker") { + const commands = [ + actionProcedure.entrypoint, + ...actionProcedure.args, + JSON.stringify(oldConfig), + ] const container = await DockerProcedureContainer.of( effects, this.manifest.id, actionProcedure, this.manifest.volumes, + `Dependencies Check - ${commands.join(" ")}`, ) return JSON.parse( - ( - await container.execFail( - [ - actionProcedure.entrypoint, - ...actionProcedure.args, - JSON.stringify(oldConfig), - ], - timeoutMs, - ) - ).stdout.toString(), + (await container.execFail(commands, timeoutMs)).stdout.toString(), ) } else if (actionProcedure.type === "script") { const moduleCode = await this.moduleCode @@ -834,24 +962,46 @@ export class SystemForEmbassy implements System { async dependenciesAutoconfig( effects: Effects, id: string, - input: unknown, timeoutMs: number | null, ): Promise { - const oldConfig = object({ remoteConfig: any }).unsafeCast( - input, - ).remoteConfig // TODO: docker + const oldConfig = (await effects.store.get({ + packageId: id, + path: EMBASSY_POINTER_PATH_PREFIX, + callback: () => { + this.dependenciesAutoconfig(effects, id, timeoutMs) + }, + })) as U.Config + if (!oldConfig) return const moduleCode = await this.moduleCode const method = moduleCode.dependencies?.[id]?.autoConfigure if (!method) return - return (await method( + const newConfig = (await method( polyfillEffects(effects, this.manifest), - oldConfig, + JSON.parse(JSON.stringify(oldConfig)), ).then((x) => { if ("result" in x) return x.result if ("error" in x) throw new Error("Error getting config: " + x.error) throw new Error("Error getting config: " + x["error-code"][1]) })) as any + const diff = partialDiff(oldConfig, newConfig) + if (diff) { + await effects.action.request({ + actionId: "config", + packageId: id, + replayId: `${id}/config`, + severity: "important", + reason: `Configure this dependency for the needs of ${this.manifest.title}`, + input: { + kind: "partial", + value: diff.diff, + }, + when: { + condition: "input-not-matches", + once: false, + }, + }) + } } } @@ -1026,9 +1176,7 @@ function extractServiceInterfaceId(manifest: Manifest, specInterface: string) { const serviceInterfaceId = `${specInterface}-${internalPort}` return serviceInterfaceId } -async function convertToNewConfig( - value: OldGetConfigRes, -): Promise { +async function convertToNewConfig(value: OldGetConfigRes) { const valueSpec: OldConfigSpec = matchOldConfigSpec.unsafeCast(value.spec) const spec = transformConfigSpec(valueSpec) if (!value.config) return { spec, config: null } diff --git a/container-runtime/src/Adapters/Systems/SystemForEmbassy/matchManifest.ts b/container-runtime/src/Adapters/Systems/SystemForEmbassy/matchManifest.ts index bd8856b42..5bda20de0 100644 --- a/container-runtime/src/Adapters/Systems/SystemForEmbassy/matchManifest.ts +++ b/container-runtime/src/Adapters/Systems/SystemForEmbassy/matchManifest.ts @@ -42,6 +42,7 @@ const matchAction = object( export const matchManifest = object( { id: string, + title: string, version: string, main: matchDockerProcedure, assets: object( diff --git a/container-runtime/src/Adapters/Systems/SystemForEmbassy/polyfillEffects.ts b/container-runtime/src/Adapters/Systems/SystemForEmbassy/polyfillEffects.ts index c212722e6..7438070ea 100644 --- a/container-runtime/src/Adapters/Systems/SystemForEmbassy/polyfillEffects.ts +++ b/container-runtime/src/Adapters/Systems/SystemForEmbassy/polyfillEffects.ts @@ -105,12 +105,14 @@ export const polyfillEffects = ( args?: string[] | undefined timeoutMillis?: number | undefined }): Promise> { + const commands: [string, ...string[]] = [command, ...(args || [])] return startSdk .runCommand( effects, { id: manifest.main.image }, - [command, ...(args || [])], + commands, {}, + commands.join(" "), ) .then((x: any) => ({ stderr: x.stderr.toString(), @@ -129,6 +131,7 @@ export const polyfillEffects = ( manifest.id, manifest.main, manifest.volumes, + [input.command, ...(input.args || [])].join(" "), ) const daemon = promiseSubcontainer.then((subcontainer) => daemons.runCommand()( @@ -153,11 +156,17 @@ export const polyfillEffects = ( path: string uid: string }): Promise { + const commands: [string, ...string[]] = [ + "chown", + "--recursive", + input.uid, + `/drive/${input.path}`, + ] await startSdk .runCommand( effects, { id: manifest.main.image }, - ["chown", "--recursive", input.uid, `/drive/${input.path}`], + commands, { mounts: [ { @@ -171,6 +180,7 @@ export const polyfillEffects = ( }, ], }, + commands.join(" "), ) .then((x: any) => ({ stderr: x.stderr.toString(), @@ -188,11 +198,17 @@ export const polyfillEffects = ( path: string mode: string }): Promise { + const commands: [string, ...string[]] = [ + "chmod", + "--recursive", + input.mode, + `/drive/${input.path}`, + ] await startSdk .runCommand( effects, { id: manifest.main.image }, - ["chmod", "--recursive", input.mode, `/drive/${input.path}`], + commands, { mounts: [ { @@ -206,6 +222,7 @@ export const polyfillEffects = ( }, ], }, + commands.join(" "), ) .then((x: any) => ({ stderr: x.stderr.toString(), diff --git a/container-runtime/src/Adapters/Systems/SystemForEmbassy/transformConfigSpec.ts b/container-runtime/src/Adapters/Systems/SystemForEmbassy/transformConfigSpec.ts index 5ce601c57..1eb2ea508 100644 --- a/container-runtime/src/Adapters/Systems/SystemForEmbassy/transformConfigSpec.ts +++ b/container-runtime/src/Adapters/Systems/SystemForEmbassy/transformConfigSpec.ts @@ -1,4 +1,4 @@ -import { CT } from "@start9labs/start-sdk" +import { IST } from "@start9labs/start-sdk" import { dictionary, object, @@ -15,9 +15,9 @@ import { literal, } from "ts-matches" -export function transformConfigSpec(oldSpec: OldConfigSpec): CT.InputSpec { +export function transformConfigSpec(oldSpec: OldConfigSpec): IST.InputSpec { return Object.entries(oldSpec).reduce((inputSpec, [key, oldVal]) => { - let newVal: CT.ValueSpec + let newVal: IST.ValueSpec if (oldVal.type === "boolean") { newVal = { @@ -43,7 +43,6 @@ export function transformConfigSpec(oldSpec: OldConfigSpec): CT.InputSpec { }), {}, ), - required: false, disabled: false, immutable: false, } @@ -124,10 +123,9 @@ export function transformConfigSpec(oldSpec: OldConfigSpec): CT.InputSpec { spec: transformConfigSpec(matchOldConfigSpec.unsafeCast(spec)), }, }), - {} as Record, + {} as Record, ), disabled: false, - required: true, default: oldVal.default, immutable: false, } @@ -141,7 +139,7 @@ export function transformConfigSpec(oldSpec: OldConfigSpec): CT.InputSpec { ...inputSpec, [key]: newVal, } - }, {} as CT.InputSpec) + }, {} as IST.InputSpec) } export function transformOldConfigToNew( @@ -233,10 +231,10 @@ export function transformNewConfigToOld( function getListSpec( oldVal: OldValueSpecList, -): CT.ValueSpecMultiselect | CT.ValueSpecList { +): IST.ValueSpecMultiselect | IST.ValueSpecList { const range = Range.from(oldVal.range) - let partial: Omit = { + let partial: Omit = { name: oldVal.name, description: oldVal.description || null, warning: oldVal.warning || null, diff --git a/container-runtime/src/Adapters/Systems/SystemForStartOs.ts b/container-runtime/src/Adapters/Systems/SystemForStartOs.ts index 51d91abb5..334764a87 100644 --- a/container-runtime/src/Adapters/Systems/SystemForStartOs.ts +++ b/container-runtime/src/Adapters/Systems/SystemForStartOs.ts @@ -1,21 +1,12 @@ -import { ExecuteResult, Procedure, System } from "../../Interfaces/System" -import { unNestPath } from "../../Models/JsonPath" -import matches, { any, number, object, string, tuple } from "ts-matches" +import { System } from "../../Interfaces/System" import { Effects } from "../../Models/Effects" -import { RpcResult, matchRpcResult } from "../RpcListener" -import { duration } from "../../Models/Duration" import { T, utils } from "@start9labs/start-sdk" -import { Volume } from "../../Models/Volume" -import { MainEffects } from "@start9labs/start-sdk/cjs/lib/StartSdk" -import { CallbackHolder } from "../../Models/CallbackHolder" import { Optional } from "ts-matches/lib/parsers/interfaces" export const STARTOS_JS_LOCATION = "/usr/lib/startos/package/index.js" type RunningMain = { - effects: MainEffects stop: () => Promise - callbacks: CallbackHolder } export class SystemForStartOs implements System { @@ -25,23 +16,24 @@ export class SystemForStartOs implements System { return new SystemForStartOs(require(STARTOS_JS_LOCATION)) } - constructor(readonly abi: T.ABI) {} - containerInit(): Promise { - throw new Error("Method not implemented.") + constructor(readonly abi: T.ABI) { + this + } + async containerInit(effects: Effects): Promise { + return void (await this.abi.containerInit({ effects })) } async packageInit( effects: Effects, - previousVersion: Optional = null, timeoutMs: number | null = null, ): Promise { - return void (await this.abi.init({ effects })) + return void (await this.abi.packageInit({ effects })) } async packageUninit( effects: Effects, nextVersion: Optional = null, timeoutMs: number | null = null, ): Promise { - return void (await this.abi.uninit({ effects, nextVersion })) + return void (await this.abi.packageUninit({ effects, nextVersion })) } async createBackup( effects: T.Effects, @@ -49,8 +41,6 @@ export class SystemForStartOs implements System { ): Promise { return void (await this.abi.createBackup({ effects, - pathMaker: ((options) => - new Volume(options.volume, options.path).path) as T.PathMaker, })) } async restoreBackup( @@ -59,118 +49,56 @@ export class SystemForStartOs implements System { ): Promise { return void (await this.abi.restoreBackup({ effects, - pathMaker: ((options) => - new Volume(options.volume, options.path).path) as T.PathMaker, })) } - getConfig( - effects: T.Effects, - timeoutMs: number | null, - ): Promise { - return this.abi.getConfig({ effects }) - } - async setConfig( - effects: Effects, - input: { effects: Effects; input: Record }, - timeoutMs: number | null, - ): Promise { - const _: unknown = await this.abi.setConfig({ effects, input }) - return - } - migration( - effects: Effects, - fromVersion: string, - timeoutMs: number | null, - ): Promise { - throw new Error("Method not implemented.") - } - properties( - effects: Effects, - timeoutMs: number | null, - ): Promise { - throw new Error("Method not implemented.") - } - async action( + getActionInput( effects: Effects, id: string, - formData: unknown, timeoutMs: number | null, - ): Promise { - const action = (await this.abi.actions({ effects }))[id] + ): Promise { + const action = this.abi.actions.get(id) if (!action) throw new Error(`Action ${id} not found`) - return action.run({ effects }) + return action.getInput({ effects }) } - dependenciesCheck( + runAction( effects: Effects, id: string, - oldConfig: unknown, + input: unknown, timeoutMs: number | null, - ): Promise { - const dependencyConfig = this.abi.dependencyConfig[id] - if (!dependencyConfig) throw new Error(`dependencyConfig ${id} not found`) - return dependencyConfig.query({ effects }) + ): Promise { + const action = this.abi.actions.get(id) + if (!action) throw new Error(`Action ${id} not found`) + return action.run({ effects, input }) } - async dependenciesAutoconfig( - effects: Effects, - id: string, - remoteConfig: unknown, - timeoutMs: number | null, - ): Promise { - const dependencyConfig = this.abi.dependencyConfig[id] - if (!dependencyConfig) throw new Error(`dependencyConfig ${id} not found`) - const queryResults = await this.getConfig(effects, timeoutMs) - return void (await dependencyConfig.update({ - queryResults, - remoteConfig, - })) // TODO - } - async actionsMetadata(effects: T.Effects): Promise { - return this.abi.actionsMetadata({ effects }) - } - - async init(): Promise {} async exit(): Promise {} - async start(effects: MainEffects): Promise { + async start(effects: Effects): Promise { + effects.constRetry = utils.once(() => effects.restart()) if (this.runningMain) await this.stop() let mainOnTerm: () => Promise | undefined const started = async (onTerm: () => Promise) => { await effects.setMainStatus({ status: "running" }) mainOnTerm = onTerm + return null } const daemons = await ( await this.abi.main({ - effects: effects as MainEffects, + effects, started, }) ).build() this.runningMain = { - effects, stop: async () => { if (mainOnTerm) await mainOnTerm() await daemons.term() }, - callbacks: new CallbackHolder(), - } - } - - callCallback(callback: number, args: any[]): void { - if (this.runningMain) { - this.runningMain.callbacks - .callCallback(callback, args) - .catch((error) => - console.error(`callback ${callback} failed`, utils.asError(error)), - ) - } else { - console.warn(`callback ${callback} ignored because system is not running`) } } async stop(): Promise { if (this.runningMain) { await this.runningMain.stop() - await this.runningMain.effects.clearCallbacks() this.runningMain = undefined } } diff --git a/container-runtime/src/Interfaces/AllGetDependencies.ts b/container-runtime/src/Interfaces/AllGetDependencies.ts index ca5c43585..24b68acc5 100644 --- a/container-runtime/src/Interfaces/AllGetDependencies.ts +++ b/container-runtime/src/Interfaces/AllGetDependencies.ts @@ -1,7 +1,4 @@ import { GetDependency } from "./GetDependency" import { System } from "./System" -import { MakeMainEffects, MakeProcedureEffects } from "./MakeEffects" -export type AllGetDependencies = GetDependency<"system", Promise> & - GetDependency<"makeProcedureEffects", MakeProcedureEffects> & - GetDependency<"makeMainEffects", MakeMainEffects> +export type AllGetDependencies = GetDependency<"system", Promise> diff --git a/container-runtime/src/Interfaces/MakeEffects.ts b/container-runtime/src/Interfaces/MakeEffects.ts deleted file mode 100644 index 3b25f8180..000000000 --- a/container-runtime/src/Interfaces/MakeEffects.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { Effects } from "../Models/Effects" -import { MainEffects } from "@start9labs/start-sdk/cjs/lib/StartSdk" -export type MakeProcedureEffects = (procedureId: string) => Effects -export type MakeMainEffects = () => MainEffects diff --git a/container-runtime/src/Interfaces/System.ts b/container-runtime/src/Interfaces/System.ts index 1348b79e9..63781cfbd 100644 --- a/container-runtime/src/Interfaces/System.ts +++ b/container-runtime/src/Interfaces/System.ts @@ -1,39 +1,26 @@ import { types as T } from "@start9labs/start-sdk" -import { RpcResult } from "../Adapters/RpcListener" import { Effects } from "../Models/Effects" import { CallbackHolder } from "../Models/CallbackHolder" -import { MainEffects } from "@start9labs/start-sdk/cjs/lib/StartSdk" import { Optional } from "ts-matches/lib/parsers/interfaces" export type Procedure = - | "/init" - | "/uninit" - | "/config/set" - | "/config/get" + | "/packageInit" + | "/packageUninit" | "/backup/create" | "/backup/restore" - | "/actions/metadata" - | "/properties" - | `/actions/${string}/get` + | `/actions/${string}/getInput` | `/actions/${string}/run` - | `/dependencies/${string}/query` - | `/dependencies/${string}/update` export type ExecuteResult = | { ok: unknown } | { err: { code: number; message: string } } export type System = { - containerInit(): Promise + containerInit(effects: T.Effects): Promise - start(effects: MainEffects): Promise - callCallback(callback: number, args: any[]): void + start(effects: T.Effects): Promise stop(): Promise - packageInit( - effects: Effects, - previousVersion: Optional, - timeoutMs: number | null, - ): Promise + packageInit(effects: Effects, timeoutMs: number | null): Promise packageUninit( effects: Effects, nextVersion: Optional, @@ -42,41 +29,17 @@ export type System = { createBackup(effects: T.Effects, timeoutMs: number | null): Promise restoreBackup(effects: T.Effects, timeoutMs: number | null): Promise - getConfig(effects: T.Effects, timeoutMs: number | null): Promise - setConfig( - effects: Effects, - input: { effects: Effects; input: Record }, - timeoutMs: number | null, - ): Promise - migration( - effects: Effects, - fromVersion: string, - timeoutMs: number | null, - ): Promise - properties( - effects: Effects, - timeoutMs: number | null, - ): Promise - action( + runAction( effects: Effects, actionId: string, - formData: unknown, + input: unknown, timeoutMs: number | null, - ): Promise - - dependenciesCheck( + ): Promise + getActionInput( effects: Effects, - id: string, - oldConfig: unknown, + actionId: string, timeoutMs: number | null, - ): Promise - dependenciesAutoconfig( - effects: Effects, - id: string, - oldConfig: unknown, - timeoutMs: number | null, - ): Promise - actionsMetadata(effects: T.Effects): Promise + ): Promise exit(): Promise } diff --git a/container-runtime/src/Models/CallbackHolder.ts b/container-runtime/src/Models/CallbackHolder.ts index b51af0bee..ce474268a 100644 --- a/container-runtime/src/Models/CallbackHolder.ts +++ b/container-runtime/src/Models/CallbackHolder.ts @@ -1,22 +1,62 @@ +import { T } from "@start9labs/start-sdk" + +const CallbackIdCell = { inc: 1 } + +const callbackRegistry = new FinalizationRegistry( + async (options: { cbs: Map; effects: T.Effects }) => { + await options.effects.clearCallbacks({ + only: Array.from(options.cbs.keys()), + }) + }, +) + export class CallbackHolder { - constructor() {} - private inc = 0 + constructor(private effects?: T.Effects) {} + private callbacks = new Map() + private children: WeakRef[] = [] private newId() { - return this.inc++ + return CallbackIdCell.inc++ } addCallback(callback?: Function) { if (!callback) { return } const id = this.newId() + console.error("adding callback", id) this.callbacks.set(id, callback) + if (this.effects) + callbackRegistry.register(this, { + cbs: this.callbacks, + effects: this.effects, + }) return id } + child(): CallbackHolder { + const child = new CallbackHolder() + this.children.push(new WeakRef(child)) + return child + } + removeChild(child: CallbackHolder) { + this.children = this.children.filter((c) => { + const ref = c.deref() + return ref && ref !== child + }) + } + private getCallback(index: number): Function | undefined { + let callback = this.callbacks.get(index) + if (callback) this.callbacks.delete(index) + else { + for (let i = 0; i < this.children.length; i++) { + callback = this.children[i].deref()?.getCallback(index) + if (callback) return callback + } + } + return callback + } callCallback(index: number, args: any[]): Promise { - const callback = this.callbacks.get(index) - if (!callback) throw new Error(`Callback ${index} does not exist`) - this.callbacks.delete(index) + const callback = this.getCallback(index) + if (!callback) return Promise.resolve() return Promise.resolve().then(() => callback(...args)) } } diff --git a/container-runtime/src/Models/JsonPath.ts b/container-runtime/src/Models/JsonPath.ts index 95a2b3a00..d101836da 100644 --- a/container-runtime/src/Models/JsonPath.ts +++ b/container-runtime/src/Models/JsonPath.ts @@ -1,9 +1,7 @@ import { literals, some, string } from "ts-matches" type NestedPath = `/${A}/${string}/${B}` -type NestedPaths = - | NestedPath<"actions", "run" | "get"> - | NestedPath<"dependencies", "query" | "update"> +type NestedPaths = NestedPath<"actions", "run" | "getInput"> // prettier-ignore type UnNestPaths = A extends `${infer A}/${infer B}` ? [...UnNestPaths, ... UnNestPaths] : @@ -15,25 +13,16 @@ export function unNestPath(a: A): UnNestPaths { function isNestedPath(path: string): path is NestedPaths { const paths = path.split("/") if (paths.length !== 4) return false - if (paths[1] === "actions" && (paths[3] === "run" || paths[3] === "get")) - return true - if ( - paths[1] === "dependencies" && - (paths[3] === "query" || paths[3] === "update") - ) + if (paths[1] === "actions" && (paths[3] === "run" || paths[3] === "getInput")) return true return false } export const jsonPath = some( literals( - "/init", - "/uninit", - "/config/set", - "/config/get", + "/packageInit", + "/packageUninit", "/backup/create", "/backup/restore", - "/actions/metadata", - "/properties", ), string.refine(isNestedPath, "isNestedPath"), ) diff --git a/container-runtime/src/index.ts b/container-runtime/src/index.ts index 5454bee3d..ec6a998f4 100644 --- a/container-runtime/src/index.ts +++ b/container-runtime/src/index.ts @@ -1,13 +1,10 @@ import { RpcListener } from "./Adapters/RpcListener" import { SystemForEmbassy } from "./Adapters/Systems/SystemForEmbassy" -import { makeMainEffects, makeProcedureEffects } from "./Adapters/EffectCreator" import { AllGetDependencies } from "./Interfaces/AllGetDependencies" import { getSystem } from "./Adapters/Systems" const getDependencies: AllGetDependencies = { system: getSystem, - makeProcedureEffects: () => makeProcedureEffects, - makeMainEffects: () => makeMainEffects, } new RpcListener(getDependencies) diff --git a/core/Cargo.lock b/core/Cargo.lock index 1fccce36d..498e5903e 100644 --- a/core/Cargo.lock +++ b/core/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "Inflector" @@ -23,6 +23,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + [[package]] name = "aes" version = "0.7.5" @@ -86,9 +92,9 @@ dependencies = [ [[package]] name = "allocator-api2" -version = "0.2.18" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" +checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9" [[package]] name = "android-tzdata" @@ -107,9 +113,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.15" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ "anstyle", "anstyle-parse", @@ -122,49 +128,49 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.8" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.4" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anyhow" -version = "1.0.86" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" [[package]] name = "arrayref" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d151e35f61089500b617991b791fc8bfd237ae50cd5950803758a179b41e67a" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" [[package]] name = "arrayvec" @@ -174,9 +180,9 @@ checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" [[package]] name = "arrayvec" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "ascii-canvas" @@ -187,6 +193,67 @@ dependencies = [ "term", ] +[[package]] +name = "asn1-rs" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5493c3bedbacf7fd7382c6346bbd66687d12bbaad3a89a2d2c303ee6cf20b048" +dependencies = [ + "asn1-rs-derive", + "asn1-rs-impl", + "displaydoc", + "nom 7.1.3", + "num-traits", + "rusticata-macros", + "thiserror", + "time", +] + +[[package]] +name = "asn1-rs-derive" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "965c2d33e53cb6b267e148a4cb0760bc01f4904c1cd4bb4002a085bb016d1490" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", + "synstructure", +] + +[[package]] +name = "asn1-rs-impl" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "async-acme" +version = "0.5.0" +source = "git+https://github.com/dr-bonez/async-acme.git#b9ff31ad900adc9086c0d1437ce51661d30856d2" +dependencies = [ + "async-trait", + "base64 0.22.1", + "futures-util", + "generic-async-http-client", + "log", + "pem", + "rcgen", + "ring", + "rustls 0.23.17", + "rustls-pemfile 2.2.0", + "serde", + "serde_json", + "thiserror", + "tokio", + "x509-parser", +] + [[package]] name = "async-channel" version = "1.9.0" @@ -200,9 +267,9 @@ dependencies = [ [[package]] name = "async-compression" -version = "0.4.12" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fec134f64e2bc57411226dfc4e52dec859ddfc7e711fc5e07b612584f000e4aa" +checksum = "0cb8f1d480b0ea3783ab015936d2a55c87e219676f0c0b7dec61494043f21857" dependencies = [ "brotli", "flate2", @@ -214,9 +281,9 @@ dependencies = [ [[package]] name = "async-stream" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" dependencies = [ "async-stream-impl", "futures-core", @@ -225,24 +292,24 @@ dependencies = [ [[package]] name = "async-stream-impl" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.87", ] [[package]] name = "async-trait" -version = "0.1.81" +version = "0.1.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.87", ] [[package]] @@ -262,15 +329,15 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "aws-lc-rs" -version = "1.8.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae74d9bd0a7530e8afd1770739ad34b36838829d6ad61818f9230f683f5ad77" +checksum = "fe7c2840b66236045acd2607d5866e274380afd87ef99d6226e961e2cb47df45" dependencies = [ "aws-lc-sys", "mirai-annotations", @@ -280,9 +347,9 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.20.1" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f0e249228c6ad2d240c2dc94b714d711629d52bad946075d8e9b2f5391f0703" +checksum = "ad3a619a9de81e1d7de1f1186dcba4506ed661a0e483d84410fdef0ee87b2f96" dependencies = [ "bindgen", "cc", @@ -306,7 +373,7 @@ dependencies = [ "futures-util", "http 0.2.12", "http-body 0.4.6", - "hyper 0.14.30", + "hyper 0.14.31", "itoa", "matchit", "memchr", @@ -316,26 +383,26 @@ dependencies = [ "rustversion", "serde", "sync_wrapper 0.1.2", - "tower", + "tower 0.4.13", "tower-layer", "tower-service", ] [[package]] name = "axum" -version = "0.7.5" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" +checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" dependencies = [ "async-trait", - "axum-core 0.4.3", - "base64 0.21.7", + "axum-core 0.4.5", + "base64 0.22.1", "bytes", "futures-util", "http 1.1.0", "http-body 1.0.1", "http-body-util", - "hyper 1.4.1", + "hyper 1.5.1", "hyper-util", "itoa", "matchit", @@ -351,8 +418,8 @@ dependencies = [ "sha1", "sync_wrapper 1.0.1", "tokio", - "tokio-tungstenite 0.21.0", - "tower", + "tokio-tungstenite 0.24.0", + "tower 0.5.1", "tower-layer", "tower-service", "tracing", @@ -377,9 +444,9 @@ dependencies = [ [[package]] name = "axum-core" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" +checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" dependencies = [ "async-trait", "bytes", @@ -390,7 +457,7 @@ dependencies = [ "mime", "pin-project-lite", "rustversion", - "sync_wrapper 0.1.2", + "sync_wrapper 1.0.1", "tower-layer", "tower-service", "tracing", @@ -407,11 +474,11 @@ dependencies = [ "http 1.1.0", "http-body 1.0.1", "http-body-util", - "hyper 1.4.1", + "hyper 1.5.1", "hyper-util", "pin-project-lite", "tokio", - "tower", + "tower 0.4.13", "tower-service", ] @@ -441,7 +508,7 @@ dependencies = [ "cc", "cfg-if", "libc", - "miniz_oxide", + "miniz_oxide 0.7.4", "object", "rustc-demangle", ] @@ -515,9 +582,9 @@ dependencies = [ [[package]] name = "bindgen" -version = "0.69.4" +version = "0.69.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0" +checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" dependencies = [ "bitflags 2.6.0", "cexpr", @@ -532,8 +599,8 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.74", - "which 4.4.2", + "syn 2.0.87", + "which", ] [[package]] @@ -603,18 +670,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23285ad32269793932e830392f2fe2f83e26488fd3ec778883a93c8323735780" dependencies = [ "arrayref", - "arrayvec 0.7.4", + "arrayvec 0.7.6", "constant_time_eq", ] [[package]] name = "blake3" -version = "1.5.3" +version = "1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9ec96fe9a81b5e365f9db71fe00edc4fe4ca2cc7dcb7861f0603012a7caa210" +checksum = "d82033247fd8e890df8f740e407ad4d038debb9eb1f40533fffb32e7d17dc6f7" dependencies = [ "arrayref", - "arrayvec 0.7.4", + "arrayvec 0.7.6", "cc", "cfg-if", "constant_time_eq", @@ -642,9 +709,9 @@ dependencies = [ [[package]] name = "brotli" -version = "6.0.0" +version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74f7971dbd9326d58187408ab83117d8ac1bb9c17b085fdacd1cf2f598719b6b" +checksum = "cc97b8f16f944bba54f0433f07e30be199b6dc2bd25937444bbad560bcea29bd" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -667,6 +734,12 @@ version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +[[package]] +name = "bytemuck" +version = "1.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b37c88a63ffd85d15b406896cc343916d7cf57838a847b3a6f2ca5d39a5695a" + [[package]] name = "byteorder" version = "1.5.0" @@ -674,10 +747,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] -name = "bytes" -version = "1.7.1" +name = "byteorder-lite" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" + +[[package]] +name = "bytes" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" [[package]] name = "cache-padded" @@ -687,9 +766,9 @@ checksum = "981520c98f422fcc584dc1a95c334e6953900b9106bc47a9839b81790009eb21" [[package]] name = "cc" -version = "1.1.12" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68064e60dbf1f17005c2fde4d07c16d8baa506fd7ffed8ccab702d93617975c7" +checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47" dependencies = [ "jobserver", "libc", @@ -800,9 +879,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.15" +version = "4.5.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d8838454fda655dafd3accb2b6e2bea645b9e4078abe84a22ceb947235c5cc" +checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f" dependencies = [ "clap_builder", "clap_derive", @@ -810,9 +889,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.15" +version = "4.5.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6" +checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec" dependencies = [ "anstream", "anstyle", @@ -822,21 +901,21 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.13" +version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.87", ] [[package]] name = "clap_lex" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" +checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" [[package]] name = "cmake" @@ -876,9 +955,9 @@ dependencies = [ [[package]] name = "colorchoice" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "concurrent-queue" @@ -907,7 +986,7 @@ dependencies = [ "encode_unicode 0.3.6", "lazy_static", "libc", - "unicode-width", + "unicode-width 0.1.12", "windows-sys 0.52.0", ] @@ -977,9 +1056,9 @@ dependencies = [ [[package]] name = "constant_time_eq" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" [[package]] name = "convert_case" @@ -1009,12 +1088,13 @@ dependencies = [ [[package]] name = "cookie_store" -version = "0.21.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4934e6b7e8419148b6ef56950d277af8561060b56afd59e2aadf98b59fce6baa" +checksum = "2eac901828f88a5241ee0600950ab981148a18f2f756900ffba1b125ca6a3ef9" dependencies = [ "cookie", - "idna 0.5.0", + "document-features", + "idna 1.0.3", "log", "publicsuffix", "serde", @@ -1042,9 +1122,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.13" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" +checksum = "0ca741a962e1b0bff6d724a1a0958b686406e853bb14061f218562e1896f95e6" dependencies = [ "libc", ] @@ -1172,9 +1252,9 @@ dependencies = [ [[package]] name = "csv" -version = "1.3.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac574ff4d437a7b5ad237ef331c17ccca63c46479e5b5453eb8e10bb99a759fe" +checksum = "acdc4883a9c96732e4733212c01447ebd805833b7275a73ca3ee080fd77afdaf" dependencies = [ "csv-core", "itoa", @@ -1237,7 +1317,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.87", ] [[package]] @@ -1261,7 +1341,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.74", + "syn 2.0.87", ] [[package]] @@ -1272,7 +1352,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.74", + "syn 2.0.87", ] [[package]] @@ -1303,7 +1383,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.87", ] [[package]] @@ -1318,6 +1398,20 @@ dependencies = [ "zeroize", ] +[[package]] +name = "der-parser" +version = "9.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cd0a5c643689626bec213c4d8bd4d96acc8ffdb4ad4bb6bc16abf27d5f4b553" +dependencies = [ + "asn1-rs", + "displaydoc", + "nom 7.1.3", + "num-bigint", + "num-traits", + "rusticata-macros", +] + [[package]] name = "der_derive" version = "0.7.3" @@ -1326,7 +1420,7 @@ checksum = "8034092389675178f570469e6c3b0465d3d30b4505c294a6550db47f3c17ad18" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.87", ] [[package]] @@ -1349,7 +1443,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.74", + "syn 2.0.87", ] [[package]] @@ -1394,12 +1488,32 @@ dependencies = [ "winapi", ] +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + [[package]] name = "divrem" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69dde51e8fef5e12c1d65e0929b03d66e4c0c18282bc30ed2ca050ad6f44dd82" +[[package]] +name = "document-features" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb6969eaabd2421f8a2775cfd2471a2b634372b4a25d41e3bd647b79912850a0" +dependencies = [ + "litrs", +] + [[package]] name = "dotenvy" version = "0.15.7" @@ -1555,23 +1669,23 @@ checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" [[package]] name = "encoding_rs" -version = "0.8.34" +version = "0.8.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" dependencies = [ "cfg-if", ] [[package]] name = "enum-as-inner" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ffccbb6966c05b32ef8fbac435df276c4ae4d3dc55a8cd0eb9745e6c12f546a" +checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" dependencies = [ - "heck 0.4.1", + "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.87", ] [[package]] @@ -1658,9 +1772,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" [[package]] name = "fd-lock-rs" @@ -1689,9 +1803,9 @@ checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" [[package]] name = "filetime" -version = "0.2.24" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf401df4a4e3872c4fe8151134cf483738e74b67fc934d6532c882b3d24a4550" +checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" dependencies = [ "cfg-if", "libc", @@ -1707,19 +1821,19 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" -version = "1.0.31" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f211bbe8e69bbd0cfdea405084f128ae8b4aaa6b0b522fc8f2b009084797920" +checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" dependencies = [ "crc32fast", - "miniz_oxide", + "miniz_oxide 0.8.0", ] [[package]] name = "flume" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" +checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" dependencies = [ "futures-core", "futures-sink", @@ -1785,9 +1899,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -1800,9 +1914,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -1810,15 +1924,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -1838,38 +1952,49 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.87", +] + +[[package]] +name = "futures-rustls" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8d8a2499f0fecc0492eb3e47eab4e92da7875e1028ad2528f214ac3346ca04e" +dependencies = [ + "futures-io", + "rustls 0.22.4", + "rustls-pki-types", ] [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", @@ -1894,6 +2019,25 @@ dependencies = [ "zeroize", ] +[[package]] +name = "generic-async-http-client" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75cec8bb4d3d32542cfcb9517f78366b52c17931e30d7ee1682c13686c19cee7" +dependencies = [ + "futures", + "futures-rustls", + "hyper 1.5.1", + "log", + "serde", + "serde_json", + "serde_qs", + "serde_urlencoded", + "tokio", + "tokio-rustls 0.25.0", + "webpki-roots 0.26.6", +] + [[package]] name = "getrandom" version = "0.1.16" @@ -1963,7 +2107,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.4.0", + "indexmap 2.6.0", "slab", "tokio", "tokio-util", @@ -1972,9 +2116,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.5" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab" +checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e" dependencies = [ "atomic-waker", "bytes", @@ -1982,7 +2126,7 @@ dependencies = [ "futures-core", "futures-sink", "http 1.1.0", - "indexmap 2.4.0", + "indexmap 2.6.0", "slab", "tokio", "tokio-util", @@ -2030,6 +2174,12 @@ dependencies = [ "allocator-api2", ] +[[package]] +name = "hashbrown" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" + [[package]] name = "hashlink" version = "0.8.4" @@ -2193,9 +2343,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.9.4" +version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" [[package]] name = "httpdate" @@ -2211,9 +2361,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.30" +version = "0.14.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9" +checksum = "8c08302e8fa335b151b788c775ff56e7a03ae64ff85c548ee820fecb70356e85" dependencies = [ "bytes", "futures-channel", @@ -2235,14 +2385,14 @@ dependencies = [ [[package]] name = "hyper" -version = "1.4.1" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" +checksum = "97818827ef4f364230e16705d4706e2897df2bb60617d6ca15d598025a3c481f" dependencies = [ "bytes", "futures-channel", "futures-util", - "h2 0.4.5", + "h2 0.4.7", "http 1.1.0", "http-body 1.0.1", "httparse", @@ -2256,18 +2406,18 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.2" +version = "0.27.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" +checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" dependencies = [ "futures-util", "http 1.1.0", - "hyper 1.4.1", + "hyper 1.5.1", "hyper-util", - "rustls 0.23.12", + "rustls 0.23.17", "rustls-pki-types", "tokio", - "tokio-rustls", + "tokio-rustls 0.26.0", "tower-service", ] @@ -2277,7 +2427,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" dependencies = [ - "hyper 0.14.30", + "hyper 0.14.31", "pin-project-lite", "tokio", "tokio-io-timeout", @@ -2291,7 +2441,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper 1.4.1", + "hyper 1.5.1", "hyper-util", "native-tls", "tokio", @@ -2301,29 +2451,28 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.7" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" +checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" dependencies = [ "bytes", "futures-channel", "futures-util", "http 1.1.0", "http-body 1.0.1", - "hyper 1.4.1", + "hyper 1.5.1", "pin-project-lite", "socket2", "tokio", - "tower", "tower-service", "tracing", ] [[package]] name = "iana-time-zone" -version = "0.1.60" +version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -2342,6 +2491,124 @@ dependencies = [ "cc", ] +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + [[package]] name = "id-pool" version = "0.2.2" @@ -2357,16 +2624,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" -[[package]] -name = "idna" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - [[package]] name = "idna" version = "0.4.0" @@ -2379,12 +2636,34 @@ dependencies = [ [[package]] name = "idna" -version = "0.5.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "image" +version = "0.25.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd6f44aed642f18953a158afeb30206f4d50da59fbc66ecb53c66488de73563b" +dependencies = [ + "bytemuck", + "byteorder-lite", + "num-traits", ] [[package]] @@ -2413,7 +2692,7 @@ dependencies = [ [[package]] name = "imbl-value" version = "0.1.0" -source = "git+https://github.com/Start9Labs/imbl-value.git#48dc39a762a3b4f9300d3b9f850cbd394e777ae0" +source = "git+https://github.com/Start9Labs/imbl-value.git#3ce01b17ae5e756fc829ee5e3513a1b19b2a03fc" dependencies = [ "imbl", "serde", @@ -2460,27 +2739,27 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.4.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", - "hashbrown 0.14.5", + "hashbrown 0.15.1", "serde", ] [[package]] name = "indicatif" -version = "0.17.8" +version = "0.17.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "763a5a8f45087d6bcea4222e7b72c291a054edf80e4ef6efd2a4979878c7bea3" +checksum = "cbf675b85ed934d3c67b5c5469701eec7db22689d0a2139d856e0925fa28b281" dependencies = [ "console", - "instant", "number_prefix", "portable-atomic", "tokio", - "unicode-width", + "unicode-width 0.2.0", + "web-time", ] [[package]] @@ -2492,15 +2771,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "instant" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" -dependencies = [ - "cfg-if", -] - [[package]] name = "integer-encoding" version = "4.0.2" @@ -2513,9 +2783,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.9.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" dependencies = [ "serde", ] @@ -2675,9 +2945,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.70" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" dependencies = [ "wasm-bindgen", ] @@ -2736,7 +3006,7 @@ dependencies = [ "petgraph", "pico-args", "regex", - "regex-syntax 0.8.4", + "regex-syntax 0.8.5", "string_cache", "term", "tiny-keccak", @@ -2750,7 +3020,7 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "507460a910eb7b32ee961886ff48539633b788a36b65692b95f225b844c82553" dependencies = [ - "regex-automata 0.4.7", + "regex-automata 0.4.9", ] [[package]] @@ -2799,9 +3069,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.155" +version = "0.2.164" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f" [[package]] name = "libloading" @@ -2815,9 +3085,9 @@ dependencies = [ [[package]] name = "libm" -version = "0.2.8" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" [[package]] name = "libredox" @@ -2827,7 +3097,7 @@ checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ "bitflags 2.6.0", "libc", - "redox_syscall 0.5.3", + "redox_syscall 0.5.7", ] [[package]] @@ -2853,6 +3123,18 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +[[package]] +name = "litemap" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" + +[[package]] +name = "litrs" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" + [[package]] name = "lock_api" version = "0.4.12" @@ -2926,9 +3208,9 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memmap2" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322" +checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f" dependencies = [ "libc", ] @@ -2972,6 +3254,15 @@ dependencies = [ "adler", ] +[[package]] +name = "miniz_oxide" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +dependencies = [ + "adler2", +] + [[package]] name = "mio" version = "1.0.2" @@ -2995,7 +3286,7 @@ checksum = "c9be0862c1b3f26a88803c4a49de6889c10e608b3ee9344e6ef5b45fb37ad3d1" name = "models" version = "0.1.0" dependencies = [ - "axum 0.7.5", + "axum 0.7.9", "base64 0.21.7", "color-eyre", "ed25519-dalek 2.1.1", @@ -3055,18 +3346,6 @@ dependencies = [ "unicase", ] -[[package]] -name = "nix" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa9b4819da1bc61c0ea48b63b7bc8604064dd43013e7cc325df098d49cd7c18a" -dependencies = [ - "bitflags 1.3.2", - "cc", - "cfg-if", - "libc", -] - [[package]] name = "nix" version = "0.24.3" @@ -3271,7 +3550,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.87", ] [[package]] @@ -3290,10 +3569,19 @@ dependencies = [ ] [[package]] -name = "once_cell" -version = "1.19.0" +name = "oid-registry" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "a8d8034d9489cdaf79228eb9f6a3b8d7bb32ba00d6645ebd48eef4077ceb5bd9" +dependencies = [ + "asn1-rs", +] + +[[package]] +name = "once_cell" +version = "1.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "opaque-debug" @@ -3316,9 +3604,9 @@ dependencies = [ [[package]] name = "openssl" -version = "0.10.66" +version = "0.10.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" +checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" dependencies = [ "bitflags 2.6.0", "cfg-if", @@ -3337,7 +3625,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.87", ] [[package]] @@ -3348,18 +3636,18 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-src" -version = "300.3.1+3.3.1" +version = "300.4.1+3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7259953d42a81bf137fbbd73bd30a8e1914d6dce43c2b90ed575783a22608b91" +checksum = "faa4eac4138c62414b5622d1b31c5c304f34b406b013c079c2bbc652fdd6678c" dependencies = [ "cc", ] [[package]] name = "openssl-sys" -version = "0.9.103" +version = "0.9.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" +checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" dependencies = [ "cc", "libc", @@ -3436,7 +3724,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.3", + "redox_syscall 0.5.7", "smallvec", "windows-targets 0.52.6", ] @@ -3498,6 +3786,16 @@ dependencies = [ "hmac", ] +[[package]] +name = "pem" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae" +dependencies = [ + "base64 0.22.1", + "serde", +] + [[package]] name = "pem-rfc7468" version = "0.7.0" @@ -3515,9 +3813,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.11" +version = "2.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd53dff83f26735fdc1ca837098ccf133605d794cdae66acfc2bfac3ec809d95" +checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442" dependencies = [ "memchr", "thiserror", @@ -3526,9 +3824,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.11" +version = "2.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a548d2beca6773b1c244554d36fcf8548a8a58e74156968211567250e48e49a" +checksum = "d214365f632b123a47fd913301e14c946c61d1c183ee245fa76eb752e59a02dd" dependencies = [ "pest", "pest_generator", @@ -3536,22 +3834,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.11" +version = "2.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c93a82e8d145725dcbaf44e5ea887c8a869efdcc28706df2d08c69e17077183" +checksum = "eb55586734301717aea2ac313f50b2eb8f60d2fc3dc01d190eefa2e625f60c4e" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.87", ] [[package]] name = "pest_meta" -version = "2.7.11" +version = "2.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a941429fea7e08bedec25e4f6785b6ffaacc6b755da98df5ef3e7dcf4a124c4f" +checksum = "b75da2a70cf4d9cb76833c990ac9cd3923c9a8905a8929789ce347c84564d03d" dependencies = [ "once_cell", "pest", @@ -3565,7 +3863,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", - "indexmap 2.4.0", + "indexmap 2.6.0", ] [[package]] @@ -3585,29 +3883,29 @@ checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" [[package]] name = "pin-project" -version = "1.1.5" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.5" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.87", ] [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" [[package]] name = "pin-utils" @@ -3638,15 +3936,15 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "portable-atomic" -version = "1.7.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265" +checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" [[package]] name = "powerfmt" @@ -3671,12 +3969,12 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] name = "prettyplease" -version = "0.2.20" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" +checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" dependencies = [ "proc-macro2", - "syn 2.0.74", + "syn 2.0.87", ] [[package]] @@ -3690,7 +3988,7 @@ dependencies = [ "is-terminal", "lazy_static", "term", - "unicode-width", + "unicode-width 0.1.12", ] [[package]] @@ -3704,18 +4002,18 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "3.1.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" dependencies = [ - "toml_edit 0.21.1", + "toml_edit 0.22.22", ] [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" dependencies = [ "unicode-ident", ] @@ -3760,7 +4058,7 @@ dependencies = [ "rand 0.8.5", "rand_chacha 0.3.1", "rand_xorshift", - "regex-syntax 0.8.4", + "regex-syntax 0.8.5", "rusty-fork", "tempfile", "unarray", @@ -3774,7 +4072,7 @@ checksum = "6ff7ff745a347b87471d859a377a9a404361e7efc2a971d73424a6d183c0fc77" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.87", ] [[package]] @@ -3797,7 +4095,7 @@ dependencies = [ "itertools 0.12.1", "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.87", ] [[package]] @@ -3817,14 +4115,23 @@ checksum = "33cb294fe86a74cbcf50d4445b37da762029549ebeea341421c7c70370f86cac" [[package]] name = "publicsuffix" -version = "2.2.3" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96a8c1bda5ae1af7f99a2962e49df150414a43d62404644d98dd5c3a93d07457" +checksum = "6f42ea446cab60335f76979ec15e12619a2165b5ae2c12166bef27d283a9fadf" dependencies = [ - "idna 0.3.0", + "idna 1.0.3", "psl-types", ] +[[package]] +name = "qrcode" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d68782463e408eb1e668cf6152704bd856c78c5b6417adaee3203d8f4c1fc9ec" +dependencies = [ + "image", +] + [[package]] name = "quick-error" version = "1.2.3" @@ -3833,9 +4140,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.36" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -3951,6 +4258,18 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "rcgen" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48406db8ac1f3cbc7dcdb56ec355343817958a356ff430259bb07baf7607e1e1" +dependencies = [ + "pem", + "ring", + "time", + "yasna", +] + [[package]] name = "redox_syscall" version = "0.1.57" @@ -3968,27 +4287,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.4.1" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "redox_syscall" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ "bitflags 2.6.0", ] [[package]] name = "redox_users" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ "getrandom 0.2.15", "libredox", @@ -3997,14 +4307,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.6" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.7", - "regex-syntax 0.8.4", + "regex-automata 0.4.9", + "regex-syntax 0.8.5", ] [[package]] @@ -4018,13 +4328,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.4", + "regex-syntax 0.8.5", ] [[package]] @@ -4035,15 +4345,15 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "reqwest" -version = "0.12.5" +version = "0.12.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7d6d2a27d57148378eb5e111173f4276ad26340ecc5c49a4a2152167a2d6a37" +checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f" dependencies = [ "base64 0.22.1", "bytes", @@ -4052,11 +4362,11 @@ dependencies = [ "encoding_rs", "futures-core", "futures-util", - "h2 0.4.5", + "h2 0.4.7", "http 1.1.0", "http-body 1.0.1", "http-body-util", - "hyper 1.4.1", + "hyper 1.5.1", "hyper-rustls", "hyper-tls", "hyper-util", @@ -4068,7 +4378,7 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls-pemfile 2.1.3", + "rustls-pemfile 2.2.0", "serde", "serde_json", "serde_urlencoded", @@ -4084,7 +4394,7 @@ dependencies = [ "wasm-bindgen-futures", "wasm-streams", "web-sys", - "winreg", + "windows-registry", ] [[package]] @@ -4138,11 +4448,11 @@ dependencies = [ [[package]] name = "rpc-toolkit" version = "0.2.3" -source = "git+https://github.com/Start9Labs/rpc-toolkit.git?branch=refactor/no-dyn-ctx#60a974a29c5e6380f7bbfbc1b4716f6d2b20b189" +source = "git+https://github.com/Start9Labs/rpc-toolkit.git?branch=refactor%2Fno-dyn-ctx#21e35d85fb8f5de0e046c7ab5266236c2b639a4b" dependencies = [ "async-stream", "async-trait", - "axum 0.7.5", + "axum 0.7.9", "clap", "futures", "http 1.1.0", @@ -4219,18 +4529,27 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustc_version" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ "semver", ] [[package]] -name = "rustix" -version = "0.38.34" +name = "rusticata-macros" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" +dependencies = [ + "nom 7.1.3", +] + +[[package]] +name = "rustix" +version = "0.38.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6" dependencies = [ "bitflags 2.6.0", "errno 0.3.9", @@ -4252,15 +4571,30 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.12" +version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044" +checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" +dependencies = [ + "log", + "ring", + "rustls-pki-types", + "rustls-webpki 0.102.8", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls" +version = "0.23.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f1a745511c54ba6d4465e8d5dfbd81b45791756de28d4981af70d6dca128f1e" dependencies = [ "aws-lc-rs", "log", "once_cell", + "ring", "rustls-pki-types", - "rustls-webpki 0.102.6", + "rustls-webpki 0.102.8", "subtle", "zeroize", ] @@ -4276,19 +4610,18 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "2.1.3" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" dependencies = [ - "base64 0.22.1", "rustls-pki-types", ] [[package]] name = "rustls-pki-types" -version = "1.8.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" +checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" [[package]] name = "rustls-webpki" @@ -4302,9 +4635,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.102.6" +version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e6b52d4fda176fd835fdc55a835d4a89b8499cad995885a21149d5ad62f852e" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ "aws-lc-rs", "ring", @@ -4314,9 +4647,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" [[package]] name = "rusty-fork" @@ -4343,7 +4676,7 @@ dependencies = [ "thingbuf", "thiserror", "unicode-segmentation", - "unicode-width", + "unicode-width 0.1.12", ] [[package]] @@ -4363,11 +4696,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.23" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -4415,9 +4748,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.11.1" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75da29fe9b9b08fe9d6b22b5b4bcbc75d8db3aa31e639aa56bb62e9d46bfceaf" +checksum = "fa39c7303dc58b5543c94d22c1766b0d31f2ee58306363ea622b10bbc075eaa2" dependencies = [ "core-foundation-sys", "libc", @@ -4434,9 +4767,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.208" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" dependencies = [ "serde_derive", ] @@ -4460,22 +4793,22 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.208" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.87", ] [[package]] name = "serde_json" -version = "1.0.125" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83c8e735a073ccf5be70aa8066aa984eaf2fa000db6c8d0100ae605b366d31ed" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ - "indexmap 2.4.0", + "indexmap 2.6.0", "itoa", "memchr", "ryu", @@ -4493,10 +4826,21 @@ dependencies = [ ] [[package]] -name = "serde_spanned" -version = "0.6.7" +name = "serde_qs" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" +checksum = "0431a35568651e363364210c91983c1da5eb29404d9f0928b67d4ebcfa7d330c" +dependencies = [ + "percent-encoding", + "serde", + "thiserror", +] + +[[package]] +name = "serde_spanned" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" dependencies = [ "serde", ] @@ -4515,15 +4859,15 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.9.0" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cecfa94848272156ea67b2b1a53f20fc7bc638c4a46d2f8abde08f05f4b857" +checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817" dependencies = [ "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.4.0", + "indexmap 2.6.0", "serde", "serde_derive", "serde_json", @@ -4533,14 +4877,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.9.0" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8fee4991ef4f274617a51ad4af30519438dacb2f56ac773b08a1922ff743350" +checksum = "9d846214a9854ef724f3da161b426242d8de7c1fc7de2f89bb1efcb154dca79d" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.87", ] [[package]] @@ -4549,7 +4893,7 @@ version = "0.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ce6afeda22f0b55dde2c34897bce76a629587348480384231205c14b59a01f" dependencies = [ - "indexmap 2.4.0", + "indexmap 2.6.0", "itoa", "libyml", "log", @@ -4741,9 +5085,9 @@ dependencies = [ [[package]] name = "sqlformat" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f895e3734318cc55f1fe66258926c9b910c124d47520339efecbb6c59cec7c1f" +checksum = "7bba3a93db0cc4f7bdece8bb09e77e2e785c20bfebf79eb8340ed80708048790" dependencies = [ "nom 7.1.3", "unicode_categories", @@ -4784,7 +5128,7 @@ dependencies = [ "futures-util", "hashlink", "hex", - "indexmap 2.4.0", + "indexmap 2.6.0", "log", "memchr", "once_cell", @@ -4802,7 +5146,7 @@ dependencies = [ "tokio-stream", "tracing", "url", - "webpki-roots", + "webpki-roots 0.25.4", ] [[package]] @@ -4973,8 +5317,8 @@ dependencies = [ "quote", "regex-syntax 0.6.29", "strsim 0.10.0", - "syn 2.0.74", - "unicode-width", + "syn 2.0.87", + "unicode-width 0.1.12", ] [[package]] @@ -5000,9 +5344,9 @@ dependencies = [ [[package]] name = "ssh-key" -version = "0.6.6" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca9b366a80cf18bb6406f4cf4d10aebfb46140a8c0c33f666a144c5c76ecbafc" +checksum = "3b86f5297f0f04d08cabaa0f6bff7cb6aec4d9c3b49d87990d63da9d9156a8c3" dependencies = [ "ed25519-dalek 2.1.1", "p256", @@ -5019,15 +5363,22 @@ dependencies = [ "zeroize", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "start-os" -version = "0.3.6-alpha.5" +version = "0.3.6-alpha.8" dependencies = [ "aes", + "async-acme", "async-compression", "async-stream", "async-trait", - "axum 0.7.5", + "axum 0.7.9", "axum-server", "backhand", "barrage", @@ -5066,7 +5417,7 @@ dependencies = [ "imbl", "imbl-value", "include_dir", - "indexmap 2.4.0", + "indexmap 2.6.0", "indicatif", "integer-encoding", "ipnet", @@ -5102,6 +5453,7 @@ dependencies = [ "procfs", "proptest", "proptest-derive", + "qrcode", "rand 0.8.5", "regex", "reqwest", @@ -5128,7 +5480,7 @@ dependencies = [ "textwrap", "thiserror", "tokio", - "tokio-rustls", + "tokio-rustls 0.26.0", "tokio-socks", "tokio-stream", "tokio-tar", @@ -5144,13 +5496,12 @@ dependencies = [ "tracing-subscriber", "trust-dns-server", "ts-rs", + "tty-spawn", "typed-builder", "unix-named-pipe", - "unshare", "url", "urlencoding", "uuid", - "which 6.0.3", "zeroize", ] @@ -5215,9 +5566,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.74" +version = "2.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fceb41e3d546d0bd83421d3409b1460cc7444cd389341a4c880fe7a042cb3d7" +checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" dependencies = [ "proc-macro2", "quote", @@ -5235,23 +5586,37 @@ name = "sync_wrapper" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] [[package]] name = "system-configuration" -version = "0.5.1" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.6.0", "core-foundation", "system-configuration-sys", ] [[package]] name = "system-configuration-sys" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" dependencies = [ "core-foundation-sys", "libc", @@ -5265,9 +5630,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tar" -version = "0.4.41" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb797dad5fb5b76fcf519e702f4a589483b5ef06567f160c392832c1f5e44909" +checksum = "c65998313f8e17d0d553d28f91a0df93e4dbbbf770279c7bc21ca0f09ea1a1f6" dependencies = [ "filetime", "libc", @@ -5276,9 +5641,9 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.12.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" +checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" dependencies = [ "cfg-if", "fastrand", @@ -5315,7 +5680,7 @@ checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" dependencies = [ "smawk", "unicode-linebreak", - "unicode-width", + "unicode-width 0.1.12", ] [[package]] @@ -5330,22 +5695,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.63" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.63" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.87", ] [[package]] @@ -5409,6 +5774,16 @@ dependencies = [ "crunchy", ] +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + [[package]] name = "tinyvec" version = "1.8.0" @@ -5426,9 +5801,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.39.2" +version = "1.41.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1" +checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33" dependencies = [ "backtrace", "bytes", @@ -5461,7 +5836,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.87", ] [[package]] @@ -5474,13 +5849,24 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-rustls" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" +dependencies = [ + "rustls 0.22.4", + "rustls-pki-types", + "tokio", +] + [[package]] name = "tokio-rustls" version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls 0.23.12", + "rustls 0.23.17", "rustls-pki-types", "tokio", ] @@ -5499,9 +5885,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" +checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" dependencies = [ "futures-core", "pin-project-lite", @@ -5523,18 +5909,6 @@ dependencies = [ "xattr 0.2.3", ] -[[package]] -name = "tokio-tungstenite" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c83b561d025642014097b66e6c1bb422783339e0909e4429cde4749d1990bc38" -dependencies = [ - "futures-util", - "log", - "tokio", - "tungstenite 0.21.0", -] - [[package]] name = "tokio-tungstenite" version = "0.23.1" @@ -5550,10 +5924,22 @@ dependencies = [ ] [[package]] -name = "tokio-util" -version = "0.7.11" +name = "tokio-tungstenite" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +checksum = "edc5f74e248dc973e0dbb7b74c7e0d6fcc301c694ff50049504004ef4d0cdcd9" +dependencies = [ + "futures-util", + "log", + "tokio", + "tungstenite 0.24.0", +] + +[[package]] +name = "tokio-util" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" dependencies = [ "bytes", "futures-core", @@ -5583,7 +5969,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.20", + "toml_edit 0.22.22", ] [[package]] @@ -5601,7 +5987,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.4.0", + "indexmap 2.6.0", "serde", "serde_spanned", "toml_datetime", @@ -5610,26 +5996,15 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.21.1" +version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ - "indexmap 2.4.0", - "toml_datetime", - "winnow 0.5.40", -] - -[[package]] -name = "toml_edit" -version = "0.22.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" -dependencies = [ - "indexmap 2.4.0", + "indexmap 2.6.0", "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.18", + "winnow 0.6.20", ] [[package]] @@ -5646,14 +6021,14 @@ dependencies = [ "h2 0.3.26", "http 0.2.12", "http-body 0.4.6", - "hyper 0.14.30", + "hyper 0.14.31", "hyper-timeout", "percent-encoding", "pin-project", "prost", "tokio", "tokio-stream", - "tower", + "tower 0.4.13", "tower-layer", "tower-service", "tracing", @@ -5662,7 +6037,7 @@ dependencies = [ [[package]] name = "torut" version = "0.2.1" -source = "git+https://github.com/Start9Labs/torut.git?branch=update/dependencies#cc7a1425a01214465e106975e6690794d8551bdb" +source = "git+https://github.com/Start9Labs/torut.git?branch=update%2Fdependencies#cc7a1425a01214465e106975e6690794d8551bdb" dependencies = [ "base32 0.4.0", "base64 0.21.7", @@ -5698,6 +6073,22 @@ dependencies = [ "tracing", ] +[[package]] +name = "tower" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper 0.1.2", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "tower-layer" version = "0.3.3" @@ -5730,7 +6121,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.87", ] [[package]] @@ -5868,7 +6259,7 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "ts-rs" version = "8.1.0" -source = "git+https://github.com/dr-bonez/ts-rs.git?branch=feature/top-level-as#7ae88ade90b5e724159048a663a0bdb04bed27f7" +source = "git+https://github.com/dr-bonez/ts-rs.git?branch=feature%2Ftop-level-as#7ae88ade90b5e724159048a663a0bdb04bed27f7" dependencies = [ "thiserror", "ts-rs-macros", @@ -5877,32 +6268,24 @@ dependencies = [ [[package]] name = "ts-rs-macros" version = "8.1.0" -source = "git+https://github.com/dr-bonez/ts-rs.git?branch=feature/top-level-as#7ae88ade90b5e724159048a663a0bdb04bed27f7" +source = "git+https://github.com/dr-bonez/ts-rs.git?branch=feature%2Ftop-level-as#7ae88ade90b5e724159048a663a0bdb04bed27f7" dependencies = [ "Inflector", "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.87", "termcolor", ] [[package]] -name = "tungstenite" -version = "0.21.0" +name = "tty-spawn" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1" +checksum = "cb91489cf2611235ae8d755d66ab028437980ee573e2230c05af41b136236ad1" dependencies = [ - "byteorder", - "bytes", - "data-encoding", - "http 1.1.0", - "httparse", - "log", - "rand 0.8.5", - "sha1", - "thiserror", - "url", - "utf-8", + "anyhow", + "nix 0.29.0", + "signal-hook", ] [[package]] @@ -5925,6 +6308,24 @@ dependencies = [ "utf-8", ] +[[package]] +name = "tungstenite" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http 1.1.0", + "httparse", + "log", + "rand 0.8.5", + "sha1", + "thiserror", + "utf-8", +] + [[package]] name = "typed-builder" version = "0.18.2" @@ -5942,7 +6343,7 @@ checksum = "1f718dfaf347dcb5b983bfc87608144b0bad87970aebcbea5ce44d2a30c08e63" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.87", ] [[package]] @@ -5953,9 +6354,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "ucd-trie" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" [[package]] name = "unarray" @@ -5965,24 +6366,21 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicase" -version = "2.7.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" -dependencies = [ - "version_check", -] +checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" [[package]] name = "unicode-bidi" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" +checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-linebreak" @@ -5992,24 +6390,24 @@ checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" [[package]] name = "unicode-normalization" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" dependencies = [ "tinyvec", ] [[package]] name = "unicode-properties" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4259d9d4425d9f0661581b804cb85fe66a4c631cadd8f490d1c13a35d5d9291" +checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" [[package]] name = "unicode-segmentation" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-width" @@ -6018,10 +6416,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" [[package]] -name = "unicode-xid" -version = "0.2.4" +name = "unicode-width" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "unicode_categories" @@ -6039,16 +6443,6 @@ dependencies = [ "libc", ] -[[package]] -name = "unshare" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ceda295552a1eda89f8a748237654ad76b9c87e383fc07af5c4e423eb8e7b9b" -dependencies = [ - "libc", - "nix 0.20.0", -] - [[package]] name = "untrusted" version = "0.9.0" @@ -6057,12 +6451,12 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.2" +version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +checksum = "8d157f1b96d14500ffdc1f10ba712e780825526c03d9a49b4d0324b0d9113ada" dependencies = [ "form_urlencoded", - "idna 0.5.0", + "idna 1.0.3", "percent-encoding", "serde", ] @@ -6079,6 +6473,18 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "utf8parse" version = "0.2.2" @@ -6087,9 +6493,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" +checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" dependencies = [ "getrandom 0.2.15", ] @@ -6160,9 +6566,9 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" dependencies = [ "cfg-if", "once_cell", @@ -6171,24 +6577,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.87", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.43" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" +checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" dependencies = [ "cfg-if", "js-sys", @@ -6198,9 +6604,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -6208,28 +6614,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.87", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" [[package]] name = "wasm-streams" -version = "0.4.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129" +checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" dependencies = [ "futures-util", "js-sys", @@ -6240,9 +6646,19 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.70" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" +checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" dependencies = [ "js-sys", "wasm-bindgen", @@ -6254,6 +6670,15 @@ version = "0.25.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" +[[package]] +name = "webpki-roots" +version = "0.26.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841c67bff177718f1d4dfefde8d8f0e78f9b6589319ba88312f567fc5841a958" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "which" version = "4.4.2" @@ -6266,25 +6691,13 @@ dependencies = [ "rustix", ] -[[package]] -name = "which" -version = "6.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ee928febd44d98f2f459a4a79bd4d928591333a494a10a868418ac1b39cf1f" -dependencies = [ - "either", - "home", - "rustix", - "winsafe", -] - [[package]] name = "whoami" -version = "1.5.1" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44ab49fad634e88f55bf8f9bb3abd2f27d7204172a112c7c9987e01c1c94ea9" +checksum = "372d5b87f58ec45c384ba03563b03544dc5fadc3983e434b286913f5b4a9bb6d" dependencies = [ - "redox_syscall 0.4.1", + "redox_syscall 0.5.7", "wasite", ] @@ -6328,6 +6741,36 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-registry" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" +dependencies = [ + "windows-result", + "windows-strings", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -6487,28 +6930,24 @@ dependencies = [ [[package]] name = "winnow" -version = "0.6.18" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" dependencies = [ "memchr", ] [[package]] -name = "winreg" -version = "0.52.0" +name = "write16" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" [[package]] -name = "winsafe" -version = "0.0.19" +name = "writeable" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" [[package]] name = "wyz" @@ -6525,6 +6964,23 @@ dependencies = [ "tap", ] +[[package]] +name = "x509-parser" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcbc162f30700d6f3f82a24bf7cc62ffe7caea42c0b2cba8bf7f3ae50cf51f69" +dependencies = [ + "asn1-rs", + "data-encoding", + "der-parser", + "lazy_static", + "nom 7.1.3", + "oid-registry", + "rusticata-macros", + "thiserror", + "time", +] + [[package]] name = "xattr" version = "0.2.3" @@ -6578,6 +7034,39 @@ dependencies = [ "serde", ] +[[package]] +name = "yasna" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" +dependencies = [ + "time", +] + +[[package]] +name = "yoke" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", + "synstructure", +] + [[package]] name = "zerocopy" version = "0.7.35" @@ -6596,7 +7085,28 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.87", +] + +[[package]] +name = "zerofrom" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", + "synstructure", ] [[package]] @@ -6616,7 +7126,29 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.87", +] + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", ] [[package]] diff --git a/core/build-cli.sh b/core/build-cli.sh new file mode 100755 index 000000000..8e069a690 --- /dev/null +++ b/core/build-cli.sh @@ -0,0 +1,50 @@ +#!/bin/bash + +cd "$(dirname "${BASH_SOURCE[0]}")" + +set -ea +shopt -s expand_aliases + +if [ -z "$ARCH" ]; then + ARCH=$(uname -m) +fi +if [ "$ARCH" = "arm64" ]; then + ARCH="aarch64" +fi + +if [ -z "$KERNEL_NAME" ]; then + KERNEL_NAME=$(uname -s) +fi + +if [ -z "$TARGET" ]; then + if [ "$KERNEL_NAME" = "Linux" ]; then + TARGET="$ARCH-unknown-linux-musl" + elif [ "$KERNEL_NAME" = "Darwin" ]; then + TARGET="$ARCH-apple-darwin" + else + >&2 echo "unknown kernel $KERNEL_NAME" + exit 1 + fi +fi + +USE_TTY= +if tty -s; then + USE_TTY="-it" +fi + +cd .. +FEATURES="$(echo $ENVIRONMENT | sed 's/-/,/g')" +RUSTFLAGS="" + +if [[ "${ENVIRONMENT}" =~ (^|-)unstable($|-) ]]; then + RUSTFLAGS="--cfg tokio_unstable" +fi + +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' + +echo "FEATURES=\"$FEATURES\"" +echo "RUSTFLAGS=\"$RUSTFLAGS\"" +rust-zig-builder sh -c "cd core && cargo zigbuild --release --no-default-features --features cli,daemon,$FEATURES --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 \ No newline at end of file diff --git a/core/helpers/src/lib.rs b/core/helpers/src/lib.rs index 80631fea2..a9df58ece 100644 --- a/core/helpers/src/lib.rs +++ b/core/helpers/src/lib.rs @@ -6,6 +6,7 @@ use std::time::Duration; use color_eyre::eyre::{eyre, Context, Error}; use futures::future::BoxFuture; use futures::FutureExt; +use models::ResultExt; use tokio::fs::File; use tokio::sync::oneshot; use tokio::task::{JoinError, JoinHandle, LocalSet}; @@ -176,7 +177,7 @@ impl Drop for AtomicFile { if let Some(file) = self.file.take() { drop(file); let path = std::mem::take(&mut self.tmp_path); - tokio::spawn(async move { tokio::fs::remove_file(path).await.unwrap() }); + tokio::spawn(async move { tokio::fs::remove_file(path).await.log_err() }); } } } diff --git a/core/startos/src/util/clap.rs b/core/models/src/clap.rs similarity index 91% rename from core/startos/src/util/clap.rs rename to core/models/src/clap.rs index 7c3b5a0bc..122e8cf9d 100644 --- a/core/startos/src/util/clap.rs +++ b/core/models/src/clap.rs @@ -1,9 +1,8 @@ use std::marker::PhantomData; use std::str::FromStr; -use clap::builder::TypedValueParser; - -use crate::prelude::*; +use rpc_toolkit::clap; +use rpc_toolkit::clap::builder::TypedValueParser; pub struct FromStrParser(PhantomData); impl FromStrParser { diff --git a/core/models/src/errors.rs b/core/models/src/errors.rs index ee6b0ae12..2077a8bbd 100644 --- a/core/models/src/errors.rs +++ b/core/models/src/errors.rs @@ -322,6 +322,11 @@ impl From for Error { Error::new(e, kind) } } +impl From for Error { + fn from(e: torut::onion::OnionAddressParseError) -> Self { + Error::new(e, ErrorKind::Tor) + } +} impl From for Error { fn from(value: patch_db::value::Error) -> Self { match value.kind { @@ -351,6 +356,14 @@ impl Debug for ErrorData { } } impl std::error::Error for ErrorData {} +impl From for ErrorData { + fn from(value: Error) -> Self { + Self { + details: value.to_string(), + debug: format!("{:?}", value), + } + } +} impl From<&RpcError> for ErrorData { fn from(value: &RpcError) -> Self { Self { diff --git a/core/models/src/id/mod.rs b/core/models/src/id/mod.rs index 85c9d8255..90dbc978c 100644 --- a/core/models/src/id/mod.rs +++ b/core/models/src/id/mod.rs @@ -11,6 +11,7 @@ mod host; mod image; mod invalid_id; mod package; +mod replay; mod service_interface; mod volume; @@ -20,6 +21,7 @@ pub use host::HostId; pub use image::ImageId; pub use invalid_id::InvalidId; pub use package::{PackageId, SYSTEM_PACKAGE_ID}; +pub use replay::ReplayId; pub use service_interface::ServiceInterfaceId; pub use volume::VolumeId; diff --git a/core/models/src/id/replay.rs b/core/models/src/id/replay.rs new file mode 100644 index 000000000..299b6160a --- /dev/null +++ b/core/models/src/id/replay.rs @@ -0,0 +1,45 @@ +use std::convert::Infallible; +use std::path::Path; +use std::str::FromStr; + +use serde::{Deserialize, Serialize}; +use ts_rs::TS; +use yasi::InternedString; + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, TS)] +#[ts(type = "string")] +pub struct ReplayId(InternedString); +impl FromStr for ReplayId { + type Err = Infallible; + fn from_str(s: &str) -> Result { + Ok(ReplayId(InternedString::intern(s))) + } +} +impl AsRef for ReplayId { + fn as_ref(&self) -> &ReplayId { + self + } +} +impl std::fmt::Display for ReplayId { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", &self.0) + } +} +impl AsRef for ReplayId { + fn as_ref(&self) -> &str { + self.0.as_ref() + } +} +impl AsRef for ReplayId { + fn as_ref(&self) -> &Path { + self.0.as_ref() + } +} +impl<'de> Deserialize<'de> for ReplayId { + fn deserialize(deserializer: D) -> Result + where + D: serde::de::Deserializer<'de>, + { + Ok(ReplayId(serde::Deserialize::deserialize(deserializer)?)) + } +} diff --git a/core/models/src/id/service_interface.rs b/core/models/src/id/service_interface.rs index 25aec0aba..f08d89cd5 100644 --- a/core/models/src/id/service_interface.rs +++ b/core/models/src/id/service_interface.rs @@ -1,9 +1,11 @@ use std::path::Path; +use std::str::FromStr; +use rpc_toolkit::clap::builder::ValueParserFactory; use serde::{Deserialize, Deserializer, Serialize}; use ts_rs::TS; -use crate::Id; +use crate::{FromStrParser, Id}; #[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, TS)] #[ts(export, type = "string")] @@ -59,3 +61,15 @@ impl sqlx::Type for ServiceInterfaceId { <&str as sqlx::Type>::compatible(ty) } } +impl FromStr for ServiceInterfaceId { + type Err = ::Err; + fn from_str(s: &str) -> Result { + Id::from_str(s).map(Self) + } +} +impl ValueParserFactory for ServiceInterfaceId { + type Parser = FromStrParser; + fn value_parser() -> Self::Parser { + FromStrParser::new() + } +} diff --git a/core/models/src/lib.rs b/core/models/src/lib.rs index ad9055f24..304ac87c5 100644 --- a/core/models/src/lib.rs +++ b/core/models/src/lib.rs @@ -1,3 +1,4 @@ +mod clap; mod data_url; mod errors; mod id; @@ -5,6 +6,7 @@ mod mime; mod procedure_name; mod version; +pub use clap::*; pub use data_url::*; pub use errors::*; pub use id::*; diff --git a/core/models/src/procedure_name.rs b/core/models/src/procedure_name.rs index 466835818..4a4a682e6 100644 --- a/core/models/src/procedure_name.rs +++ b/core/models/src/procedure_name.rs @@ -1,38 +1,30 @@ use serde::{Deserialize, Serialize}; -use crate::{ActionId, PackageId}; +use crate::ActionId; #[derive(Debug, Clone, Serialize, Deserialize)] pub enum ProcedureName { GetConfig, SetConfig, CreateBackup, - Properties, RestoreBackup, - ActionMetadata, + GetActionInput(ActionId), RunAction(ActionId), - GetAction(ActionId), - QueryDependency(PackageId), - UpdateDependency(PackageId), - Init, - Uninit, + PackageInit, + PackageUninit, } impl ProcedureName { pub fn js_function_name(&self) -> String { match self { - ProcedureName::Init => "/init".to_string(), - ProcedureName::Uninit => "/uninit".to_string(), + ProcedureName::PackageInit => "/packageInit".to_string(), + ProcedureName::PackageUninit => "/packageUninit".to_string(), ProcedureName::SetConfig => "/config/set".to_string(), ProcedureName::GetConfig => "/config/get".to_string(), ProcedureName::CreateBackup => "/backup/create".to_string(), - ProcedureName::Properties => "/properties".to_string(), ProcedureName::RestoreBackup => "/backup/restore".to_string(), - ProcedureName::ActionMetadata => "/actions/metadata".to_string(), ProcedureName::RunAction(id) => format!("/actions/{}/run", id), - ProcedureName::GetAction(id) => format!("/actions/{}/get", id), - ProcedureName::QueryDependency(id) => format!("/dependencies/{}/query", id), - ProcedureName::UpdateDependency(id) => format!("/dependencies/{}/update", id), + ProcedureName::GetActionInput(id) => format!("/actions/{}/getInput", id), } } } diff --git a/core/startos/Cargo.toml b/core/startos/Cargo.toml index d0228ba31..e2a20a0a1 100644 --- a/core/startos/Cargo.toml +++ b/core/startos/Cargo.toml @@ -14,7 +14,7 @@ keywords = [ name = "start-os" readme = "README.md" repository = "https://github.com/Start9Labs/start-os" -version = "0.3.6-alpha.5" +version = "0.3.6-alpha.8" license = "MIT" [lib] @@ -39,10 +39,10 @@ path = "src/main.rs" [features] cli = [] -container-runtime = ["procfs", "unshare"] +container-runtime = ["procfs", "tty-spawn"] daemon = [] registry = [] -default = ["cli", "daemon"] +default = ["cli", "daemon", "registry", "container-runtime"] dev = [] unstable = ["console-subscriber", "tokio/tracing"] docker = [] @@ -50,6 +50,10 @@ test = [] [dependencies] aes = { version = "0.7.5", features = ["ctr"] } +async-acme = { version = "0.5.0", git = "https://github.com/dr-bonez/async-acme.git", features = [ + "use_rustls", + "use_tokio", +] } async-compression = { version = "0.4.4", features = [ "gzip", "brotli", @@ -156,6 +160,7 @@ prettytable-rs = "0.10.0" procfs = { version = "0.16.0", optional = true } proptest = "1.3.1" proptest-derive = "0.5.0" +qrcode = "0.14.1" rand = { version = "0.8.5", features = ["std"] } regex = "1.10.2" reqwest = { version = "0.12.4", features = ["stream", "json", "socks"] } @@ -197,7 +202,7 @@ tokio-util = { version = "0.7.9", features = ["io"] } torut = { git = "https://github.com/Start9Labs/torut.git", branch = "update/dependencies", features = [ "serialize", ] } -tower-service = "0.3.2" +tower-service = "0.3.3" tracing = "0.1.39" tracing-error = "0.2.0" tracing-futures = "0.2.5" @@ -205,10 +210,9 @@ tracing-journald = "0.3.0" tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } trust-dns-server = "0.23.1" ts-rs = { git = "https://github.com/dr-bonez/ts-rs.git", branch = "feature/top-level-as" } # "8.1.0" +tty-spawn = { version = "0.4.0", optional = true } typed-builder = "0.18.0" -which = "6.0.3" unix-named-pipe = "0.2.0" -unshare = { version = "0.7.0", optional = true } url = { version = "2.4.1", features = ["serde"] } urlencoding = "2.1.3" uuid = { version = "1.4.1", features = ["v4"] } diff --git a/core/startos/registry.service b/core/startos/registry.service new file mode 100644 index 000000000..63941a25e --- /dev/null +++ b/core/startos/registry.service @@ -0,0 +1,13 @@ +[Unit] +Description=StartOS Registry + +[Service] +Type=simple +Environment=RUST_LOG=startos=debug,patch_db=warn +ExecStart=/usr/local/bin/registry +Restart=always +RestartSec=3 +ManagedOOMPreference=avoid + +[Install] +WantedBy=multi-user.target diff --git a/core/startos/src/action.rs b/core/startos/src/action.rs index 7c4492adc..d0748265b 100644 --- a/core/startos/src/action.rs +++ b/core/startos/src/action.rs @@ -1,87 +1,302 @@ -use clap::Parser; +use std::collections::BTreeMap; +use std::fmt; + +use clap::{CommandFactory, FromArgMatches, Parser}; pub use models::ActionId; use models::PackageId; +use qrcode::QrCode; +use rpc_toolkit::{from_fn_async, Context, HandlerExt, ParentHandler}; use serde::{Deserialize, Serialize}; use tracing::instrument; use ts_rs::TS; -use crate::config::Config; -use crate::context::RpcContext; +use crate::context::{CliContext, RpcContext}; use crate::prelude::*; use crate::rpc_continuations::Guid; -use crate::util::serde::{display_serializable, StdinDeserializable, WithIoFormat}; +use crate::util::serde::{ + display_serializable, HandlerExtSerde, StdinDeserializable, WithIoFormat, +}; -#[derive(Debug, Serialize, Deserialize)] +pub fn action_api() -> ParentHandler { + ParentHandler::new() + .subcommand( + "get-input", + from_fn_async(get_action_input) + .with_display_serializable() + .with_about("Get action input spec") + .with_call_remote::(), + ) + .subcommand( + "run", + from_fn_async(run_action) + .with_display_serializable() + .with_custom_display_fn(|_, res| { + if let Some(res) = res { + println!("{res}") + } + Ok(()) + }) + .with_about("Run service action") + .with_call_remote::(), + ) +} + +#[derive(Debug, Clone, Deserialize, Serialize, TS)] +#[ts(export)] +#[serde(rename_all = "camelCase")] +pub struct ActionInput { + #[ts(type = "Record")] + pub spec: Value, + #[ts(type = "Record | null")] + pub value: Option, +} + +#[derive(Deserialize, Serialize, TS, Parser)] +#[serde(rename_all = "camelCase")] +pub struct GetActionInputParams { + pub package_id: PackageId, + pub action_id: ActionId, +} + +#[instrument(skip_all)] +pub async fn get_action_input( + ctx: RpcContext, + GetActionInputParams { + package_id, + action_id, + }: GetActionInputParams, +) -> Result, Error> { + ctx.services + .get(&package_id) + .await + .as_ref() + .or_not_found(lazy_format!("Manager for {}", package_id))? + .get_action_input(Guid::new(), action_id) + .await +} + +#[derive(Debug, Serialize, Deserialize, TS)] #[serde(tag = "version")] +#[ts(export)] pub enum ActionResult { #[serde(rename = "0")] V0(ActionResultV0), + #[serde(rename = "1")] + V1(ActionResultV1), +} +impl fmt::Display for ActionResult { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::V0(res) => res.fmt(f), + Self::V1(res) => res.fmt(f), + } + } } -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize, TS)] pub struct ActionResultV0 { pub message: String, pub value: Option, pub copyable: bool, pub qr: bool, } - -#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub enum DockerStatus { - Running, - Stopped, +impl fmt::Display for ActionResultV0 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.message)?; + if let Some(value) = &self.value { + write!(f, ":\n{value}")?; + if self.qr { + use qrcode::render::unicode; + write!( + f, + "\n{}", + QrCode::new(value.as_bytes()) + .unwrap() + .render::() + .build() + )?; + } + } + Ok(()) + } } -pub fn display_action_result(params: WithIoFormat, result: ActionResult) { +#[derive(Debug, Serialize, Deserialize, TS)] +#[serde(rename_all = "camelCase")] +pub struct ActionResultV1 { + pub title: String, + pub message: Option, + pub result: Option, +} + +#[derive(Debug, Serialize, Deserialize, TS)] +#[serde(rename_all = "camelCase")] +pub struct ActionResultMember { + pub name: String, + pub description: Option, + #[serde(flatten)] + #[ts(flatten)] + pub value: ActionResultValue, +} + +#[derive(Debug, Serialize, Deserialize, TS)] +#[serde(rename_all = "camelCase")] +#[serde(rename_all_fields = "camelCase")] +#[serde(tag = "type")] +pub enum ActionResultValue { + Single { + value: String, + copyable: bool, + qr: bool, + masked: bool, + }, + Group { + value: Vec, + }, +} +impl ActionResultValue { + fn fmt_rec(&self, f: &mut fmt::Formatter<'_>, indent: usize) -> fmt::Result { + match self { + Self::Single { value, qr, .. } => { + for _ in 0..indent { + write!(f, " ")?; + } + write!(f, "{value}")?; + if *qr { + use qrcode::render::unicode; + writeln!(f)?; + for _ in 0..indent { + write!(f, " ")?; + } + write!( + f, + "{}", + QrCode::new(value.as_bytes()) + .unwrap() + .render::() + .build() + )?; + } + } + Self::Group { value } => { + for ActionResultMember { + name, + description, + value, + } in value + { + for _ in 0..indent { + write!(f, " ")?; + } + write!(f, "{name}")?; + if let Some(description) = description { + write!(f, ": {description}")?; + } + writeln!(f, ":")?; + value.fmt_rec(f, indent + 1)?; + } + } + } + Ok(()) + } +} +impl fmt::Display for ActionResultV1 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + writeln!(f, "{}:", self.title)?; + if let Some(message) = &self.message { + writeln!(f, "{message}")?; + } + if let Some(result) = &self.result { + result.fmt_rec(f, 1)?; + } + Ok(()) + } +} + +pub fn display_action_result(params: WithIoFormat, result: Option) { + let Some(result) = result else { + return; + }; if let Some(format) = params.format { return display_serializable(format, result); } - match result { - ActionResult::V0(ar) => { - println!( - "{}: {}", - ar.message, - serde_json::to_string(&ar.value).unwrap() - ); - } - } + println!("{result}") } -#[derive(Deserialize, Serialize, Parser, TS)] +#[derive(Deserialize, Serialize, TS)] #[serde(rename_all = "camelCase")] -#[command(rename_all = "kebab-case")] -pub struct ActionParams { - #[arg(id = "id")] - #[serde(rename = "id")] +pub struct RunActionParams { + pub package_id: PackageId, + pub action_id: ActionId, + #[ts(optional, type = "any")] + pub input: Option, +} + +#[derive(Parser)] +struct CliRunActionParams { pub package_id: PackageId, pub action_id: ActionId, #[command(flatten)] - #[ts(type = "{ [key: string]: any } | null")] - #[serde(default)] - pub input: StdinDeserializable>, + pub input: StdinDeserializable>, +} +impl From for RunActionParams { + fn from( + CliRunActionParams { + package_id, + action_id, + input, + }: CliRunActionParams, + ) -> Self { + Self { + package_id, + action_id, + input: input.0, + } + } +} +impl CommandFactory for RunActionParams { + fn command() -> clap::Command { + CliRunActionParams::command() + } + fn command_for_update() -> clap::Command { + CliRunActionParams::command_for_update() + } +} +impl FromArgMatches for RunActionParams { + fn from_arg_matches(matches: &clap::ArgMatches) -> Result { + CliRunActionParams::from_arg_matches(matches).map(Self::from) + } + fn from_arg_matches_mut(matches: &mut clap::ArgMatches) -> Result { + CliRunActionParams::from_arg_matches_mut(matches).map(Self::from) + } + fn update_from_arg_matches(&mut self, matches: &clap::ArgMatches) -> Result<(), clap::Error> { + *self = CliRunActionParams::from_arg_matches(matches).map(Self::from)?; + Ok(()) + } + fn update_from_arg_matches_mut( + &mut self, + matches: &mut clap::ArgMatches, + ) -> Result<(), clap::Error> { + *self = CliRunActionParams::from_arg_matches_mut(matches).map(Self::from)?; + Ok(()) + } } -// impl C // #[command(about = "Executes an action", display(display_action_result))] #[instrument(skip_all)] -pub async fn action( +pub async fn run_action( ctx: RpcContext, - ActionParams { + RunActionParams { package_id, action_id, - input: StdinDeserializable(input), - }: ActionParams, -) -> Result { + input, + }: RunActionParams, +) -> Result, Error> { ctx.services .get(&package_id) .await .as_ref() .or_not_found(lazy_format!("Manager for {}", package_id))? - .action( - Guid::new(), - action_id, - input.map(|c| to_value(&c)).transpose()?.unwrap_or_default(), - ) + .run_action(Guid::new(), action_id, input.unwrap_or_default()) .await } diff --git a/core/startos/src/auth.rs b/core/startos/src/auth.rs index d998e9897..a6b624b70 100644 --- a/core/startos/src/auth.rs +++ b/core/startos/src/auth.rs @@ -91,28 +91,40 @@ pub fn auth() -> ParentHandler { .with_metadata("login", Value::Bool(true)) .no_cli(), ) - .subcommand("login", from_fn_async(cli_login).no_display()) + .subcommand( + "login", + from_fn_async(cli_login) + .no_display() + .with_about("Log in to StartOS server"), + ) .subcommand( "logout", from_fn_async(logout) .with_metadata("get_session", Value::Bool(true)) .no_display() + .with_about("Log out of StartOS server") .with_call_remote::(), ) - .subcommand("session", session::()) + .subcommand( + "session", + session::().with_about("List or kill StartOS sessions"), + ) .subcommand( "reset-password", from_fn_async(reset_password_impl).no_cli(), ) .subcommand( "reset-password", - from_fn_async(cli_reset_password).no_display(), + from_fn_async(cli_reset_password) + .no_display() + .with_about("Reset StartOS password"), ) .subcommand( "get-pubkey", from_fn_async(get_pubkey) .with_metadata("authenticated", Value::Bool(false)) .no_display() + .with_about("Get public key derived from server private key") .with_call_remote::(), ) } @@ -275,8 +287,8 @@ pub struct Session { #[serde(rename_all = "camelCase")] #[ts(export)] pub struct SessionList { - #[ts(type = "string")] - current: InternedString, + #[ts(type = "string | null")] + current: Option, sessions: Sessions, } @@ -290,12 +302,14 @@ pub fn session() -> ParentHandler { .with_custom_display_fn(|handle, result| { Ok(display_sessions(handle.params, result)) }) + .with_about("Display all server sessions") .with_call_remote::(), ) .subcommand( "kill", from_fn_async(kill) .no_display() + .with_about("Terminate existing server session(s)") .with_call_remote::(), ) } @@ -323,7 +337,7 @@ fn display_sessions(params: WithIoFormat, arg: SessionList) { session.user_agent.as_deref().unwrap_or("N/A"), &format!("{}", session.metadata), ]; - if id == arg.current { + if Some(id) == arg.current { row.iter_mut() .map(|c| c.style(Attr::ForegroundColor(color::GREEN))) .collect::<()>() @@ -340,7 +354,7 @@ pub struct ListParams { #[arg(skip)] #[ts(skip)] #[serde(rename = "__auth_session")] // from Auth middleware - session: InternedString, + session: Option, } // #[command(display(display_sessions))] diff --git a/core/startos/src/backup/backup_bulk.rs b/core/startos/src/backup/backup_bulk.rs index b4419e88e..136595b67 100644 --- a/core/startos/src/backup/backup_bulk.rs +++ b/core/startos/src/backup/backup_bulk.rs @@ -141,7 +141,7 @@ impl Drop for BackupStatusGuard { .ser(&None) }) .await - .unwrap() + .log_err() }); } } @@ -332,10 +332,10 @@ async fn perform_backup( let timestamp = Utc::now(); - backup_guard.unencrypted_metadata.version = crate::version::Current::new().semver().into(); + 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.timestamp = timestamp.clone(); - backup_guard.metadata.version = crate::version::Current::new().semver().into(); + backup_guard.metadata.version = crate::version::Current::default().semver().into(); backup_guard.metadata.timestamp = Some(timestamp); backup_guard.metadata.package_backups = package_backups; diff --git a/core/startos/src/backup/mod.rs b/core/startos/src/backup/mod.rs index 8afafaa33..110a918b6 100644 --- a/core/startos/src/backup/mod.rs +++ b/core/startos/src/backup/mod.rs @@ -40,9 +40,13 @@ pub fn backup() -> ParentHandler { "create", from_fn_async(backup_bulk::backup_all) .no_display() + .with_about("Create backup for all packages") .with_call_remote::(), ) - .subcommand("target", target::target::()) + .subcommand( + "target", + target::target::().with_about("Commands related to a backup target"), + ) } pub fn package_backup() -> ParentHandler { @@ -50,6 +54,7 @@ pub fn package_backup() -> ParentHandler { "restore", from_fn_async(restore::restore_packages_rpc) .no_display() + .with_about("Restore package(s) from backup") .with_call_remote::(), ) } diff --git a/core/startos/src/backup/target/cifs.rs b/core/startos/src/backup/target/cifs.rs index e83f4e981..71cbe267e 100644 --- a/core/startos/src/backup/target/cifs.rs +++ b/core/startos/src/backup/target/cifs.rs @@ -52,18 +52,21 @@ pub fn cifs() -> ParentHandler { "add", from_fn_async(add) .no_display() + .with_about("Add a new backup target") .with_call_remote::(), ) .subcommand( "update", from_fn_async(update) .no_display() + .with_about("Update an existing backup target") .with_call_remote::(), ) .subcommand( "remove", from_fn_async(remove) .no_display() + .with_about("Remove an existing backup target") .with_call_remote::(), ) } diff --git a/core/startos/src/backup/target/mod.rs b/core/startos/src/backup/target/mod.rs index 032f70848..eb3fc29bc 100644 --- a/core/startos/src/backup/target/mod.rs +++ b/core/startos/src/backup/target/mod.rs @@ -9,7 +9,7 @@ use digest::generic_array::GenericArray; use digest::OutputSizeUser; use exver::Version; use imbl_value::InternedString; -use models::PackageId; +use models::{FromStrParser, PackageId}; use rpc_toolkit::{from_fn_async, Context, HandlerExt, ParentHandler}; use serde::{Deserialize, Serialize}; use sha2::Sha256; @@ -27,7 +27,6 @@ use crate::disk::mount::filesystem::{FileSystem, MountType, ReadWrite}; use crate::disk::mount::guard::{GenericMountGuard, TmpMountGuard}; use crate::disk::util::PartitionInfo; use crate::prelude::*; -use crate::util::clap::FromStrParser; use crate::util::serde::{ deserialize_from_str, display_serializable, serialize_display, HandlerExtSerde, WithIoFormat, }; @@ -142,11 +141,15 @@ impl FileSystem for BackupTargetFS { // #[command(subcommands(cifs::cifs, list, info, mount, umount))] pub fn target() -> ParentHandler { ParentHandler::new() - .subcommand("cifs", cifs::cifs::()) + .subcommand( + "cifs", + cifs::cifs::().with_about("Add, remove, or update a backup target"), + ) .subcommand( "list", from_fn_async(list) .with_display_serializable() + .with_about("List existing backup targets") .with_call_remote::(), ) .subcommand( @@ -156,16 +159,20 @@ pub fn target() -> ParentHandler { .with_custom_display_fn::(|params, info| { Ok(display_backup_info(params.params, info)) }) + .with_about("Display package backup information") .with_call_remote::(), ) .subcommand( "mount", - from_fn_async(mount).with_call_remote::(), + from_fn_async(mount) + .with_about("Mount backup target") + .with_call_remote::(), ) .subcommand( "umount", from_fn_async(umount) .no_display() + .with_about("Unmount backup target") .with_call_remote::(), ) } diff --git a/core/startos/src/bins/container_cli.rs b/core/startos/src/bins/container_cli.rs index db7cbd36a..b0da1cb00 100644 --- a/core/startos/src/bins/container_cli.rs +++ b/core/startos/src/bins/container_cli.rs @@ -8,7 +8,7 @@ use crate::util::logger::EmbassyLogger; use crate::version::{Current, VersionT}; lazy_static::lazy_static! { - static ref VERSION_STRING: String = Current::new().semver().to_string(); + static ref VERSION_STRING: String = Current::default().semver().to_string(); } pub fn main(args: impl IntoIterator) { diff --git a/core/startos/src/bins/mod.rs b/core/startos/src/bins/mod.rs index 4a4670a5b..6ffecfce9 100644 --- a/core/startos/src/bins/mod.rs +++ b/core/startos/src/bins/mod.rs @@ -28,6 +28,16 @@ fn select_executable(name: &str) -> Option)> { "embassy-sdk" => Some(|_| deprecated::renamed("embassy-sdk", "start-sdk")), "embassyd" => Some(|_| deprecated::renamed("embassyd", "startd")), "embassy-init" => Some(|_| deprecated::removed("embassy-init")), + "contents" => Some(|_| { + #[cfg(feature = "cli")] + println!("start-cli"); + #[cfg(feature = "container-runtime")] + println!("start-cli (container)"); + #[cfg(feature = "daemon")] + println!("startd"); + #[cfg(feature = "registry")] + println!("registry"); + }), _ => None, } } diff --git a/core/startos/src/bins/start_cli.rs b/core/startos/src/bins/start_cli.rs index 17cc095a3..2e92e0cc0 100644 --- a/core/startos/src/bins/start_cli.rs +++ b/core/startos/src/bins/start_cli.rs @@ -9,7 +9,7 @@ use crate::util::logger::EmbassyLogger; use crate::version::{Current, VersionT}; lazy_static::lazy_static! { - static ref VERSION_STRING: String = Current::new().semver().to_string(); + static ref VERSION_STRING: String = Current::default().semver().to_string(); } pub fn main(args: impl IntoIterator) { diff --git a/core/startos/src/config/action.rs b/core/startos/src/config/action.rs deleted file mode 100644 index ef26571a7..000000000 --- a/core/startos/src/config/action.rs +++ /dev/null @@ -1,22 +0,0 @@ -use std::collections::{BTreeMap, BTreeSet}; - -use models::PackageId; -use serde::{Deserialize, Serialize}; - -use super::{Config, ConfigSpec}; -#[allow(unused_imports)] -use crate::prelude::*; -use crate::status::health_check::HealthCheckId; - -#[derive(Debug, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct ConfigRes { - pub config: Option, - pub spec: ConfigSpec, -} - -#[derive(Debug, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct SetResult { - pub depends_on: BTreeMap>, -} diff --git a/core/startos/src/config/mod.rs b/core/startos/src/config/mod.rs deleted file mode 100644 index 22edd98f7..000000000 --- a/core/startos/src/config/mod.rs +++ /dev/null @@ -1,281 +0,0 @@ -use std::collections::BTreeSet; -use std::sync::Arc; -use std::time::Duration; - -use clap::Parser; -use color_eyre::eyre::eyre; -use indexmap::{IndexMap, IndexSet}; -use itertools::Itertools; -use models::{ErrorKind, OptionExt, PackageId}; -use patch_db::value::InternedString; -use patch_db::Value; -use regex::Regex; -use rpc_toolkit::{from_fn_async, Context, Empty, HandlerExt, ParentHandler}; -use serde::{Deserialize, Serialize}; -use tracing::instrument; -use ts_rs::TS; - -use crate::context::{CliContext, RpcContext}; -use crate::prelude::*; -use crate::rpc_continuations::Guid; -use crate::util::serde::{HandlerExtSerde, StdinDeserializable}; - -#[derive(Clone, Debug, Default, Serialize, Deserialize)] -pub struct ConfigSpec(pub IndexMap); - -pub mod action; -pub mod util; - -use util::NumRange; - -use self::action::ConfigRes; - -pub type Config = patch_db::value::InOMap; -pub trait TypeOf { - fn type_of(&self) -> &'static str; -} -impl TypeOf for Value { - fn type_of(&self) -> &'static str { - match self { - Value::Array(_) => "list", - Value::Bool(_) => "boolean", - Value::Null => "null", - Value::Number(_) => "number", - Value::Object(_) => "object", - Value::String(_) => "string", - } - } -} - -#[derive(Debug, thiserror::Error)] -pub enum ConfigurationError { - #[error("Timeout Error")] - TimeoutError(#[from] TimeoutError), - #[error("No Match: {0}")] - NoMatch(#[from] NoMatchWithPath), - #[error("System Error: {0}")] - SystemError(Error), -} -impl From for Error { - fn from(err: ConfigurationError) -> Self { - let kind = match &err { - ConfigurationError::SystemError(e) => e.kind, - _ => crate::ErrorKind::ConfigGen, - }; - crate::Error::new(err, kind) - } -} - -#[derive(Clone, Copy, Debug, thiserror::Error)] -#[error("Timeout Error")] -pub struct TimeoutError; - -#[derive(Clone, Debug, thiserror::Error)] -pub struct NoMatchWithPath { - pub path: Vec, - pub error: MatchError, -} -impl NoMatchWithPath { - pub fn new(error: MatchError) -> Self { - NoMatchWithPath { - path: Vec::new(), - error, - } - } - pub fn prepend(mut self, seg: InternedString) -> Self { - self.path.push(seg); - self - } -} -impl std::fmt::Display for NoMatchWithPath { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}: {}", self.path.iter().rev().join("."), self.error) - } -} -impl From for Error { - fn from(e: NoMatchWithPath) -> Self { - ConfigurationError::from(e).into() - } -} - -#[derive(Clone, Debug, thiserror::Error)] -pub enum MatchError { - #[error("String {0:?} Does Not Match Pattern {1}")] - Pattern(Arc, Regex), - #[error("String {0:?} Is Not In Enum {1:?}")] - Enum(Arc, IndexSet), - #[error("Field Is Not Nullable")] - NotNullable, - #[error("Length Mismatch: expected {0}, actual: {1}")] - LengthMismatch(NumRange, usize), - #[error("Invalid Type: expected {0}, actual: {1}")] - InvalidType(&'static str, &'static str), - #[error("Number Out Of Range: expected {0}, actual: {1}")] - OutOfRange(NumRange, f64), - #[error("Number Is Not Integral: {0}")] - NonIntegral(f64), - #[error("Variant {0:?} Is Not In Union {1:?}")] - Union(Arc, IndexSet), - #[error("Variant Is Missing Tag {0:?}")] - MissingTag(InternedString), - #[error("Property {0:?} Of Variant {1:?} Conflicts With Union Tag")] - PropertyMatchesUnionTag(InternedString, String), - #[error("Name of Property {0:?} Conflicts With Map Tag Name")] - PropertyNameMatchesMapTag(String), - #[error("Object Key Is Invalid: {0}")] - InvalidKey(String), - #[error("Value In List Is Not Unique")] - ListUniquenessViolation, -} - -#[derive(Deserialize, Serialize, Parser, TS)] -#[serde(rename_all = "camelCase")] -#[command(rename_all = "kebab-case")] -pub struct ConfigParams { - pub id: PackageId, -} - -// #[command(subcommands(get, set))] -pub fn config() -> ParentHandler { - ParentHandler::new() - .subcommand( - "get", - from_fn_async(get) - .with_inherited(|ConfigParams { id }, _| id) - .with_display_serializable() - .with_call_remote::(), - ) - .subcommand( - "set", - set::().with_inherited(|ConfigParams { id }, _| id), - ) -} - -#[instrument(skip_all)] -pub async fn get(ctx: RpcContext, _: Empty, id: PackageId) -> Result { - ctx.services - .get(&id) - .await - .as_ref() - .or_not_found(lazy_format!("Manager for {id}"))? - .get_config(Guid::new()) - .await -} - -#[derive(Deserialize, Serialize, Parser, TS)] -#[serde(rename_all = "camelCase")] -pub struct SetParams { - #[arg(long = "timeout")] - pub timeout: Option, - #[command(flatten)] - #[ts(type = "{ [key: string]: any } | null")] - pub config: StdinDeserializable>, -} - -// #[command( -// subcommands(self(set_impl(async, context(RpcContext))), set_dry), -// display(display_none), -// metadata(sync_db = true) -// )] -#[instrument(skip_all)] -pub fn set() -> ParentHandler { - ParentHandler::new() - .root_handler( - from_fn_async(set_impl) - .with_metadata("sync_db", Value::Bool(true)) - .with_inherited(|set_params, id| (id, set_params)) - .no_display() - .with_call_remote::(), - ) - .subcommand( - "dry", - from_fn_async(set_dry) - .with_inherited(|set_params, id| (id, set_params)) - .no_display() - .with_call_remote::(), - ) -} - -pub async fn set_dry( - ctx: RpcContext, - _: Empty, - ( - id, - SetParams { - timeout, - config: StdinDeserializable(config), - }, - ): (PackageId, SetParams), -) -> Result, Error> { - let mut breakages = BTreeSet::new(); - - let procedure_id = Guid::new(); - - let db = ctx.db.peek().await; - for dep in db - .as_public() - .as_package_data() - .as_entries()? - .into_iter() - .filter_map( - |(k, v)| match v.as_current_dependencies().contains_key(&id) { - Ok(true) => Some(Ok(k)), - Ok(false) => None, - Err(e) => Some(Err(e)), - }, - ) - { - let dep_id = dep?; - - let Some(dependent) = &*ctx.services.get(&dep_id).await else { - continue; - }; - - if dependent - .dependency_config(procedure_id.clone(), id.clone(), config.clone()) - .await? - .is_some() - { - breakages.insert(dep_id); - } - } - - Ok(breakages) -} - -#[derive(Default)] -pub struct ConfigureContext { - pub timeout: Option, - pub config: Option, -} - -#[instrument(skip_all)] -pub async fn set_impl( - ctx: RpcContext, - _: Empty, - ( - id, - SetParams { - timeout, - config: StdinDeserializable(config), - }, - ): (PackageId, SetParams), -) -> Result<(), Error> { - let configure_context = ConfigureContext { - timeout: timeout.map(|t| *t), - config, - }; - ctx.services - .get(&id) - .await - .as_ref() - .ok_or_else(|| { - Error::new( - eyre!("There is no manager running for {id}"), - ErrorKind::Unknown, - ) - })? - .configure(Guid::new(), configure_context) - .await?; - Ok(()) -} diff --git a/core/startos/src/config/util.rs b/core/startos/src/config/util.rs deleted file mode 100644 index 359c24476..000000000 --- a/core/startos/src/config/util.rs +++ /dev/null @@ -1,406 +0,0 @@ -use std::borrow::Cow; -use std::ops::{Bound, RangeBounds, RangeInclusive}; - -use patch_db::Value; -use rand::distributions::Distribution; -use rand::Rng; - -use super::Config; - -pub const STATIC_NULL: Value = Value::Null; - -#[derive(Clone, Debug)] -pub struct CharSet(pub Vec<(RangeInclusive, usize)>, usize); -impl CharSet { - pub fn contains(&self, c: &char) -> bool { - self.0.iter().any(|r| r.0.contains(c)) - } - pub fn gen(&self, rng: &mut R) -> char { - let mut idx = rng.gen_range(0..self.1); - for r in &self.0 { - if idx < r.1 { - return std::convert::TryFrom::try_from( - rand::distributions::Uniform::new_inclusive( - u32::from(*r.0.start()), - u32::from(*r.0.end()), - ) - .sample(rng), - ) - .unwrap(); - } else { - idx -= r.1; - } - } - unreachable!() - } -} -impl Default for CharSet { - fn default() -> Self { - CharSet(vec![('!'..='~', 94)], 94) - } -} -impl<'de> serde::de::Deserialize<'de> for CharSet { - fn deserialize(deserializer: D) -> Result - where - D: serde::de::Deserializer<'de>, - { - let s = String::deserialize(deserializer)?; - let mut res = Vec::new(); - let mut len = 0; - let mut a: Option = None; - let mut b: Option = None; - let mut in_range = false; - for c in s.chars() { - match c { - ',' => match (a, b, in_range) { - (Some(start), Some(end), _) => { - if !end.is_ascii() { - return Err(serde::de::Error::custom("Invalid Character")); - } - if start >= end { - return Err(serde::de::Error::custom("Invalid Bounds")); - } - let l = u32::from(end) - u32::from(start) + 1; - res.push((start..=end, l as usize)); - len += l as usize; - a = None; - b = None; - in_range = false; - } - (Some(start), None, false) => { - len += 1; - res.push((start..=start, 1)); - a = None; - } - (Some(_), None, true) => { - b = Some(','); - } - (None, None, false) => { - a = Some(','); - } - _ => { - return Err(serde::de::Error::custom("Syntax Error")); - } - }, - '-' => { - if a.is_none() { - a = Some('-'); - } else if !in_range { - in_range = true; - } else if b.is_none() { - b = Some('-') - } else { - return Err(serde::de::Error::custom("Syntax Error")); - } - } - _ => { - if a.is_none() { - a = Some(c); - } else if in_range && b.is_none() { - b = Some(c); - } else { - return Err(serde::de::Error::custom("Syntax Error")); - } - } - } - } - match (a, b) { - (Some(start), Some(end)) => { - if !end.is_ascii() { - return Err(serde::de::Error::custom("Invalid Character")); - } - if start >= end { - return Err(serde::de::Error::custom("Invalid Bounds")); - } - let l = u32::from(end) - u32::from(start) + 1; - res.push((start..=end, l as usize)); - len += l as usize; - } - (Some(c), None) => { - len += 1; - res.push((c..=c, 1)); - } - _ => (), - } - - Ok(CharSet(res, len)) - } -} -impl serde::ser::Serialize for CharSet { - fn serialize(&self, serializer: S) -> Result - where - S: serde::ser::Serializer, - { - <&str>::serialize( - &self - .0 - .iter() - .map(|r| match r.1 { - 1 => format!("{}", r.0.start()), - _ => format!("{}-{}", r.0.start(), r.0.end()), - }) - .collect::>() - .join(",") - .as_str(), - serializer, - ) - } -} - -pub trait MergeWith { - fn merge_with(&mut self, other: &serde_json::Value); -} - -impl MergeWith for serde_json::Value { - fn merge_with(&mut self, other: &serde_json::Value) { - use serde_json::Value::Object; - if let (Object(orig), Object(ref other)) = (self, other) { - for (key, val) in other.into_iter() { - match (orig.get_mut(key), val) { - (Some(new_orig @ Object(_)), other @ Object(_)) => { - new_orig.merge_with(other); - } - (None, _) => { - orig.insert(key.clone(), val.clone()); - } - _ => (), - } - } - } - } -} - -#[test] -fn merge_with_tests() { - use serde_json::json; - - let mut a = json!( - {"a": 1, "c": {"d": "123"}, "i": [1,2,3], "j": {}, "k":[1,2,3], "l": "test"} - ); - a.merge_with( - &json!({"a":"a", "b": "b", "c":{"d":"d", "e":"e"}, "f":{"g":"g"}, "h": [1,2,3], "i":"i", "j":[1,2,3], "k":{}}), - ); - assert_eq!( - a, - json!({"a": 1, "c": {"d": "123", "e":"e"}, "b":"b", "f": {"g":"g"}, "h":[1,2,3], "i":[1,2,3], "j": {}, "k":[1,2,3], "l": "test"}) - ) -} -pub mod serde_regex { - use regex::Regex; - use serde::*; - - pub fn serialize(regex: &Regex, serializer: S) -> Result - where - S: Serializer, - { - <&str>::serialize(®ex.as_str(), serializer) - } - - pub fn deserialize<'de, D>(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let s = String::deserialize(deserializer)?; - Regex::new(&s).map_err(|e| de::Error::custom(e)) - } -} - -#[derive(Clone, Debug)] -pub struct NumRange( - pub (Bound, Bound), -); -impl std::ops::Deref for NumRange -where - T: std::str::FromStr + std::fmt::Display + std::cmp::PartialOrd, -{ - type Target = (Bound, Bound); - - fn deref(&self) -> &Self::Target { - &self.0 - } -} -impl<'de, T> serde::de::Deserialize<'de> for NumRange -where - T: std::str::FromStr + std::fmt::Display + std::cmp::PartialOrd, - ::Err: std::fmt::Display, -{ - fn deserialize(deserializer: D) -> Result - where - D: serde::de::Deserializer<'de>, - { - let s = String::deserialize(deserializer)?; - let mut split = s.split(","); - let start = split - .next() - .map(|s| match s.get(..1) { - Some("(") => match s.get(1..2) { - Some("*") => Ok(Bound::Unbounded), - _ => s[1..] - .trim() - .parse() - .map(Bound::Excluded) - .map_err(|e| serde::de::Error::custom(e)), - }, - Some("[") => s[1..] - .trim() - .parse() - .map(Bound::Included) - .map_err(|e| serde::de::Error::custom(e)), - _ => Err(serde::de::Error::custom(format!( - "Could not parse left bound: {}", - s - ))), - }) - .transpose()? - .unwrap(); - let end = split - .next() - .map(|s| match s.get(s.len() - 1..) { - Some(")") => match s.get(s.len() - 2..s.len() - 1) { - Some("*") => Ok(Bound::Unbounded), - _ => s[..s.len() - 1] - .trim() - .parse() - .map(Bound::Excluded) - .map_err(|e| serde::de::Error::custom(e)), - }, - Some("]") => s[..s.len() - 1] - .trim() - .parse() - .map(Bound::Included) - .map_err(|e| serde::de::Error::custom(e)), - _ => Err(serde::de::Error::custom(format!( - "Could not parse right bound: {}", - s - ))), - }) - .transpose()? - .unwrap_or(Bound::Unbounded); - - Ok(NumRange((start, end))) - } -} -impl std::fmt::Display for NumRange -where - T: std::str::FromStr + std::fmt::Display + std::cmp::PartialOrd, -{ - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self.start_bound() { - Bound::Excluded(n) => write!(f, "({},", n)?, - Bound::Included(n) => write!(f, "[{},", n)?, - Bound::Unbounded => write!(f, "(*,")?, - }; - match self.end_bound() { - Bound::Excluded(n) => write!(f, "{})", n), - Bound::Included(n) => write!(f, "{}]", n), - Bound::Unbounded => write!(f, "*)"), - } - } -} -impl serde::ser::Serialize for NumRange -where - T: std::str::FromStr + std::fmt::Display + std::cmp::PartialOrd, -{ - fn serialize(&self, serializer: S) -> Result - where - S: serde::ser::Serializer, - { - <&str>::serialize(&format!("{}", self).as_str(), serializer) - } -} - -#[derive(Clone, Debug)] -pub enum UniqueBy { - Any(Vec), - All(Vec), - Exactly(String), - NotUnique, -} -impl UniqueBy { - pub fn eq(&self, lhs: &Config, rhs: &Config) -> bool { - match self { - UniqueBy::Any(any) => any.iter().any(|u| u.eq(lhs, rhs)), - UniqueBy::All(all) => all.iter().all(|u| u.eq(lhs, rhs)), - UniqueBy::Exactly(key) => lhs.get(&**key) == rhs.get(&**key), - UniqueBy::NotUnique => false, - } - } -} -impl Default for UniqueBy { - fn default() -> Self { - UniqueBy::NotUnique - } -} -impl<'de> serde::de::Deserialize<'de> for UniqueBy { - fn deserialize>(deserializer: D) -> Result { - struct Visitor; - impl<'de> serde::de::Visitor<'de> for Visitor { - type Value = UniqueBy; - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(formatter, "a key, an \"any\" object, or an \"all\" object") - } - fn visit_str(self, v: &str) -> Result { - Ok(UniqueBy::Exactly(v.to_owned())) - } - fn visit_string(self, v: String) -> Result { - Ok(UniqueBy::Exactly(v)) - } - fn visit_map>( - self, - mut map: A, - ) -> Result { - let mut variant = None; - while let Some(key) = map.next_key::>()? { - match key.as_ref() { - "any" => { - return Ok(UniqueBy::Any(map.next_value()?)); - } - "all" => { - return Ok(UniqueBy::All(map.next_value()?)); - } - _ => { - variant = Some(key); - } - } - } - Err(serde::de::Error::unknown_variant( - variant.unwrap_or_default().as_ref(), - &["any", "all"], - )) - } - fn visit_unit(self) -> Result { - Ok(UniqueBy::NotUnique) - } - fn visit_none(self) -> Result { - Ok(UniqueBy::NotUnique) - } - } - deserializer.deserialize_any(Visitor) - } -} - -impl serde::ser::Serialize for UniqueBy { - fn serialize(&self, serializer: S) -> Result - where - S: serde::ser::Serializer, - { - use serde::ser::SerializeMap; - - match self { - UniqueBy::Any(any) => { - let mut map = serializer.serialize_map(Some(1))?; - map.serialize_key("any")?; - map.serialize_value(any)?; - map.end() - } - UniqueBy::All(all) => { - let mut map = serializer.serialize_map(Some(1))?; - map.serialize_key("all")?; - map.serialize_value(all)?; - map.end() - } - UniqueBy::Exactly(key) => serializer.serialize_str(key), - UniqueBy::NotUnique => serializer.serialize_unit(), - } - } -} diff --git a/core/startos/src/context/rpc.rs b/core/startos/src/context/rpc.rs index 5330c58bc..73d103adc 100644 --- a/core/startos/src/context/rpc.rs +++ b/core/startos/src/context/rpc.rs @@ -1,4 +1,4 @@ -use std::collections::BTreeMap; +use std::collections::{BTreeMap, BTreeSet}; use std::future::Future; use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4}; use std::ops::Deref; @@ -9,8 +9,11 @@ use std::time::Duration; use chrono::{TimeDelta, Utc}; use helpers::NonDetachingJoinHandle; +use imbl::OrdMap; use imbl_value::InternedString; +use itertools::Itertools; use josekit::jwk::Jwk; +use models::{ActionId, PackageId}; use reqwest::{Client, Proxy}; use rpc_toolkit::yajrc::RpcError; use rpc_toolkit::{CallRemote, Context, Empty}; @@ -23,7 +26,6 @@ use crate::account::AccountInfo; use crate::auth::Sessions; use crate::context::config::ServerConfig; use crate::db::model::Database; -use crate::dependencies::compute_dependency_config_errs; use crate::disk::OsPartitionInfo; use crate::init::check_time_is_synchronized; use crate::lxc::{ContainerId, LxcContainer, LxcManager}; @@ -33,11 +35,11 @@ use crate::net::wifi::WpaCli; use crate::prelude::*; use crate::progress::{FullProgressTracker, PhaseProgressTrackerHandle}; use crate::rpc_continuations::{Guid, OpenAuthedContinuations, RpcContinuations}; +use crate::service::action::update_requested_actions; use crate::service::effects::callbacks::ServiceCallbacks; use crate::service::ServiceMap; use crate::shutdown::Shutdown; -use crate::system::get_mem_info; -use crate::util::lshw::{lshw, LshwDevice}; +use crate::util::lshw::LshwDevice; use crate::util::sync::SyncMutex; pub struct RpcContextSeed { @@ -58,16 +60,15 @@ pub struct RpcContextSeed { pub shutdown: broadcast::Sender>, pub tor_socks: SocketAddr, pub lxc_manager: Arc, - pub open_authed_continuations: OpenAuthedContinuations, + pub open_authed_continuations: OpenAuthedContinuations>, pub rpc_continuations: RpcContinuations, pub callbacks: ServiceCallbacks, pub wifi_manager: Option>>, pub current_secret: Arc, pub client: Client, - pub hardware: Hardware, pub start_time: Instant, pub crons: SyncMutex>>, - #[cfg(feature = "dev")] + // #[cfg(feature = "dev")] pub dev: Dev, } @@ -83,15 +84,14 @@ pub struct Hardware { pub struct InitRpcContextPhases { load_db: PhaseProgressTrackerHandle, init_net_ctrl: PhaseProgressTrackerHandle, - read_device_info: PhaseProgressTrackerHandle, cleanup_init: CleanupInitPhases, + // TODO: migrations } impl InitRpcContextPhases { pub fn new(handle: &FullProgressTracker) -> Self { Self { load_db: handle.add_phase("Loading database".into(), Some(5)), init_net_ctrl: handle.add_phase("Initializing network".into(), Some(1)), - read_device_info: handle.add_phase("Reading device information".into(), Some(1)), cleanup_init: CleanupInitPhases::new(handle), } } @@ -100,14 +100,14 @@ impl InitRpcContextPhases { pub struct CleanupInitPhases { cleanup_sessions: PhaseProgressTrackerHandle, init_services: PhaseProgressTrackerHandle, - check_dependencies: PhaseProgressTrackerHandle, + check_requested_actions: PhaseProgressTrackerHandle, } impl CleanupInitPhases { pub fn new(handle: &FullProgressTracker) -> Self { Self { cleanup_sessions: handle.add_phase("Cleaning up sessions".into(), Some(1)), init_services: handle.add_phase("Initializing services".into(), Some(10)), - check_dependencies: handle.add_phase("Checking dependencies".into(), Some(1)), + check_requested_actions: handle.add_phase("Checking action requests".into(), Some(1)), } } } @@ -123,7 +123,6 @@ impl RpcContext { InitRpcContextPhases { mut load_db, mut init_net_ctrl, - mut read_device_info, cleanup_init, }: InitRpcContextPhases, ) -> Result { @@ -175,11 +174,6 @@ impl RpcContext { let metrics_cache = RwLock::>::new(None); let tor_proxy_url = format!("socks5h://{tor_proxy}"); - read_device_info.start(); - let devices = lshw().await?; - let ram = get_mem_info().await?.total.0 as u64 * 1024 * 1024; - read_device_info.complete(); - let crons = SyncMutex::new(BTreeMap::new()); if !db @@ -271,10 +265,9 @@ impl RpcContext { })) .build() .with_kind(crate::ErrorKind::ParseUrl)?, - hardware: Hardware { devices, ram }, start_time: Instant::now(), crons, - #[cfg(feature = "dev")] + // #[cfg(feature = "dev")] dev: Dev { lxc: Mutex::new(BTreeMap::new()), }, @@ -283,6 +276,7 @@ impl RpcContext { let res = Self(seed.clone()); res.cleanup_and_initialize(cleanup_init).await?; tracing::info!("Cleaned up transient states"); + crate::version::post_init(&res).await?; Ok(res) } @@ -309,7 +303,7 @@ impl RpcContext { CleanupInitPhases { mut cleanup_sessions, init_services, - mut check_dependencies, + mut check_requested_actions, }: CleanupInitPhases, ) -> Result<(), Error> { cleanup_sessions.start(); @@ -366,35 +360,68 @@ impl RpcContext { cleanup_sessions.complete(); self.services.init(&self, init_services).await?; - tracing::info!("Initialized Package Managers"); + tracing::info!("Initialized Services"); - check_dependencies.start(); - let mut updated_current_dependents = BTreeMap::new(); + // TODO + check_requested_actions.start(); let peek = self.db.peek().await; - for (package_id, package) in peek.as_public().as_package_data().as_entries()?.into_iter() { - let package = package.clone(); - let mut current_dependencies = package.as_current_dependencies().de()?; - compute_dependency_config_errs(self, &package_id, &mut current_dependencies) - .await - .log_err(); - updated_current_dependents.insert(package_id.clone(), current_dependencies); + let mut action_input: OrdMap> = OrdMap::new(); + let requested_actions: BTreeSet<_> = peek + .as_public() + .as_package_data() + .as_entries()? + .into_iter() + .map(|(_, pde)| { + Ok(pde + .as_requested_actions() + .as_entries()? + .into_iter() + .map(|(_, r)| { + Ok::<_, Error>(( + r.as_request().as_package_id().de()?, + r.as_request().as_action_id().de()?, + )) + })) + }) + .flatten_ok() + .map(|a| a.and_then(|a| a)) + .try_collect()?; + let procedure_id = Guid::new(); + for (package_id, action_id) in requested_actions { + if let Some(service) = self.services.get(&package_id).await.as_ref() { + if let Some(input) = service + .get_action_input(procedure_id.clone(), action_id.clone()) + .await? + .and_then(|i| i.value) + { + action_input + .entry(package_id) + .or_default() + .insert(action_id, input); + } + } } self.db - .mutate(|v| { - for (package_id, deps) in updated_current_dependents { - if let Some(model) = v - .as_public_mut() - .as_package_data_mut() - .as_idx_mut(&package_id) - .map(|i| i.as_current_dependencies_mut()) - { - model.ser(&deps)?; + .mutate(|db| { + for (package_id, action_input) in &action_input { + for (action_id, input) in action_input { + for (_, pde) in db.as_public_mut().as_package_data_mut().as_entries_mut()? { + pde.as_requested_actions_mut().mutate(|requested_actions| { + Ok(update_requested_actions( + requested_actions, + package_id, + action_id, + input, + false, + )) + })?; + } } } Ok(()) }) .await?; - check_dependencies.complete(); + check_requested_actions.complete(); Ok(()) } @@ -431,8 +458,8 @@ impl AsRef for RpcContext { &self.rpc_continuations } } -impl AsRef> for RpcContext { - fn as_ref(&self) -> &OpenAuthedContinuations { +impl AsRef>> for RpcContext { + fn as_ref(&self) -> &OpenAuthedContinuations> { &self.open_authed_continuations } } diff --git a/core/startos/src/context/setup.rs b/core/startos/src/context/setup.rs index 999154977..96ec07700 100644 --- a/core/startos/src/context/setup.rs +++ b/core/startos/src/context/setup.rs @@ -21,6 +21,7 @@ use crate::account::AccountInfo; use crate::context::config::ServerConfig; use crate::context::RpcContext; use crate::disk::OsPartitionInfo; +use crate::hostname::Hostname; use crate::init::init_postgres; use crate::prelude::*; use crate::progress::FullProgressTracker; @@ -42,6 +43,8 @@ lazy_static::lazy_static! { pub struct SetupResult { pub tor_address: String, #[ts(type = "string")] + pub hostname: Hostname, + #[ts(type = "string")] pub lan_address: InternedString, pub root_ca: String, } @@ -50,6 +53,7 @@ impl TryFrom<&AccountInfo> for SetupResult { fn try_from(value: &AccountInfo) -> Result { Ok(Self { tor_address: format!("https://{}", value.tor_key.public().get_onion_address()), + hostname: value.hostname.clone(), lan_address: value.hostname.lan_address(), root_ca: String::from_utf8(value.root_ca_cert.to_pem()?)?, }) diff --git a/core/startos/src/db/mod.rs b/core/startos/src/db/mod.rs index ef35bd30d..c7e38e81c 100644 --- a/core/startos/src/db/mod.rs +++ b/core/startos/src/db/mod.rs @@ -31,7 +31,12 @@ lazy_static::lazy_static! { pub fn db() -> ParentHandler { ParentHandler::new() - .subcommand("dump", from_fn_async(cli_dump).with_display_serializable()) + .subcommand( + "dump", + from_fn_async(cli_dump) + .with_display_serializable() + .with_about("Filter/query db to display tables and records"), + ) .subcommand("dump", from_fn_async(dump).no_cli()) .subcommand( "subscribe", @@ -39,8 +44,16 @@ pub fn db() -> ParentHandler { .with_metadata("get_session", Value::Bool(true)) .no_cli(), ) - .subcommand("put", put::()) - .subcommand("apply", from_fn_async(cli_apply).no_display()) + .subcommand( + "put", + put::().with_about("Command for adding UI record to db"), + ) + .subcommand( + "apply", + from_fn_async(cli_apply) + .no_display() + .with_about("Update a db record"), + ) .subcommand("apply", from_fn_async(apply).no_cli()) } @@ -115,7 +128,7 @@ pub struct SubscribeParams { pointer: Option, #[ts(skip)] #[serde(rename = "__auth_session")] - session: InternedString, + session: Option, } #[derive(Deserialize, Serialize, TS)] @@ -215,6 +228,8 @@ pub async fn subscribe( #[serde(rename_all = "camelCase")] #[command(rename_all = "kebab-case")] pub struct CliApplyParams { + #[arg(long)] + allow_model_mismatch: bool, expr: String, path: Option, } @@ -225,7 +240,12 @@ async fn cli_apply( context, parent_method, method, - params: CliApplyParams { expr, path }, + params: + CliApplyParams { + allow_model_mismatch, + expr, + path, + }, .. }: HandlerArgs, ) -> Result<(), RpcError> { @@ -240,7 +260,14 @@ async fn cli_apply( &expr, )?; - Ok::<_, Error>(( + let value = if allow_model_mismatch { + serde_json::from_value::(res.clone().into()).with_ctx(|_| { + ( + crate::ErrorKind::Deserialization, + "result does not match database model", + ) + })? + } else { to_value( &serde_json::from_value::(res.clone().into()).with_ctx( |_| { @@ -250,9 +277,9 @@ async fn cli_apply( ) }, )?, - )?, - (), - )) + )? + }; + Ok::<_, Error>((value, ())) }) .await?; } else { @@ -299,6 +326,7 @@ pub fn put() -> ParentHandler { "ui", from_fn_async(ui) .with_display_serializable() + .with_about("Add path and value to db") .with_call_remote::(), ) } diff --git a/core/startos/src/db/model/package.rs b/core/startos/src/db/model/package.rs index 957e42c54..df5773cc3 100644 --- a/core/startos/src/db/model/package.rs +++ b/core/startos/src/db/model/package.rs @@ -4,7 +4,8 @@ use chrono::{DateTime, Utc}; use exver::VersionRange; use imbl_value::InternedString; use models::{ - ActionId, DataUrl, HealthCheckId, HostId, PackageId, ServiceInterfaceId, VersionString, + ActionId, DataUrl, HealthCheckId, HostId, PackageId, ReplayId, ServiceInterfaceId, + VersionString, }; use patch_db::json_ptr::JsonPointer; use patch_db::HasModel; @@ -17,8 +18,8 @@ use crate::net::service_interface::ServiceInterface; use crate::prelude::*; use crate::progress::FullProgress; use crate::s9pk::manifest::Manifest; -use crate::status::Status; -use crate::util::serde::Pem; +use crate::status::MainStatus; +use crate::util::serde::{is_partial_of, Pem}; #[derive(Debug, Default, Deserialize, Serialize, TS)] #[ts(export)] @@ -310,9 +311,9 @@ pub struct InstallingInfo { } #[derive(Debug, Clone, serde::Serialize, serde::Deserialize, TS)] #[ts(export)] -#[serde(rename_all = "camelCase")] +#[serde(rename_all = "kebab-case")] pub enum AllowedStatuses { - OnlyRunning, // onlyRunning + OnlyRunning, OnlyStopped, Any, } @@ -324,13 +325,28 @@ pub struct ActionMetadata { pub name: String, pub description: String, pub warning: Option, - #[ts(type = "any")] - pub input: Value, - pub disabled: bool, + #[serde(default)] + pub visibility: ActionVisibility, pub allowed_statuses: AllowedStatuses, + pub has_input: bool, pub group: Option, } +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, TS)] +#[ts(export)] +#[serde(rename_all = "kebab-case")] +#[serde(rename_all_fields = "camelCase")] +pub enum ActionVisibility { + Hidden, + Disabled(String), + Enabled, +} +impl Default for ActionVisibility { + fn default() -> Self { + Self::Enabled + } +} + #[derive(Debug, Deserialize, Serialize, HasModel, TS)] #[serde(rename_all = "camelCase")] #[model = "Model"] @@ -338,7 +354,7 @@ pub struct ActionMetadata { pub struct PackageDataEntry { pub state_info: PackageState, pub data_version: Option, - pub status: Status, + pub status: MainStatus, #[ts(type = "string | null")] pub registry: Option, #[ts(type = "string")] @@ -348,6 +364,8 @@ pub struct PackageDataEntry { pub last_backup: Option>, pub current_dependencies: CurrentDependencies, pub actions: BTreeMap, + #[ts(as = "BTreeMap::")] + pub requested_actions: BTreeMap, pub service_interfaces: BTreeMap, pub hosts: Hosts, #[ts(type = "string[]")] @@ -384,8 +402,9 @@ impl Map for CurrentDependencies { } } -#[derive(Clone, Debug, Deserialize, Serialize, TS)] +#[derive(Clone, Debug, Deserialize, Serialize, TS, HasModel)] #[serde(rename_all = "camelCase")] +#[model = "Model"] pub struct CurrentDependencyInfo { #[ts(type = "string | null")] pub title: Option, @@ -394,11 +413,10 @@ pub struct CurrentDependencyInfo { pub kind: CurrentDependencyKind, #[ts(type = "string")] pub version_range: VersionRange, - pub config_satisfied: bool, } #[derive(Clone, Debug, Deserialize, Serialize, TS)] -#[serde(rename_all = "camelCase")] +#[serde(rename_all = "kebab-case")] #[serde(tag = "kind")] pub enum CurrentDependencyKind { Exists, @@ -410,6 +428,81 @@ pub enum CurrentDependencyKind { }, } +#[derive(Clone, Debug, Deserialize, Serialize, TS, HasModel)] +#[serde(rename_all = "camelCase")] +#[ts(export)] +#[model = "Model"] +pub struct ActionRequestEntry { + pub request: ActionRequest, + pub active: bool, +} + +#[derive(Clone, Debug, Deserialize, Serialize, TS, HasModel)] +#[serde(rename_all = "camelCase")] +#[ts(export)] +#[model = "Model"] +pub struct ActionRequest { + pub package_id: PackageId, + pub action_id: ActionId, + #[serde(default)] + pub severity: ActionSeverity, + #[ts(optional)] + pub reason: Option, + #[ts(optional)] + pub when: Option, + #[ts(optional)] + pub input: Option, +} + +#[derive(Clone, Debug, Deserialize, Serialize, TS)] +#[serde(rename_all = "kebab-case")] +#[ts(export)] +pub enum ActionSeverity { + Critical, + Important, +} +impl Default for ActionSeverity { + fn default() -> Self { + ActionSeverity::Important + } +} + +#[derive(Clone, Debug, Deserialize, Serialize, TS)] +#[serde(rename_all = "camelCase")] +#[ts(export)] +pub struct ActionRequestTrigger { + #[serde(default)] + pub once: bool, + pub condition: ActionRequestCondition, +} + +#[derive(Clone, Debug, Deserialize, Serialize, TS)] +#[serde(rename_all = "kebab-case")] +#[ts(export)] +pub enum ActionRequestCondition { + InputNotMatches, +} + +#[derive(Clone, Debug, Deserialize, Serialize, TS)] +#[serde(rename_all = "kebab-case")] +#[serde(tag = "kind")] +pub enum ActionRequestInput { + Partial { + #[ts(type = "Record")] + value: Value, + }, +} +impl ActionRequestInput { + pub fn matches(&self, input: Option<&Value>) -> bool { + match self { + Self::Partial { value } => match input { + None => false, + Some(full) => is_partial_of(value, full), + }, + } + } +} + #[derive(Debug, Default, Deserialize, Serialize)] pub struct InterfaceAddressMap(pub BTreeMap); impl Map for InterfaceAddressMap { diff --git a/core/startos/src/db/model/private.rs b/core/startos/src/db/model/private.rs index c57364fc3..2675b36d0 100644 --- a/core/startos/src/db/model/private.rs +++ b/core/startos/src/db/model/private.rs @@ -31,6 +31,6 @@ pub struct Private { pub package_stores: BTreeMap, } -fn generate_compat_key() -> Pem { +pub fn generate_compat_key() -> Pem { Pem(ed25519_dalek::SigningKey::generate(&mut rand::thread_rng())) } diff --git a/core/startos/src/db/model/public.rs b/core/startos/src/db/model/public.rs index b20693a90..85978134d 100644 --- a/core/startos/src/db/model/public.rs +++ b/core/startos/src/db/model/public.rs @@ -22,6 +22,7 @@ use crate::prelude::*; use crate::progress::FullProgress; use crate::system::SmtpValue; use crate::util::cpupower::Governor; +use crate::util::lshw::LshwDevice; use crate::version::{Current, VersionT}; use crate::{ARCH, PLATFORM}; @@ -43,16 +44,18 @@ impl Public { arch: get_arch(), platform: get_platform(), id: account.server_id.clone(), - version: Current::new().semver(), + version: Current::default().semver(), hostname: account.hostname.no_dot_host_name(), last_backup: None, - eos_version_compat: Current::new().compat().clone(), + package_version_compat: Current::default().compat().clone(), + post_init_migration_todos: BTreeSet::new(), lan_address, onion_address: account.tor_key.public().get_onion_address(), tor_address: format!("https://{}", account.tor_key.public().get_onion_address()) .parse() .unwrap(), ip_info: BTreeMap::new(), + acme: None, status_info: ServerStatus { backup_progress: None, updated: false, @@ -77,6 +80,8 @@ impl Public { zram: true, governor: None, smtp: None, + ram: 0, + devices: Vec::new(), }, package_data: AllPackageData::default(), ui: serde_json::from_str(include_str!(concat!( @@ -112,11 +117,13 @@ pub struct ServerInfo { pub hostname: InternedString, #[ts(type = "string")] pub version: Version, + #[ts(type = "string")] + pub package_version_compat: VersionRange, + #[ts(type = "string[]")] + pub post_init_migration_todos: BTreeSet, #[ts(type = "string | null")] pub last_backup: Option>, #[ts(type = "string")] - pub eos_version_compat: VersionRange, - #[ts(type = "string")] pub lan_address: Url, #[ts(type = "string")] pub onion_address: OnionAddressV3, @@ -124,6 +131,7 @@ pub struct ServerInfo { #[ts(type = "string")] pub tor_address: Url, pub ip_info: BTreeMap, + pub acme: Option, #[serde(default)] pub status_info: ServerStatus, pub wifi: WifiInfo, @@ -138,6 +146,9 @@ pub struct ServerInfo { pub zram: bool, pub governor: Option, pub smtp: Option, + #[ts(type = "number")] + pub ram: u64, + pub devices: Vec, } #[derive(Debug, Deserialize, Serialize, HasModel, TS)] @@ -165,6 +176,20 @@ impl IpInfo { } } +#[derive(Debug, Deserialize, Serialize, HasModel, TS)] +#[serde(rename_all = "camelCase")] +#[model = "Model"] +#[ts(export)] +pub struct AcmeSettings { + #[ts(type = "string")] + pub provider: Url, + /// email addresses for letsencrypt + pub contact: Vec, + #[ts(type = "string[]")] + /// domains to get letsencrypt certs for + pub domains: BTreeSet, +} + #[derive(Debug, Default, Deserialize, Serialize, HasModel, TS)] #[model = "Model"] #[ts(export)] diff --git a/core/startos/src/dependencies.rs b/core/startos/src/dependencies.rs index 013648980..3b55c8fc3 100644 --- a/core/startos/src/dependencies.rs +++ b/core/startos/src/dependencies.rs @@ -1,28 +1,14 @@ use std::collections::BTreeMap; -use std::time::Duration; -use clap::Parser; use imbl_value::InternedString; use models::PackageId; -use patch_db::json_patch::merge; -use rpc_toolkit::{from_fn_async, Context, Empty, HandlerExt, ParentHandler}; use serde::{Deserialize, Serialize}; -use tracing::instrument; use ts_rs::TS; -use crate::config::{Config, ConfigSpec, ConfigureContext}; -use crate::context::{CliContext, RpcContext}; -use crate::db::model::package::CurrentDependencies; use crate::prelude::*; -use crate::rpc_continuations::Guid; -use crate::util::serde::HandlerExtSerde; use crate::util::PathOrUrl; use crate::Error; -pub fn dependency() -> ParentHandler { - ParentHandler::new().subcommand("configure", configure::()) -} - #[derive(Clone, Debug, Default, Deserialize, Serialize, HasModel, TS)] #[model = "Model"] #[ts(export)] @@ -56,129 +42,3 @@ pub struct DependencyMetadata { #[ts(type = "string")] pub title: InternedString, } - -#[derive(Deserialize, Serialize, Parser, TS)] -#[serde(rename_all = "camelCase")] -#[command(rename_all = "kebab-case")] -pub struct ConfigureParams { - dependent_id: PackageId, - dependency_id: PackageId, -} -pub fn configure() -> ParentHandler { - ParentHandler::new() - .root_handler( - from_fn_async(configure_impl) - .with_inherited(|params, _| params) - .no_display() - .with_call_remote::(), - ) - .subcommand( - "dry", - from_fn_async(configure_dry) - .with_inherited(|params, _| params) - .with_display_serializable() - .with_call_remote::(), - ) -} - -pub async fn configure_impl( - ctx: RpcContext, - _: Empty, - ConfigureParams { - dependent_id, - dependency_id, - }: ConfigureParams, -) -> Result<(), Error> { - let ConfigDryRes { - old_config: _, - new_config, - spec: _, - } = configure_logic(ctx.clone(), (dependent_id, dependency_id.clone())).await?; - - let configure_context = ConfigureContext { - timeout: Some(Duration::from_secs(3).into()), - config: Some(new_config), - }; - ctx.services - .get(&dependency_id) - .await - .as_ref() - .ok_or_else(|| { - Error::new( - eyre!("There is no manager running for {dependency_id}"), - ErrorKind::Unknown, - ) - })? - .configure(Guid::new(), configure_context) - .await?; - Ok(()) -} - -pub async fn configure_dry( - ctx: RpcContext, - _: Empty, - ConfigureParams { - dependent_id, - dependency_id, - }: ConfigureParams, -) -> Result { - configure_logic(ctx.clone(), (dependent_id, dependency_id.clone())).await -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct ConfigDryRes { - pub old_config: Config, - pub new_config: Config, - pub spec: ConfigSpec, -} - -pub async fn configure_logic( - ctx: RpcContext, - (dependent_id, dependency_id): (PackageId, PackageId), -) -> Result { - let procedure_id = Guid::new(); - let dependency_guard = ctx.services.get(&dependency_id).await; - let dependency = dependency_guard.as_ref().or_not_found(&dependency_id)?; - let dependent_guard = ctx.services.get(&dependent_id).await; - let dependent = dependent_guard.as_ref().or_not_found(&dependent_id)?; - let config_res = dependency.get_config(procedure_id.clone()).await?; - let diff = Value::Object( - dependent - .dependency_config(procedure_id, dependency_id, config_res.config.clone()) - .await? - .unwrap_or_default(), - ); - let mut new_config = Value::Object(config_res.config.clone().unwrap_or_default()); - merge(&mut new_config, &diff); - Ok(ConfigDryRes { - old_config: config_res.config.unwrap_or_default(), - new_config: new_config.as_object().cloned().unwrap_or_default(), - spec: config_res.spec, - }) -} - -#[instrument(skip_all)] -pub async fn compute_dependency_config_errs( - ctx: &RpcContext, - id: &PackageId, - current_dependencies: &mut CurrentDependencies, -) -> Result<(), Error> { - let procedure_id = Guid::new(); - let service_guard = ctx.services.get(id).await; - let service = service_guard.as_ref().or_not_found(id)?; - for (dep_id, dep_info) in current_dependencies.0.iter_mut() { - // check if config passes dependency check - let Some(dependency) = &*ctx.services.get(dep_id).await else { - continue; - }; - - let dep_config = dependency.get_config(procedure_id.clone()).await?.config; - - dep_info.config_satisfied = service - .dependency_config(procedure_id.clone(), dep_id.clone(), dep_config) - .await? - .is_none(); - } - Ok(()) -} diff --git a/core/startos/src/diagnostic.rs b/core/startos/src/diagnostic.rs index 5e99580e9..f0c142706 100644 --- a/core/startos/src/diagnostic.rs +++ b/core/startos/src/diagnostic.rs @@ -9,35 +9,53 @@ use rpc_toolkit::{ use crate::context::{CliContext, DiagnosticContext, RpcContext}; use crate::init::SYSTEM_REBUILD_PATH; use crate::shutdown::Shutdown; +use crate::util::io::delete_file; use crate::Error; pub fn diagnostic() -> ParentHandler { ParentHandler::new() - .subcommand("error", from_fn(error).with_call_remote::()) - .subcommand("logs", crate::system::logs::()) + .subcommand( + "error", + from_fn(error) + .with_about("Display diagnostic error") + .with_call_remote::(), + ) .subcommand( "logs", - from_fn_async(crate::logs::cli_logs::).no_display(), + crate::system::logs::().with_about("Display OS logs"), + ) + .subcommand( + "logs", + from_fn_async(crate::logs::cli_logs::) + .no_display() + .with_about("Display OS logs"), ) .subcommand( "kernel-logs", - crate::system::kernel_logs::(), + crate::system::kernel_logs::().with_about("Display kernel logs"), ) .subcommand( "kernel-logs", - from_fn_async(crate::logs::cli_logs::).no_display(), + from_fn_async(crate::logs::cli_logs::) + .no_display() + .with_about("Display kernal logs"), ) .subcommand( "restart", from_fn(restart) .no_display() + .with_about("Restart the server") .with_call_remote::(), ) - .subcommand("disk", disk::()) + .subcommand( + "disk", + disk::().with_about("Command to remove disk from filesystem"), + ) .subcommand( "rebuild", from_fn_async(rebuild) .no_display() + .with_about("Teardown and rebuild service containers") .with_call_remote::(), ) } @@ -72,14 +90,13 @@ pub fn disk() -> ParentHandler { CallRemoteHandler::::new( from_fn_async(forget_disk::).no_display(), ) - .no_display(), + .no_display() + .with_about("Remove disk from filesystem"), ) } pub async fn forget_disk(_: C) -> Result<(), Error> { - let disk_guid = Path::new("/media/startos/config/disk.guid"); - if tokio::fs::metadata(disk_guid).await.is_ok() { - tokio::fs::remove_file(disk_guid).await?; - } + delete_file("/media/startos/config/overlay/etc/hostname").await?; + delete_file("/media/startos/config/disk.guid").await?; Ok(()) } diff --git a/core/startos/src/disk/mod.rs b/core/startos/src/disk/mod.rs index c0a701fc9..d1fbe282f 100644 --- a/core/startos/src/disk/mod.rs +++ b/core/startos/src/disk/mod.rs @@ -51,13 +51,16 @@ pub fn disk() -> ParentHandler { .with_custom_display_fn(|handle, result| { Ok(display_disk_info(handle.params, result)) }) + .with_about("List disk info") .with_call_remote::(), ) .subcommand("repair", from_fn_async(|_: C| repair()).no_cli()) .subcommand( "repair", CallRemoteHandler::::new( - from_fn_async(|_: RpcContext| repair()).no_display(), + from_fn_async(|_: RpcContext| repair()) + .no_display() + .with_about("Repair disk in the event of corruption"), ), ) } diff --git a/core/startos/src/disk/mount/backup.rs b/core/startos/src/disk/mount/backup.rs index 8f45b0d4f..2c322c284 100644 --- a/core/startos/src/disk/mount/backup.rs +++ b/core/startos/src/disk/mount/backup.rs @@ -219,10 +219,10 @@ impl Drop for BackupMountGuard { let second = self.backup_disk_mount_guard.take(); tokio::spawn(async move { if let Some(guard) = first { - guard.unmount().await.unwrap(); + guard.unmount().await.log_err(); } if let Some(guard) = second { - guard.unmount().await.unwrap(); + guard.unmount().await.log_err(); } }); } diff --git a/core/startos/src/disk/mount/filesystem/overlayfs.rs b/core/startos/src/disk/mount/filesystem/overlayfs.rs index 5e40a21a1..e8d1f0b34 100644 --- a/core/startos/src/disk/mount/filesystem/overlayfs.rs +++ b/core/startos/src/disk/mount/filesystem/overlayfs.rs @@ -151,12 +151,12 @@ impl Drop for OverlayGuard { let guard = self.inner_guard.take(); if lower.is_some() || upper.is_some() || guard.mounted { tokio::spawn(async move { - guard.unmount(false).await.unwrap(); + guard.unmount(false).await.log_err(); if let Some(lower) = lower { - lower.unmount().await.unwrap(); + lower.unmount().await.log_err(); } if let Some(upper) = upper { - upper.delete().await.unwrap(); + upper.delete().await.log_err(); } }); } diff --git a/core/startos/src/disk/mount/guard.rs b/core/startos/src/disk/mount/guard.rs index a2d577226..6e1cdc35e 100644 --- a/core/startos/src/disk/mount/guard.rs +++ b/core/startos/src/disk/mount/guard.rs @@ -96,7 +96,7 @@ impl Drop for MountGuard { fn drop(&mut self) { if self.mounted { let mountpoint = std::mem::take(&mut self.mountpoint); - tokio::spawn(async move { unmount(mountpoint, true).await.unwrap() }); + tokio::spawn(async move { unmount(mountpoint, true).await.log_err() }); } } } diff --git a/core/startos/src/disk/mount/util.rs b/core/startos/src/disk/mount/util.rs index 674f33304..61368e67a 100644 --- a/core/startos/src/disk/mount/util.rs +++ b/core/startos/src/disk/mount/util.rs @@ -5,6 +5,16 @@ use tracing::instrument; use crate::util::Invoke; use crate::Error; +pub async fn is_mountpoint(path: impl AsRef) -> Result { + let is_mountpoint = tokio::process::Command::new("mountpoint") + .arg(path.as_ref()) + .stdout(std::process::Stdio::null()) + .stderr(std::process::Stdio::null()) + .status() + .await?; + Ok(is_mountpoint.success()) +} + #[instrument(skip_all)] pub async fn bind, P1: AsRef>( src: P0, @@ -16,13 +26,7 @@ pub async fn bind, P1: AsRef>( src.as_ref().display(), dst.as_ref().display() ); - let is_mountpoint = tokio::process::Command::new("mountpoint") - .arg(dst.as_ref()) - .stdout(std::process::Stdio::null()) - .stderr(std::process::Stdio::null()) - .status() - .await?; - if is_mountpoint.success() { + if is_mountpoint(&dst).await? { unmount(dst.as_ref(), true).await?; } tokio::fs::create_dir_all(&src).await?; diff --git a/core/startos/src/init.rs b/core/startos/src/init.rs index e6b7be598..a81e7e336 100644 --- a/core/startos/src/init.rs +++ b/core/startos/src/init.rs @@ -32,7 +32,9 @@ use crate::progress::{ use crate::rpc_continuations::{Guid, RpcContinuation}; use crate::s9pk::v2::pack::{CONTAINER_DATADIR, CONTAINER_TOOL}; use crate::ssh::SSH_AUTHORIZED_KEYS_FILE; +use crate::system::get_mem_info; use crate::util::io::{create_file, IOHook}; +use crate::util::lshw::lshw; use crate::util::net::WebSocketExt; use crate::util::{cpupower, Invoke}; use crate::Error; @@ -323,7 +325,9 @@ pub async fn init( local_auth.complete(); load_database.start(); - let db = TypedPatchDb::::load_unchecked(cfg.db().await?); + let db = cfg.db().await?; + crate::version::Current::default().pre_init(&db).await?; + let db = TypedPatchDb::::load_unchecked(db); let peek = db.peek().await; load_database.complete(); tracing::info!("Opened PatchDB"); @@ -506,6 +510,8 @@ pub async fn init( update_server_info.start(); server_info.ip_info = crate::net::dhcp::init_ips().await?; + server_info.ram = get_mem_info().await?.total.0 as u64 * 1024 * 1024; + server_info.devices = lshw().await?; server_info.status_info = ServerStatus { updated: false, update_progress: None, @@ -528,8 +534,6 @@ pub async fn init( .await?; launch_service_network.complete(); - crate::version::init(&db, run_migrations).await?; - validate_db.start(); db.mutate(|d| { let model = d.de()?; @@ -549,18 +553,33 @@ pub async fn init( pub fn init_api() -> ParentHandler { ParentHandler::new() - .subcommand("logs", crate::system::logs::()) .subcommand( "logs", - from_fn_async(crate::logs::cli_logs::).no_display(), + crate::system::logs::().with_about("Disply OS logs"), + ) + .subcommand( + "logs", + from_fn_async(crate::logs::cli_logs::) + .no_display() + .with_about("Display OS logs"), ) - .subcommand("kernel-logs", crate::system::kernel_logs::()) .subcommand( "kernel-logs", - from_fn_async(crate::logs::cli_logs::).no_display(), + crate::system::kernel_logs::().with_about("Display kernel logs"), + ) + .subcommand( + "kernel-logs", + from_fn_async(crate::logs::cli_logs::) + .no_display() + .with_about("Display kernel logs"), ) .subcommand("subscribe", from_fn_async(init_progress).no_cli()) - .subcommand("subscribe", from_fn_async(cli_init_progress).no_display()) + .subcommand( + "subscribe", + from_fn_async(cli_init_progress) + .no_display() + .with_about("Get initialization progress"), + ) } #[derive(Debug, Deserialize, Serialize, TS)] diff --git a/core/startos/src/install/mod.rs b/core/startos/src/install/mod.rs index 7a545a3aa..f153c88ad 100644 --- a/core/startos/src/install/mod.rs +++ b/core/startos/src/install/mod.rs @@ -9,7 +9,7 @@ use exver::VersionRange; use futures::{AsyncWriteExt, StreamExt}; use imbl_value::{json, InternedString}; use itertools::Itertools; -use models::VersionString; +use models::{FromStrParser, VersionString}; use reqwest::header::{HeaderMap, CONTENT_LENGTH}; use reqwest::Url; use rpc_toolkit::yajrc::{GenericRpcMethod, RpcError}; @@ -17,6 +17,7 @@ use rpc_toolkit::HandlerArgs; use rustyline_async::ReadlineEvent; use serde::{Deserialize, Serialize}; use tokio::sync::oneshot; +use tokio_tungstenite::tungstenite::protocol::frame::coding::CloseCode; use tracing::instrument; use ts_rs::TS; @@ -29,7 +30,6 @@ use crate::registry::package::get::GetPackageResponse; use crate::rpc_continuations::{Guid, RpcContinuation}; use crate::s9pk::manifest::PackageId; use crate::upload::upload; -use crate::util::clap::FromStrParser; use crate::util::io::open_file; use crate::util::net::WebSocketExt; use crate::util::Never; @@ -172,7 +172,7 @@ pub async fn install( pub struct SideloadParams { #[ts(skip)] #[serde(rename = "__auth_session")] - session: InternedString, + session: Option, } #[derive(Deserialize, Serialize, TS)] @@ -188,7 +188,7 @@ pub async fn sideload( SideloadParams { session }: SideloadParams, ) -> Result { let (upload, file) = upload(&ctx, session.clone()).await?; - let (err_send, err_recv) = oneshot::channel(); + let (err_send, err_recv) = oneshot::channel::(); let progress = Guid::new(); let progress_tracker = FullProgressTracker::new(); let mut progress_listener = progress_tracker.stream(Some(Duration::from_millis(200))); @@ -202,12 +202,14 @@ pub async fn sideload( use axum::extract::ws::Message; async move { if let Err(e) = async { - type RpcResponse = rpc_toolkit::yajrc::RpcResponse::>; + type RpcResponse = rpc_toolkit::yajrc::RpcResponse< + GenericRpcMethod<&'static str, (), FullProgress>, + >; tokio::select! { res = async { while let Some(progress) = progress_listener.next().await { ws.send(Message::Text( - serde_json::to_string(&RpcResponse::from_result::(Ok(progress))) + serde_json::to_string(&progress) .with_kind(ErrorKind::Serialization)?, )) .await @@ -217,12 +219,8 @@ pub async fn sideload( } => res?, err = err_recv => { if let Ok(e) = err { - ws.send(Message::Text( - serde_json::to_string(&RpcResponse::from_result::(Err(e))) - .with_kind(ErrorKind::Serialization)?, - )) - .await - .with_kind(ErrorKind::Network)?; + ws.close_result(Err::<&str, _>(e.clone_output())).await?; + return Err(e) } } } @@ -260,7 +258,7 @@ pub async fn sideload( } .await { - let _ = err_send.send(RpcError::from(e.clone_output())); + let _ = err_send.send(e.clone_output()); tracing::error!("Error sideloading package: {e}"); tracing::debug!("{e:?}"); } @@ -407,19 +405,21 @@ pub async fn cli_install( let mut progress = FullProgress::new(); - type RpcResponse = rpc_toolkit::yajrc::RpcResponse< - GenericRpcMethod<&'static str, (), FullProgress>, - >; - loop { tokio::select! { msg = ws.next() => { if let Some(msg) = msg { - if let Message::Text(t) = msg.with_kind(ErrorKind::Network)? { - progress = - serde_json::from_str::(&t) - .with_kind(ErrorKind::Deserialization)?.result?; - bar.update(&progress); + match msg.with_kind(ErrorKind::Network)? { + Message::Text(t) => { + progress = + serde_json::from_str::(&t) + .with_kind(ErrorKind::Deserialization)?; + bar.update(&progress); + } + Message::Close(Some(c)) if c.code != CloseCode::Normal => { + return Err(Error::new(eyre!("{}", c.reason), ErrorKind::Network)) + } + _ => (), } } else { break; diff --git a/core/startos/src/lib.rs b/core/startos/src/lib.rs index feeb5a647..3c5875e36 100644 --- a/core/startos/src/lib.rs +++ b/core/startos/src/lib.rs @@ -29,7 +29,6 @@ pub mod action; pub mod auth; pub mod backup; pub mod bins; -pub mod config; pub mod context; pub mod control; pub mod db; @@ -50,7 +49,6 @@ pub mod notifications; pub mod os_install; pub mod prelude; pub mod progress; -pub mod properties; pub mod registry; pub mod rpc_continuations; pub mod s9pk; @@ -70,7 +68,6 @@ pub mod volume; use std::time::SystemTime; use clap::Parser; -pub use config::Config; pub use error::{Error, ErrorKind, ResultExt}; use imbl_value::Value; use rpc_toolkit::yajrc::RpcError; @@ -116,29 +113,70 @@ impl std::fmt::Display for ApiState { pub fn main_api() -> ParentHandler { let api = ParentHandler::new() - .subcommand::("git-info", from_fn(version::git_info)) + .subcommand( + "git-info", + from_fn(|_: C| version::git_info()).with_about("Display the githash of StartOS CLI"), + ) .subcommand( "echo", from_fn(echo::) .with_metadata("authenticated", Value::Bool(false)) + .with_about("Echo a message") .with_call_remote::(), ) .subcommand( "state", from_fn(|_: RpcContext| Ok::<_, Error>(ApiState::Running)) .with_metadata("authenticated", Value::Bool(false)) + .with_about("Display the API that is currently serving") .with_call_remote::(), ) - .subcommand("server", server::()) - .subcommand("package", package::()) - .subcommand("net", net::net::()) - .subcommand("auth", auth::auth::()) - .subcommand("db", db::db::()) - .subcommand("ssh", ssh::ssh::()) - .subcommand("wifi", net::wifi::wifi::()) - .subcommand("disk", disk::disk::()) - .subcommand("notification", notifications::notification::()) - .subcommand("backup", backup::backup::()) + .subcommand( + "server", + server::() + .with_about("Commands related to the server i.e. restart, update, and shutdown"), + ) + .subcommand( + "package", + package::().with_about("Commands related to packages"), + ) + .subcommand( + "net", + net::net::().with_about("Network commands related to tor and dhcp"), + ) + .subcommand( + "auth", + auth::auth::().with_about( + "Commands related to Authentication i.e. login, logout, reset-password", + ), + ) + .subcommand( + "db", + db::db::().with_about("Commands to interact with the db i.e. dump, put, apply"), + ) + .subcommand( + "ssh", + ssh::ssh::() + .with_about("Commands for interacting with ssh keys i.e. add, delete, list"), + ) + .subcommand( + "wifi", + net::wifi::wifi::() + .with_about("Commands related to wifi networks i.e. add, connect, delete"), + ) + .subcommand( + "disk", + disk::disk::().with_about("Commands for listing disk info and repairing"), + ) + .subcommand( + "notification", + notifications::notification::().with_about("Create, delete, or list notifications"), + ) + .subcommand( + "backup", + backup::backup::() + .with_about("Commands related to backup creation and backup targets"), + ) .subcommand( "registry", CallRemoteHandler::::new( @@ -146,10 +184,20 @@ pub fn main_api() -> ParentHandler { ) .no_cli(), ) - .subcommand("s9pk", s9pk::rpc::s9pk()) - .subcommand("util", util::rpc::util::()); + .subcommand( + "s9pk", + s9pk::rpc::s9pk().with_about("Commands for interacting with s9pk files"), + ) + .subcommand( + "util", + util::rpc::util::().with_about("Command for calculating the blake3 hash of a file"), + ); #[cfg(feature = "dev")] - let api = api.subcommand("lxc", lxc::dev::lxc::()); + let api = api.subcommand( + "lxc", + lxc::dev::lxc::() + .with_about("Commands related to lxc containers i.e. create, list, remove, connect"), + ); api } @@ -162,42 +210,57 @@ pub fn server() -> ParentHandler { .with_custom_display_fn(|handle, result| { Ok(system::display_time(handle.params, result)) }) - .with_call_remote::(), + .with_about("Display current time and server uptime") + .with_call_remote::() + ) + .subcommand( + "experimental", + system::experimental::() + .with_about("Commands related to configuring experimental options such as zram and cpu governor"), ) - .subcommand("experimental", system::experimental::()) - .subcommand("logs", system::logs::()) .subcommand( "logs", - from_fn_async(logs::cli_logs::).no_display(), + system::logs::().with_about("Display OS logs"), + ) + .subcommand( + "logs", + from_fn_async(logs::cli_logs::).no_display().with_about("Display OS logs"), ) - .subcommand("kernel-logs", system::kernel_logs::()) .subcommand( "kernel-logs", - from_fn_async(logs::cli_logs::).no_display(), + system::kernel_logs::().with_about("Display Kernel logs"), + ) + .subcommand( + "kernel-logs", + from_fn_async(logs::cli_logs::).no_display().with_about("Display Kernel logs"), ) .subcommand( "metrics", from_fn_async(system::metrics) .with_display_serializable() - .with_call_remote::(), + .with_about("Display information about the server i.e. temperature, RAM, CPU, and disk usage") + .with_call_remote::() ) .subcommand( "shutdown", from_fn_async(shutdown::shutdown) .no_display() - .with_call_remote::(), + .with_about("Shutdown the server") + .with_call_remote::() ) .subcommand( "restart", from_fn_async(shutdown::restart) .no_display() - .with_call_remote::(), + .with_about("Restart the server") + .with_call_remote::() ) .subcommand( "rebuild", from_fn_async(shutdown::rebuild) .no_display() - .with_call_remote::(), + .with_about("Teardown and rebuild service containers") + .with_call_remote::() ) .subcommand( "update", @@ -207,7 +270,7 @@ pub fn server() -> ParentHandler { ) .subcommand( "update", - from_fn_async(update::cli_update_system).no_display(), + from_fn_async(update::cli_update_system).no_display().with_about("Check a given registry for StartOS updates and update if available"), ) .subcommand( "update-firmware", @@ -222,19 +285,22 @@ pub fn server() -> ParentHandler { .with_custom_display_fn(|_handle, result| { Ok(firmware::display_firmware_update_result(result)) }) - .with_call_remote::(), + .with_about("Update the mainboard's firmware to the latest firmware available in this version of StartOS if available. Note: This command does not reach out to the Internet") + .with_call_remote::() ) .subcommand( "set-smtp", from_fn_async(system::set_system_smtp) .no_display() - .with_call_remote::(), + .with_about("Set system smtp server and credentials") + .with_call_remote::() ) .subcommand( "clear-smtp", from_fn_async(system::clear_system_smtp) .no_display() - .with_call_remote::(), + .with_about("Remove system smtp server and credentials") + .with_call_remote::() ) } @@ -242,12 +308,7 @@ pub fn package() -> ParentHandler { ParentHandler::new() .subcommand( "action", - from_fn_async(action::action) - .with_display_serializable() - .with_custom_display_fn(|handle, result| { - Ok(action::display_action_result(handle.params, result)) - }) - .with_call_remote::(), + action::action_api::().with_about("Commands to get action input or run an action"), ) .subcommand( "install", @@ -261,32 +322,40 @@ pub fn package() -> ParentHandler { .with_metadata("get_session", Value::Bool(true)) .no_cli(), ) - .subcommand("install", from_fn_async(install::cli_install).no_display()) + .subcommand( + "install", + from_fn_async(install::cli_install) + .no_display() + .with_about("Install a package from a marketplace or via sideloading"), + ) .subcommand( "uninstall", from_fn_async(install::uninstall) .with_metadata("sync_db", Value::Bool(true)) .no_display() + .with_about("Remove a package") .with_call_remote::(), ) .subcommand( "list", from_fn_async(install::list) .with_display_serializable() + .with_about("List installed packages") .with_call_remote::(), ) .subcommand( "installed-version", from_fn_async(install::installed_version) .with_display_serializable() + .with_about("Display installed version for a PackageId") .with_call_remote::(), ) - .subcommand("config", config::config::()) .subcommand( "start", from_fn_async(control::start) .with_metadata("sync_db", Value::Bool(true)) .no_display() + .with_about("Start a service") .with_call_remote::(), ) .subcommand( @@ -294,6 +363,7 @@ pub fn package() -> ParentHandler { from_fn_async(control::stop) .with_metadata("sync_db", Value::Bool(true)) .no_display() + .with_about("Stop a service") .with_call_remote::(), ) .subcommand( @@ -301,100 +371,174 @@ pub fn package() -> ParentHandler { from_fn_async(control::restart) .with_metadata("sync_db", Value::Bool(true)) .no_display() + .with_about("Restart a service") + .with_call_remote::(), + ) + .subcommand( + "rebuild", + from_fn_async(service::rebuild) + .with_metadata("sync_db", Value::Bool(true)) + .no_display() + .with_about("Rebuild service container") .with_call_remote::(), ) .subcommand("logs", logs::package_logs()) .subcommand( "logs", - from_fn_async(logs::cli_logs::).no_display(), + logs::package_logs().with_about("Display package logs"), ) .subcommand( - "properties", - from_fn_async(properties::properties) - .with_custom_display_fn(|_handle, result| { - Ok(properties::display_properties(result)) - }) - .with_call_remote::(), + "logs", + from_fn_async(logs::cli_logs::) + .no_display() + .with_about("Display package logs"), + ) + .subcommand( + "backup", + backup::package_backup::() + .with_about("Commands for restoring package(s) from backup"), ) - .subcommand("dependency", dependencies::dependency::()) - .subcommand("backup", backup::package_backup::()) .subcommand("connect", from_fn_async(service::connect_rpc).no_cli()) .subcommand( "connect", - from_fn_async(service::connect_rpc_cli).no_display(), + from_fn_async(service::connect_rpc_cli) + .no_display() + .with_about("Connect to a LXC container"), + ) + .subcommand( + "attach", + from_fn_async(service::attach) + .with_metadata("get_session", Value::Bool(true)) + .with_about("Execute commands within a service container") + .no_cli(), + ) + .subcommand("attach", from_fn_async(service::cli_attach).no_display()) + .subcommand( + "host", + net::host::host::().with_about("Manage network hosts for a package"), ) } pub fn diagnostic_api() -> ParentHandler { ParentHandler::new() - .subcommand::( + .subcommand( "git-info", - from_fn(version::git_info).with_metadata("authenticated", Value::Bool(false)), + 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_call_remote::(), + 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::()) + .subcommand( + "diagnostic", + diagnostic::diagnostic::() + .with_about("Diagnostic commands i.e. logs, restart, rebuild"), + ) } pub fn init_api() -> ParentHandler { ParentHandler::new() - .subcommand::( + .subcommand( "git-info", - from_fn(version::git_info).with_metadata("authenticated", Value::Bool(false)), + 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_call_remote::(), + 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::()) + .subcommand( + "init", + init::init_api::() + .with_about("Commands to get logs or initialization progress"), + ) } pub fn setup_api() -> ParentHandler { ParentHandler::new() - .subcommand::( + .subcommand( "git-info", - from_fn(version::git_info).with_metadata("authenticated", Value::Bool(false)), + 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_call_remote::(), + from_fn(echo::) + .with_about("Echo a message") + .with_call_remote::(), ) .subcommand("setup", setup::setup::()) } pub fn install_api() -> ParentHandler { ParentHandler::new() - .subcommand::( + .subcommand( "git-info", - from_fn(version::git_info).with_metadata("authenticated", Value::Bool(false)), + 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_call_remote::(), + 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"), ) - .subcommand("install", os_install::install::()) } pub fn expanded_api() -> ParentHandler { main_api() - .subcommand("init", from_fn_blocking(developer::init).no_display()) - .subcommand("pubkey", from_fn_blocking(developer::pubkey)) - .subcommand("diagnostic", diagnostic::diagnostic::()) + .subcommand( + "init", + from_fn_blocking(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::()) - .subcommand("registry", registry::registry_api::()) + .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 9cf234f5f..1cb3327b6 100644 --- a/core/startos/src/logs.rs +++ b/core/startos/src/logs.rs @@ -12,7 +12,7 @@ use color_eyre::eyre::eyre; use futures::stream::BoxStream; use futures::{Future, FutureExt, Stream, StreamExt, TryStreamExt}; use itertools::Itertools; -use models::PackageId; +use models::{FromStrParser, PackageId}; use rpc_toolkit::yajrc::RpcError; use rpc_toolkit::{ from_fn_async, CallRemote, Context, Empty, HandlerArgs, HandlerExt, HandlerFor, ParentHandler, @@ -30,7 +30,6 @@ use crate::error::ResultExt; use crate::lxc::ContainerId; use crate::prelude::*; use crate::rpc_continuations::{Guid, RpcContinuation, RpcContinuations}; -use crate::util::clap::FromStrParser; use crate::util::serde::Reversible; use crate::util::Invoke; @@ -114,7 +113,7 @@ async fn ws_handler( #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] pub struct LogResponse { - entries: Reversible, + pub entries: Reversible, start_cursor: Option, end_cursor: Option, } @@ -361,11 +360,7 @@ pub fn logs< source: impl for<'a> LogSourceFn<'a, C, Extra>, ) -> ParentHandler> { ParentHandler::new() - .root_handler( - logs_nofollow::(source.clone()) - .with_inherited(|params, _| params) - .no_cli(), - ) + .root_handler(logs_nofollow::(source.clone()).no_cli()) .subcommand( "follow", logs_follow::(source) @@ -437,7 +432,7 @@ where fn logs_nofollow( f: impl for<'a> LogSourceFn<'a, C, Extra>, -) -> impl HandlerFor, Ok = LogResponse, Err = Error> +) -> impl HandlerFor, InheritedParams = Empty, Ok = LogResponse, Err = Error> where C: Context, Extra: FromArgMatches + Args + Send + Sync + 'static, @@ -445,7 +440,7 @@ where from_fn_async( move |HandlerArgs { context, - inherited_params: + params: LogsParams { extra, limit, @@ -454,7 +449,7 @@ where before, }, .. - }: HandlerArgs>| { + }: HandlerArgs>| { let f = f.clone(); async move { fetch_logs( @@ -487,14 +482,18 @@ fn logs_follow< context, inherited_params: LogsParams { - extra, limit, boot, .. + extra, + cursor, + limit, + boot, + .. }, .. }: HandlerArgs>| { let f = f.clone(); async move { let src = f.call(&context, extra).await?; - follow_logs(context, src, limit, boot.map(String::from)).await + follow_logs(context, src, cursor, limit, boot.map(String::from)).await } }, ) @@ -525,7 +524,7 @@ pub fn package_logs() -> ParentHandler> pub async fn journalctl( id: LogSource, - limit: usize, + limit: Option, cursor: Option<&str>, boot: Option<&str>, before: bool, @@ -533,11 +532,12 @@ pub async fn journalctl( ) -> Result { let mut cmd = gen_journalctl_command(&id); - cmd.arg(format!("--lines={}", limit)); + if let Some(limit) = limit { + cmd.arg(format!("--lines={}", limit)); + } - let cursor_formatted = format!("--after-cursor={}", cursor.unwrap_or("")); - if cursor.is_some() { - cmd.arg(&cursor_formatted); + if let Some(cursor) = cursor { + cmd.arg(&format!("--after-cursor={}", cursor)); if before { cmd.arg("--reverse"); } @@ -638,8 +638,15 @@ pub async fn fetch_logs( before: bool, ) -> Result { let limit = limit.unwrap_or(50); - let mut stream = - journalctl(id, limit, cursor.as_deref(), boot.as_deref(), before, false).await?; + let mut stream = journalctl( + id, + Some(limit), + cursor.as_deref(), + boot.as_deref(), + before, + false, + ) + .await?; let mut entries = Vec::with_capacity(limit); let mut start_cursor = None; @@ -682,11 +689,16 @@ pub async fn fetch_logs( pub async fn follow_logs>( ctx: Context, id: LogSource, + cursor: Option, limit: Option, boot: Option, ) -> Result { - let limit = limit.unwrap_or(50); - let mut stream = journalctl(id, limit, None, boot.as_deref(), false, true).await?; + let limit = if cursor.is_some() { + None + } else { + Some(limit.unwrap_or(50)) + }; + let mut stream = journalctl(id, limit, cursor.as_deref(), boot.as_deref(), false, true).await?; let mut start_cursor = None; let mut first_entry = None; diff --git a/core/startos/src/lxc/dev.rs b/core/startos/src/lxc/dev.rs index 61dd8e598..248546d88 100644 --- a/core/startos/src/lxc/dev.rs +++ b/core/startos/src/lxc/dev.rs @@ -8,16 +8,21 @@ use rpc_toolkit::{ use serde::{Deserialize, Serialize}; use ts_rs::TS; -use crate::context::{CliContext, RpcContext}; use crate::lxc::{ContainerId, LxcConfig}; use crate::prelude::*; use crate::rpc_continuations::Guid; +use crate::{ + context::{CliContext, RpcContext}, + service::ServiceStats, +}; pub fn lxc() -> ParentHandler { ParentHandler::new() .subcommand( "create", - from_fn_async(create).with_call_remote::(), + from_fn_async(create) + .with_about("Create lxc container") + .with_call_remote::(), ) .subcommand( "list", @@ -31,16 +36,59 @@ pub fn lxc() -> ParentHandler { table.printstd(); Ok(()) }) + .with_about("List lxc containers") + .with_call_remote::(), + ) + .subcommand( + "stats", + from_fn_async(stats) + .with_custom_display_fn(|_, res| { + use prettytable::*; + let mut table = table!([ + "Container ID", + "Name", + "Memory Usage", + "Memory Limit", + "Memory %" + ]); + for ServiceStats { + container_id, + package_id, + memory_usage, + memory_limit, + } in res + { + table.add_row(row![ + &*container_id, + &*package_id, + memory_usage, + memory_limit, + format!( + "{:.2}", + memory_usage.0 as f64 / memory_limit.0 as f64 * 100.0 + ) + ]); + } + table.printstd(); + Ok(()) + }) + .with_about("List information related to the lxc containers i.e. CPU, Memory, Disk") .with_call_remote::(), ) .subcommand( "remove", from_fn_async(remove) .no_display() + .with_about("Remove lxc container") .with_call_remote::(), ) .subcommand("connect", from_fn_async(connect_rpc).no_cli()) - .subcommand("connect", from_fn_async(connect_rpc_cli).no_display()) + .subcommand( + "connect", + from_fn_async(connect_rpc_cli) + .no_display() + .with_about("Connect to a lxc container"), + ) } pub async fn create(ctx: RpcContext) -> Result { @@ -54,6 +102,22 @@ pub async fn list(ctx: RpcContext) -> Result, Error> { Ok(ctx.dev.lxc.lock().await.keys().cloned().collect()) } +pub async fn stats(ctx: RpcContext) -> Result, Error> { + let ids = ctx.db.peek().await.as_public().as_package_data().keys()?; + let guids: Vec<_> = ctx.dev.lxc.lock().await.keys().cloned().collect(); + + let mut stats = Vec::with_capacity(guids.len()); + for id in ids { + let service: tokio::sync::OwnedRwLockReadGuard> = + ctx.services.get(&id).await; + + let service_ref = service.as_ref().or_not_found(&id)?; + + stats.push(service_ref.stats().await?); + } + Ok(stats) +} + #[derive(Deserialize, Serialize, Parser, TS)] pub struct RemoveParams { #[ts(type = "string")] diff --git a/core/startos/src/lxc/mod.rs b/core/startos/src/lxc/mod.rs index 480f7a24c..c0fb6eaba 100644 --- a/core/startos/src/lxc/mod.rs +++ b/core/startos/src/lxc/mod.rs @@ -1,13 +1,13 @@ -use std::collections::BTreeSet; use std::net::Ipv4Addr; use std::path::Path; use std::sync::{Arc, Weak}; use std::time::Duration; +use std::{collections::BTreeSet, ffi::OsString}; use clap::builder::ValueParserFactory; use futures::{AsyncWriteExt, StreamExt}; use imbl_value::{InOMap, InternedString}; -use models::InvalidId; +use models::{FromStrParser, InvalidId}; use rpc_toolkit::yajrc::RpcError; use rpc_toolkit::{GenericRpcMethod, RpcRequest, RpcResponse}; use rustyline_async::{ReadlineEvent, SharedWriter}; @@ -28,12 +28,11 @@ use crate::disk::mount::guard::{GenericMountGuard, MountGuard, TmpMountGuard}; use crate::disk::mount::util::unmount; use crate::prelude::*; use crate::rpc_continuations::{Guid, RpcContinuation}; -use crate::util::clap::FromStrParser; use crate::util::io::open_file; use crate::util::rpc_client::UnixRpcClient; use crate::util::{new_guid, Invoke}; -#[cfg(feature = "dev")] +// #[cfg(feature = "dev")] pub mod dev; const LXC_CONTAINER_DIR: &str = "/var/lib/lxc"; @@ -127,7 +126,8 @@ impl LxcManager { Path::new(LXC_CONTAINER_DIR).join(container).join("rootfs"), true, ) - .await?; + .await + .log_err(); if tokio_stream::wrappers::ReadDirStream::new( tokio::fs::read_dir(&rootfs_path).await?, ) @@ -287,6 +287,30 @@ impl LxcContainer { self.rpc_bind.path() } + pub async fn command(&self, commands: &[&str]) -> Result { + let mut cmd = Command::new("lxc-attach"); + cmd.kill_on_drop(true); + + let output = cmd + .arg(&**self.guid) + .arg("--") + .args(commands) + .output() + .await?; + + if !output.status.success() { + return Err(Error::new( + eyre!( + "Command failed with exit code: {:?} \n Message: {:?}", + output.status.code(), + String::from_utf8(output.stderr) + ), + ErrorKind::Docker, + )); + } + Ok(String::from_utf8(output.stdout)?) + } + #[instrument(skip_all)] pub async fn exit(mut self) -> Result<(), Error> { Command::new("lxc-stop") @@ -365,7 +389,7 @@ impl Drop for LxcContainer { tracing::error!("Error reading logs from crashed container: {e}"); tracing::debug!("{e:?}") } - rootfs.unmount(true).await.unwrap(); + rootfs.unmount(true).await.log_err(); drop(guid); if let Err(e) = manager.gc().await { tracing::error!("Error cleaning up dangling LXC containers: {e}"); diff --git a/core/startos/src/middleware/auth.rs b/core/startos/src/middleware/auth.rs index 9b04afb38..7c5eaa4c2 100644 --- a/core/startos/src/middleware/auth.rs +++ b/core/startos/src/middleware/auth.rs @@ -49,7 +49,7 @@ impl HasLoggedOutSessions { .map(|s| s.as_logout_session_id()) .collect(); for sid in &to_log_out { - ctx.open_authed_continuations.kill(sid) + ctx.open_authed_continuations.kill(&Some(sid.clone())) } ctx.ephemeral_sessions.mutate(|s| { for sid in &to_log_out { diff --git a/core/startos/src/net/acme.rs b/core/startos/src/net/acme.rs new file mode 100644 index 000000000..95f9d4adb --- /dev/null +++ b/core/startos/src/net/acme.rs @@ -0,0 +1,324 @@ +use std::collections::{BTreeMap, BTreeSet}; +use std::str::FromStr; + +use clap::builder::ValueParserFactory; +use clap::Parser; +use imbl_value::InternedString; +use itertools::Itertools; +use models::{ErrorData, FromStrParser}; +use openssl::pkey::{PKey, Private}; +use openssl::x509::X509; +use rpc_toolkit::{from_fn_async, Context, HandlerExt, ParentHandler}; +use serde::{Deserialize, Serialize}; +use url::Url; + +use crate::context::{CliContext, RpcContext}; +use crate::db::model::public::AcmeSettings; +use crate::db::model::Database; +use crate::prelude::*; +use crate::util::serde::{Pem, Pkcs8Doc}; + +#[derive(Debug, Default, Deserialize, Serialize, HasModel)] +#[model = "Model"] +pub struct AcmeCertStore { + pub accounts: BTreeMap>, Pem>, + pub certs: BTreeMap>, AcmeCert>>, +} +impl AcmeCertStore { + pub fn new() -> Self { + Self::default() + } +} + +#[derive(Debug, Deserialize, Serialize)] +pub struct AcmeCert { + pub key: Pem>, + pub fullchain: Vec>, +} + +pub struct AcmeCertCache<'a>(pub &'a TypedPatchDb); +#[async_trait::async_trait] +impl<'a> async_acme::cache::AcmeCache for AcmeCertCache<'a> { + 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 { + return Ok(None); + }; + Ok(Some(account.de()?.0.document.into_vec())) + } + + async fn write_account(&self, contacts: &[&str], contents: &[u8]) -> Result<(), Self::Error> { + let contacts = JsonKey::new(contacts.into_iter().map(|s| (*s).to_owned()).collect_vec()); + let key = Pkcs8Doc { + tag: "EC PRIVATE KEY".into(), + document: pkcs8::Document::try_from(contents).with_kind(ErrorKind::Pem)?, + }; + self.0 + .mutate(|db| { + db.as_private_mut() + .as_key_store_mut() + .as_acme_mut() + .as_accounts_mut() + .insert(&contacts, &Pem::new(key)) + }) + .await?; + Ok(()) + } + + async fn read_certificate( + &self, + domains: &[String], + directory_url: &str, + ) -> Result, Self::Error> { + let domains = JsonKey::new(domains.into_iter().map(InternedString::intern).collect()); + 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(&domains)) + else { + return Ok(None); + }; + let cert = cert.de()?; + Ok(Some(( + String::from_utf8( + cert.key + .0 + .private_key_to_pem_pkcs8() + .with_kind(ErrorKind::OpenSsl)?, + ) + .with_kind(ErrorKind::Utf8)?, + cert.fullchain + .into_iter() + .map(|cert| { + String::from_utf8(cert.0.to_pem().with_kind(ErrorKind::OpenSsl)?) + .with_kind(ErrorKind::Utf8) + }) + .collect::, _>>()? + .join("\n"), + ))) + } + + async fn write_certificate( + &self, + domains: &[String], + directory_url: &str, + key_pem: &str, + certificate_pem: &str, + ) -> Result<(), Self::Error> { + tracing::info!("Saving new certificate for {domains:?}"); + let domains = JsonKey::new(domains.into_iter().map(InternedString::intern).collect()); + let directory_url = directory_url + .parse::() + .with_kind(ErrorKind::ParseUrl)?; + let cert = AcmeCert { + key: Pem(PKey::::private_key_from_pem(key_pem.as_bytes()) + .with_kind(ErrorKind::OpenSsl)?), + fullchain: X509::stack_from_pem(certificate_pem.as_bytes()) + .with_kind(ErrorKind::OpenSsl)? + .into_iter() + .map(Pem) + .collect(), + }; + self.0 + .mutate(|db| { + db.as_private_mut() + .as_key_store_mut() + .as_acme_mut() + .as_certs_mut() + .upsert(&directory_url, || Ok(BTreeMap::new()))? + .insert(&domains, &cert) + }) + .await?; + + Ok(()) + } +} + +pub fn acme() -> ParentHandler { + ParentHandler::new() + .subcommand( + "init", + from_fn_async(init) + .no_display() + .with_about("Setup ACME certificate acquisition") + .with_call_remote::(), + ) + .subcommand( + "domain", + domain::() + .with_about("Add, remove, or view domains for which to acquire ACME certificates"), + ) +} + +#[derive(Clone, Deserialize, Serialize)] +pub struct AcmeProvider(pub Url); +impl FromStr for AcmeProvider { + type Err = ::Err; + fn from_str(s: &str) -> Result { + match s { + "letsencrypt" => async_acme::acme::LETS_ENCRYPT_PRODUCTION_DIRECTORY.parse(), + "letsencrypt-staging" => async_acme::acme::LETS_ENCRYPT_STAGING_DIRECTORY.parse(), + s => s.parse(), + } + .map(Self) + } +} +impl ValueParserFactory for AcmeProvider { + type Parser = FromStrParser; + fn value_parser() -> Self::Parser { + Self::Parser::new() + } +} + +#[derive(Deserialize, Serialize, Parser)] +pub struct InitAcmeParams { + #[arg(long)] + pub provider: AcmeProvider, + #[arg(long)] + pub contact: Vec, +} + +pub async fn init( + ctx: RpcContext, + InitAcmeParams { + provider: AcmeProvider(provider), + contact, + }: InitAcmeParams, +) -> Result<(), Error> { + ctx.db + .mutate(|db| { + db.as_public_mut() + .as_server_info_mut() + .as_acme_mut() + .map_mutate(|acme| { + Ok(Some(AcmeSettings { + provider, + contact, + domains: acme.map(|acme| acme.domains).unwrap_or_default(), + })) + }) + }) + .await?; + Ok(()) +} + +pub fn domain() -> ParentHandler { + ParentHandler::new() + .subcommand( + "add", + from_fn_async(add_domain) + .no_display() + .with_about("Add a domain for which to acquire ACME certificates") + .with_call_remote::(), + ) + .subcommand( + "remove", + from_fn_async(remove_domain) + .no_display() + .with_about("Remove a domain for which to acquire ACME certificates") + .with_call_remote::(), + ) + .subcommand( + "list", + from_fn_async(list_domains) + .with_custom_display_fn(|_, res| { + for domain in res { + println!("{domain}") + } + Ok(()) + }) + .with_about("List domains for which to acquire ACME certificates") + .with_call_remote::(), + ) +} + +#[derive(Deserialize, Serialize, Parser)] +pub struct DomainParams { + pub domain: InternedString, +} + +pub async fn add_domain( + ctx: RpcContext, + DomainParams { domain }: DomainParams, +) -> Result<(), Error> { + ctx.db + .mutate(|db| { + db.as_public_mut() + .as_server_info_mut() + .as_acme_mut() + .transpose_mut() + .ok_or_else(|| { + Error::new( + eyre!("Please call `start-cli net acme init` before adding a domain"), + ErrorKind::InvalidRequest, + ) + })? + .as_domains_mut() + .mutate(|domains| { + domains.insert(domain); + Ok(()) + }) + }) + .await?; + Ok(()) +} + +pub async fn remove_domain( + ctx: RpcContext, + DomainParams { domain }: DomainParams, +) -> Result<(), Error> { + ctx.db + .mutate(|db| { + if let Some(acme) = db + .as_public_mut() + .as_server_info_mut() + .as_acme_mut() + .transpose_mut() + { + acme.as_domains_mut().mutate(|domains| { + domains.remove(&domain); + Ok(()) + }) + } else { + Ok(()) + } + }) + .await?; + Ok(()) +} + +pub async fn list_domains(ctx: RpcContext) -> Result, Error> { + if let Some(acme) = ctx + .db + .peek() + .await + .into_public() + .into_server_info() + .into_acme() + .transpose() + { + acme.into_domains().de() + } else { + Ok(BTreeSet::new()) + } +} diff --git a/core/startos/src/net/dhcp.rs b/core/startos/src/net/dhcp.rs index ffcb9774b..e323ba371 100644 --- a/core/startos/src/net/dhcp.rs +++ b/core/startos/src/net/dhcp.rs @@ -58,6 +58,7 @@ pub fn dhcp() -> ParentHandler { "update", from_fn_async::<_, _, (), Error, (RpcContext, UpdateParams)>(update) .no_display() + .with_about("Update IP assigned by dhcp") .with_call_remote::(), ) } diff --git a/core/startos/src/net/dns.rs b/core/startos/src/net/dns.rs index 090e845b0..016e5de9f 100644 --- a/core/startos/src/net/dns.rs +++ b/core/startos/src/net/dns.rs @@ -98,16 +98,8 @@ impl RequestHandler for Resolver { ) .await } - a => { - if a != RecordType::AAAA { - tracing::warn!( - "Non A-Record requested for {}: {:?}", - query.name(), - query.query_type() - ); - } - let mut res = Header::response_from_request(request.header()); - res.set_response_code(ResponseCode::NXDomain); + _ => { + let res = Header::response_from_request(request.header()); response_handle .send_response( MessageResponseBuilder::from_message_request(&*request).build( diff --git a/core/startos/src/net/host/address.rs b/core/startos/src/net/host/address.rs index 9b16441ce..05942ffa9 100644 --- a/core/startos/src/net/host/address.rs +++ b/core/startos/src/net/host/address.rs @@ -1,7 +1,9 @@ use std::fmt; use std::str::FromStr; +use clap::builder::ValueParserFactory; use imbl_value::InternedString; +use models::FromStrParser; use serde::{Deserialize, Serialize}; use torut::onion::OnionAddressV3; use ts_rs::TS; @@ -46,3 +48,10 @@ impl fmt::Display for HostAddress { } } } + +impl ValueParserFactory for HostAddress { + type Parser = FromStrParser; + fn value_parser() -> Self::Parser { + Self::Parser::new() + } +} diff --git a/core/startos/src/net/host/binding.rs b/core/startos/src/net/host/binding.rs index 76dd04059..174f0330f 100644 --- a/core/startos/src/net/host/binding.rs +++ b/core/startos/src/net/host/binding.rs @@ -1,3 +1,7 @@ +use std::str::FromStr; + +use clap::builder::ValueParserFactory; +use models::{FromStrParser, HostId}; use serde::{Deserialize, Serialize}; use ts_rs::TS; @@ -5,10 +9,37 @@ use crate::net::forward::AvailablePorts; use crate::net::vhost::AlpnInfo; use crate::prelude::*; +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, TS)] +#[ts(export)] +#[serde(rename_all = "camelCase")] +pub struct BindId { + pub id: HostId, + pub internal_port: u16, +} +impl ValueParserFactory for BindId { + type Parser = FromStrParser; + fn value_parser() -> Self::Parser { + FromStrParser::new() + } +} +impl FromStr for BindId { + type Err = Error; + fn from_str(s: &str) -> Result { + let (id, port) = s + .split_once(":") + .ok_or_else(|| Error::new(eyre!("expected :"), ErrorKind::ParseUrl))?; + Ok(Self { + id: id.parse()?, + internal_port: port.parse()?, + }) + } +} + #[derive(Debug, Deserialize, Serialize, TS)] #[serde(rename_all = "camelCase")] #[ts(export)] pub struct BindInfo { + pub enabled: bool, pub options: BindOptions, pub lan: LanInfo, } @@ -30,6 +61,7 @@ impl BindInfo { assigned_ssl_port = Some(available_ports.alloc()?); } Ok(Self { + enabled: true, options, lan: LanInfo { assigned_port, @@ -69,7 +101,14 @@ impl BindInfo { available_ports.free([port]); } } - Ok(Self { options, lan }) + Ok(Self { + enabled: true, + options, + lan, + }) + } + pub fn disable(&mut self) { + self.enabled = false; } } diff --git a/core/startos/src/net/host/mod.rs b/core/startos/src/net/host/mod.rs index 175fe3e83..be5db0f2d 100644 --- a/core/startos/src/net/host/mod.rs +++ b/core/startos/src/net/host/mod.rs @@ -1,10 +1,13 @@ use std::collections::{BTreeMap, BTreeSet}; +use clap::Parser; use imbl_value::InternedString; use models::{HostId, PackageId}; +use rpc_toolkit::{from_fn_async, Context, Empty, HandlerExt, ParentHandler}; use serde::{Deserialize, Serialize}; use ts_rs::TS; +use crate::context::{CliContext, RpcContext}; use crate::db::model::DatabaseModel; use crate::net::forward::AvailablePorts; use crate::net::host::address::HostAddress; @@ -134,3 +137,163 @@ impl Model { }) } } + +#[derive(Deserialize, Serialize, Parser)] +pub struct HostParams { + package: PackageId, +} + +pub fn host() -> ParentHandler { + ParentHandler::::new() + .subcommand( + "list", + from_fn_async(list_hosts) + .with_inherited(|HostParams { package }, _| package) + .with_custom_display_fn(|_, ids| { + for id in ids { + println!("{id}") + } + Ok(()) + }) + .with_about("List host IDs available for this service"), + ) + .subcommand( + "address", + address::().with_inherited(|HostParams { package }, _| package), + ) +} + +pub async fn list_hosts( + ctx: RpcContext, + _: Empty, + package: PackageId, +) -> Result, Error> { + ctx.db + .peek() + .await + .into_public() + .into_package_data() + .into_idx(&package) + .or_not_found(&package)? + .into_hosts() + .keys() +} + +#[derive(Deserialize, Serialize, Parser)] +pub struct AddressApiParams { + host: HostId, +} + +pub fn address() -> ParentHandler { + ParentHandler::::new() + .subcommand( + "add", + from_fn_async(add_address) + .with_inherited(|AddressApiParams { host }, package| (package, host)) + .no_display() + .with_about("Add an address to this host") + .with_call_remote::(), + ) + .subcommand( + "remove", + from_fn_async(remove_address) + .with_inherited(|AddressApiParams { host }, package| (package, host)) + .no_display() + .with_about("Remove an address from this host") + .with_call_remote::(), + ) + .subcommand( + "list", + from_fn_async(list_addresses) + .with_inherited(|AddressApiParams { host }, package| (package, host)) + .with_custom_display_fn(|_, res| { + for address in res { + println!("{address}") + } + Ok(()) + }) + .with_about("List addresses for this host") + .with_call_remote::(), + ) +} + +#[derive(Deserialize, Serialize, Parser)] +pub struct AddressParams { + pub address: HostAddress, +} + +pub async fn add_address( + ctx: RpcContext, + AddressParams { address }: AddressParams, + (package, host): (PackageId, HostId), +) -> Result<(), Error> { + ctx.db + .mutate(|db| { + if let HostAddress::Onion { address } = address { + db.as_private() + .as_key_store() + .as_onion() + .get_key(&address)?; + } + + db.as_public_mut() + .as_package_data_mut() + .as_idx_mut(&package) + .or_not_found(&package)? + .as_hosts_mut() + .as_idx_mut(&host) + .or_not_found(&host)? + .as_addresses_mut() + .mutate(|a| Ok(a.insert(address))) + }) + .await?; + let service = ctx.services.get(&package).await; + let service_ref = service.as_ref().or_not_found(&package)?; + service_ref.update_host(host).await?; + + Ok(()) +} + +pub async fn remove_address( + ctx: RpcContext, + AddressParams { address }: AddressParams, + (package, host): (PackageId, HostId), +) -> Result<(), Error> { + ctx.db + .mutate(|db| { + db.as_public_mut() + .as_package_data_mut() + .as_idx_mut(&package) + .or_not_found(&package)? + .as_hosts_mut() + .as_idx_mut(&host) + .or_not_found(&host)? + .as_addresses_mut() + .mutate(|a| Ok(a.remove(&address))) + }) + .await?; + let service = ctx.services.get(&package).await; + let service_ref = service.as_ref().or_not_found(&package)?; + service_ref.update_host(host).await?; + + Ok(()) +} + +pub async fn list_addresses( + ctx: RpcContext, + _: Empty, + (package, host): (PackageId, HostId), +) -> Result, Error> { + ctx.db + .peek() + .await + .into_public() + .into_package_data() + .into_idx(&package) + .or_not_found(&package)? + .into_hosts() + .into_idx(&host) + .or_not_found(&host)? + .into_addresses() + .de() +} diff --git a/core/startos/src/net/keys.rs b/core/startos/src/net/keys.rs index 02ec17329..866b2ca06 100644 --- a/core/startos/src/net/keys.rs +++ b/core/startos/src/net/keys.rs @@ -1,6 +1,7 @@ use serde::{Deserialize, Serialize}; use crate::account::AccountInfo; +use crate::net::acme::AcmeCertStore; use crate::net::ssl::CertStore; use crate::net::tor::OnionStore; use crate::prelude::*; @@ -10,13 +11,15 @@ use crate::prelude::*; pub struct KeyStore { pub onion: OnionStore, pub local_certs: CertStore, - // pub letsencrypt_certs: BTreeMap, CertData> + #[serde(default)] + pub acme: AcmeCertStore, } impl KeyStore { pub fn new(account: &AccountInfo) -> Result { let mut res = Self { onion: OnionStore::new(), local_certs: CertStore::new(account)?, + acme: AcmeCertStore::new(), }; res.onion.insert(account.tor_key.clone()); Ok(res) diff --git a/core/startos/src/net/mod.rs b/core/startos/src/net/mod.rs index e55da4206..53b94454d 100644 --- a/core/startos/src/net/mod.rs +++ b/core/startos/src/net/mod.rs @@ -1,5 +1,6 @@ -use rpc_toolkit::{Context, ParentHandler}; +use rpc_toolkit::{Context, HandlerExt, ParentHandler}; +pub mod acme; pub mod dhcp; pub mod dns; pub mod forward; @@ -20,6 +21,16 @@ pub const PACKAGE_CERT_PATH: &str = "/var/lib/embassy/ssl"; pub fn net() -> ParentHandler { ParentHandler::new() - .subcommand("tor", tor::tor::()) - .subcommand("dhcp", dhcp::dhcp::()) + .subcommand( + "tor", + tor::tor::().with_about("Tor commands such as list-services, logs, and reset"), + ) + .subcommand( + "dhcp", + dhcp::dhcp::().with_about("Command to update IP assigned from dhcp"), + ) + .subcommand( + "acme", + acme::acme::().with_about("Setup automatic clearnet certificate acquisition"), + ) } diff --git a/core/startos/src/net/net_controller.rs b/core/startos/src/net/net_controller.rs index b7a8022b4..a8beaf55f 100644 --- a/core/startos/src/net/net_controller.rs +++ b/core/startos/src/net/net_controller.rs @@ -15,8 +15,8 @@ use crate::hostname::Hostname; use crate::net::dns::DnsController; use crate::net::forward::LanPortForwardController; use crate::net::host::address::HostAddress; -use crate::net::host::binding::{AddSslOptions, BindOptions, LanInfo}; -use crate::net::host::{host_for, Host, HostKind}; +use crate::net::host::binding::{AddSslOptions, BindId, BindOptions, LanInfo}; +use crate::net::host::{host_for, Host, HostKind, Hosts}; use crate::net::service_interface::{HostnameInfo, IpHostname, OnionHostname}; use crate::net::tor::TorController; use crate::net::vhost::{AlpnInfo, VHostController}; @@ -154,14 +154,16 @@ impl NetController { ) -> Result { let dns = self.dns.add(Some(package.clone()), ip).await?; - Ok(NetService { + let mut res = NetService { shutdown: false, id: package, ip, dns, controller: Arc::downgrade(self), binds: BTreeMap::new(), - }) + }; + res.clear_bindings(Default::default()).await?; + Ok(res) } } @@ -221,35 +223,45 @@ impl NetService { self.update(id, host).await } - pub async fn clear_bindings(&mut self) -> Result<(), Error> { - let ctrl = self.net_controller()?; + pub async fn clear_bindings(&mut self, except: BTreeSet) -> Result<(), Error> { + let pkg_id = &self.id; + let hosts = self + .net_controller()? + .db + .mutate(|db| { + let mut res = Hosts::default(); + for (host_id, host) in db + .as_public_mut() + .as_package_data_mut() + .as_idx_mut(pkg_id) + .or_not_found(pkg_id)? + .as_hosts_mut() + .as_entries_mut()? + { + host.as_bindings_mut().mutate(|b| { + for (internal_port, info) in b { + if !except.contains(&BindId { + id: host_id.clone(), + internal_port: *internal_port, + }) { + info.disable(); + } + } + Ok(()) + })?; + res.0.insert(host_id, host.de()?); + } + Ok(res) + }) + .await?; let mut errors = ErrorCollection::new(); - for (_, binds) in std::mem::take(&mut self.binds) { - for (_, (lan, _, hostnames, rc)) in binds.lan { - drop(rc); - if let Some(external) = lan.assigned_ssl_port { - for hostname in ctrl.server_hostnames.iter().cloned() { - ctrl.vhost.gc(hostname, external).await?; - } - for hostname in hostnames { - ctrl.vhost.gc(Some(hostname), external).await?; - } - } - if let Some(external) = lan.assigned_port { - ctrl.forward.gc(external).await?; - } - } - for (addr, (_, rcs)) in binds.tor { - drop(rcs); - errors.handle(ctrl.tor.gc(Some(addr), None).await); - } + for (id, host) in hosts.0 { + errors.handle(self.update(id, host).await); } - std::mem::take(&mut self.dns); - errors.handle(ctrl.dns.gc(Some(self.id.clone()), self.ip).await); errors.into_result() } - async fn update(&mut self, id: HostId, host: Host) -> Result<(), Error> { + pub async fn update(&mut self, id: HostId, host: Host) -> Result<(), Error> { let ctrl = self.net_controller()?; let mut hostname_info = BTreeMap::new(); let binds = self.binds.entry(id.clone()).or_default(); @@ -261,6 +273,9 @@ impl NetService { let ip_info = server_info.as_ip_info().de()?; let hostname = server_info.as_hostname().de()?; for (port, bind) in &host.bindings { + if !bind.enabled { + continue; + } let old_lan_bind = binds.lan.remove(port); let lan_bind = old_lan_bind .as_ref() @@ -315,16 +330,29 @@ impl NetService { } HostAddress::Domain { address } => { if hostnames.insert(address.clone()) { + let address = Some(address.clone()); rcs.push( ctrl.vhost .add( - Some(address.clone()), + address.clone(), external, target, connect_ssl.clone(), ) .await?, ); + if ssl.preferred_external_port == 443 { + rcs.push( + ctrl.vhost + .add( + address.clone(), + 5443, + target, + connect_ssl.clone(), + ) + .await?, + ); + } } } } @@ -348,11 +376,32 @@ impl NetService { network_interface_id: interface.clone(), public: false, hostname: IpHostname::Local { - value: format!("{hostname}.local"), + value: InternedString::from_display(&{ + let hostname = &hostname; + lazy_format!("{hostname}.local") + }), port: new_lan_bind.0.assigned_port, ssl_port: new_lan_bind.0.assigned_ssl_port, }, }); + for address in host.addresses() { + if let HostAddress::Domain { address } = address { + if let Some(ssl) = &new_lan_bind.1 { + if ssl.preferred_external_port == 443 { + bind_hostname_info.push(HostnameInfo::Ip { + network_interface_id: interface.clone(), + public: false, + hostname: IpHostname::Domain { + domain: address.clone(), + subdomain: None, + port: None, + ssl_port: Some(443), + }, + }); + } + } + } + } if let Some(ipv4) = ip_info.ipv4 { bind_hostname_info.push(HostnameInfo::Ip { network_interface_id: interface.clone(), @@ -395,7 +444,7 @@ impl NetService { } let mut removed = BTreeSet::new(); binds.lan.retain(|internal, (external, _, hostnames, _)| { - if host.bindings.contains_key(internal) { + if host.bindings.get(internal).map_or(false, |b| b.enabled) { true } else { removed.insert((*external, std::mem::take(hostnames))); @@ -424,6 +473,9 @@ impl NetService { let mut tor_hostname_ports = BTreeMap::::new(); let mut tor_binds = OrdMap::::new(); for (internal, info) in &host.bindings { + if !info.enabled { + continue; + } tor_binds.insert( info.options.preferred_external_port, SocketAddr::from((self.ip, *internal)), @@ -497,6 +549,7 @@ impl NetService { ctrl.tor.gc(Some(addr.clone()), None).await?; } } + self.net_controller()? .db .mutate(|db| { @@ -511,7 +564,7 @@ impl NetService { pub async fn remove_all(mut self) -> Result<(), Error> { self.shutdown = true; if let Some(ctrl) = Weak::upgrade(&self.controller) { - self.clear_bindings().await?; + self.clear_bindings(Default::default()).await?; drop(ctrl); Ok(()) } else { @@ -566,7 +619,7 @@ impl Drop for NetService { binds: BTreeMap::new(), }, ); - tokio::spawn(async move { svc.remove_all().await.unwrap() }); + tokio::spawn(async move { svc.remove_all().await.log_err() }); } } } diff --git a/core/startos/src/net/service_interface.rs b/core/startos/src/net/service_interface.rs index b1824140b..ade10d959 100644 --- a/core/startos/src/net/service_interface.rs +++ b/core/startos/src/net/service_interface.rs @@ -47,13 +47,16 @@ pub enum IpHostname { ssl_port: Option, }, Local { - value: String, + #[ts(type = "string")] + value: InternedString, port: Option, ssl_port: Option, }, Domain { - domain: String, - subdomain: Option, + #[ts(type = "string")] + domain: InternedString, + #[ts(type = "string | null")] + subdomain: Option, port: Option, ssl_port: Option, }, diff --git a/core/startos/src/net/static_server.rs b/core/startos/src/net/static_server.rs index f1da91851..c070d7920 100644 --- a/core/startos/src/net/static_server.rs +++ b/core/startos/src/net/static_server.rs @@ -84,7 +84,7 @@ pub fn rpc_router>( server: HttpServer, ) -> Router { Router::new() - .route("/rpc/*path", post(server)) + .route("/rpc/*path", any(server)) .route( "/ws/rpc/:guid", get({ diff --git a/core/startos/src/net/tor.rs b/core/startos/src/net/tor.rs index 24b8ddb02..bba50c371 100644 --- a/core/startos/src/net/tor.rs +++ b/core/startos/src/net/tor.rs @@ -26,7 +26,7 @@ use ts_rs::TS; use crate::context::{CliContext, RpcContext}; use crate::logs::{journalctl, LogSource, LogsParams}; use crate::prelude::*; -use crate::util::serde::{display_serializable, HandlerExtSerde, WithIoFormat}; +use crate::util::serde::{display_serializable, Base64, HandlerExtSerde, WithIoFormat}; use crate::util::Invoke; pub const SYSTEMD_UNIT: &str = "tor@default"; @@ -59,7 +59,9 @@ impl Model { self.insert(&key.public().get_onion_address(), &key) } pub fn get_key(&self, address: &OnionAddressV3) -> Result { - self.as_idx(address).or_not_found(address)?.de() + self.as_idx(address) + .or_not_found(lazy_format!("private key for {address}"))? + .de() } } @@ -91,20 +93,102 @@ pub fn tor() -> ParentHandler { .with_custom_display_fn(|handle, result| { Ok(display_services(handle.params, result)) }) + .with_about("Display Tor V3 Onion Addresses") .with_call_remote::(), ) - .subcommand("logs", logs()) + .subcommand("logs", logs().with_about("Display Tor logs")) .subcommand( "logs", - from_fn_async(crate::logs::cli_logs::).no_display(), + 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()? + .public() + .get_onion_address()) + }) + .await +} + +#[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 = TorSecretKeyV3::from(key.0); + ctx.db + .mutate(|db| { + db.as_private_mut() + .as_key_store_mut() + .as_onion_mut() + .insert_key(&key) + }) + .await?; + Ok(key.public().get_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")] @@ -307,7 +391,7 @@ async fn torctl( let logs = journalctl( LogSource::Unit(SYSTEMD_UNIT), - 0, + Some(0), None, Some("0"), false, diff --git a/core/startos/src/net/vhost.rs b/core/startos/src/net/vhost.rs index 9fc7c8384..7d48b1469 100644 --- a/core/startos/src/net/vhost.rs +++ b/core/startos/src/net/vhost.rs @@ -4,6 +4,7 @@ use std::str::FromStr; use std::sync::{Arc, Weak}; use std::time::Duration; +use async_acme::acme::ACME_TLS_ALPN_NAME; use axum::body::Body; use axum::extract::Request; use axum::response::Response; @@ -15,31 +16,47 @@ use models::ResultExt; use serde::{Deserialize, Serialize}; use tokio::io::AsyncWriteExt; use tokio::net::{TcpListener, TcpStream}; -use tokio::sync::{Mutex, RwLock}; +use tokio::sync::{watch, Mutex, RwLock}; +use tokio_rustls::rustls::crypto::CryptoProvider; use tokio_rustls::rustls::pki_types::{ CertificateDer, PrivateKeyDer, PrivatePkcs8KeyDer, ServerName, }; -use tokio_rustls::rustls::server::Acceptor; +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::wrappers::WatchStream; +use tokio_stream::StreamExt; use tracing::instrument; use ts_rs::TS; use crate::db::model::Database; +use crate::net::acme::AcmeCertCache; use crate::net::static_server::server_error; use crate::prelude::*; use crate::util::io::BackTrackingIO; +use crate::util::sync::SyncMutex; use crate::util::serde::MaybeUtf8String; +#[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 { + crypto_provider: Arc, db: TypedPatchDb, servers: Mutex>, } impl VHostController { pub fn new(db: TypedPatchDb) -> Self { Self { + crypto_provider: Arc::new(tokio_rustls::rustls::crypto::ring::default_provider()), db, servers: Mutex::new(BTreeMap::new()), } @@ -56,7 +73,8 @@ impl VHostController { let server = if let Some(server) = writable.remove(&external) { server } else { - VHostServer::new(external, self.db.clone()).await? + tracing::info!("Listening on {external}"); + VHostServer::new(external, self.db.clone(), self.crypto_provider.clone()).await? }; let rc = server .add( @@ -108,7 +126,11 @@ struct VHostServer { } impl VHostServer { #[instrument(skip_all)] - async fn new(port: u16, db: TypedPatchDb) -> Result { + async fn new(port: u16, db: TypedPatchDb, crypto_provider: Arc) -> Result { + let acme_tls_alpn_cache = Arc::new(SyncMutex::new(BTreeMap::< + InternedString, + watch::Receiver>>, + >::new())); // check if port allowed let listener = TcpListener::bind(SocketAddr::new(Ipv6Addr::UNSPECIFIED.into(), port)) .await @@ -133,9 +155,11 @@ impl VHostServer { let mut stream = BackTrackingIO::new(stream); let mapping = mapping.clone(); let db = db.clone(); + let acme_tls_alpn_cache = acme_tls_alpn_cache.clone(); + let crypto_provider = crypto_provider.clone(); tokio::spawn(async move { if let Err(e) = async { - let mid = match LazyConfigAcceptor::new( + let mid: tokio_rustls::StartHandshake<&mut BackTrackingIO> = match LazyConfigAcceptor::new( Acceptor::default(), &mut stream, ) @@ -206,38 +230,102 @@ impl VHostServer { .map(|(target, _)| target.clone()) }; if let Some(target) = target { - let mut tcp_stream = - TcpStream::connect(target.addr).await?; - let hostnames = target_name - .into_iter() - .chain( - db.peek() - .await - .into_public() - .into_server_info() - .into_ip_info() - .into_entries()? - .into_iter() - .flat_map(|(_, ips)| [ - ips.as_ipv4().de().map(|ip| ip.map(IpAddr::V4)), - ips.as_ipv6().de().map(|ip| ip.map(IpAddr::V6)) - ]) - .filter_map(|a| a.transpose()) - .map(|a| a.map(|ip| InternedString::from_display(&ip))) - .collect::, _>>()?, - ) - .collect(); - let key = db - .mutate(|v| { - v.as_private_mut() - .as_key_store_mut() - .as_local_certs_mut() - .cert_for(&hostnames) - }) - .await?; - let cfg = ServerConfig::builder() - .with_no_client_auth(); - let mut cfg = + let peek = db.peek().await; + let root = peek.as_private().as_key_store().as_local_certs().as_root_cert().de()?; + let mut cfg = match async { + if let Some(acme_settings) = peek.as_public().as_server_info().as_acme().de()? { + if let Some(domain) = target_name.as_ref().filter(|target_name| acme_settings.domains.contains(*target_name)) { + 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()]; + return Ok(Err(cfg)); + } else { + let domains = [domain.to_string()]; + 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(()) + }, + acme_settings.provider.as_str(), + &domains, + Some(&AcmeCertCache(&db)), + &acme_settings.contact, + ) + .await + .with_kind(ErrorKind::OpenSsl)?; + return Ok(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( + peek + .as_public() + .as_server_info() + .as_ip_info() + .as_entries()? + .into_iter() + .flat_map(|(_, ips)| [ + ips.as_ipv4().de().map(|ip| ip.map(IpAddr::V4)), + ips.as_ipv6().de().map(|ip| ip.map(IpAddr::V6)) + ]) + .filter_map(|a| a.transpose()) + .map(|a| a.map(|ip| InternedString::from_display(&ip))) + .collect::, _>>()?, + ) + .collect(); + let key = db + .mutate(|v| { + v.as_private_mut() + .as_key_store_mut() + .as_local_certs_mut() + .cert_for(&hostnames) + }) + .await?; + 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, ) { @@ -275,16 +363,34 @@ impl VHostServer { )), ) } - .with_kind(crate::ErrorKind::OpenSsl)?; + .with_kind(crate::ErrorKind::OpenSsl) + .map(Ok) + }.await? { + Ok(a) => a, + Err(cfg) => { + 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 mut tcp_stream = + TcpStream::connect(target.addr).await?; match target.connect_ssl { Ok(()) => { let mut client_cfg = - tokio_rustls::rustls::ClientConfig::builder() + 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( - key.root.to_der()?, + root.to_der()?, ), ).with_kind(crate::ErrorKind::OpenSsl)?; store diff --git a/core/startos/src/net/web_server.rs b/core/startos/src/net/web_server.rs index a9cfdf046..d1ad64d01 100644 --- a/core/startos/src/net/web_server.rs +++ b/core/startos/src/net/web_server.rs @@ -7,7 +7,7 @@ use axum::extract::Request; use axum::Router; use axum_server::Handle; use bytes::Bytes; -use futures::future::ready; +use futures::future::{ready, BoxFuture}; use futures::FutureExt; use helpers::NonDetachingJoinHandle; use tokio::sync::{oneshot, watch}; @@ -30,8 +30,39 @@ impl SwappableRouter { } } -#[derive(Clone)] -pub struct SwappableRouterService(watch::Receiver); +pub struct SwappableRouterService { + router: watch::Receiver, + changed: Option>, +} +impl SwappableRouterService { + fn router(&self) -> Router { + self.router.borrow().clone() + } + fn changed(&mut self, cx: &mut std::task::Context<'_>) -> Poll<()> { + let mut changed = if let Some(changed) = self.changed.take() { + changed + } else { + let mut router = self.router.clone(); + async move { + router.changed().await; + } + .boxed() + }; + if changed.poll_unpin(cx).is_ready() { + return Poll::Ready(()); + } + self.changed = Some(changed); + Poll::Pending + } +} +impl Clone for SwappableRouterService { + fn clone(&self) -> Self { + Self { + router: self.router.clone(), + changed: None, + } + } +} impl tower_service::Service> for SwappableRouterService where B: axum::body::HttpBody + Send + 'static, @@ -42,15 +73,13 @@ where type Future = >>::Future; #[inline] fn poll_ready(&mut self, cx: &mut std::task::Context<'_>) -> Poll> { - let mut changed = self.0.changed().boxed(); - if changed.poll_unpin(cx).is_ready() { + if self.changed(cx).is_ready() { return Poll::Ready(Ok(())); } - drop(changed); - tower_service::Service::>::poll_ready(&mut self.0.borrow().clone(), cx) + tower_service::Service::>::poll_ready(&mut self.router(), cx) } fn call(&mut self, req: Request) -> Self::Future { - self.0.borrow().clone().call(req) + self.router().call(req) } } @@ -66,7 +95,10 @@ impl tower_service::Service for SwappableRouter { Poll::Ready(Ok(())) } fn call(&mut self, _: T) -> Self::Future { - ready(Ok(SwappableRouterService(self.0.subscribe()))) + ready(Ok(SwappableRouterService { + router: self.0.subscribe(), + changed: None, + })) } } diff --git a/core/startos/src/net/wifi.rs b/core/startos/src/net/wifi.rs index 298fad71f..056a403de 100644 --- a/core/startos/src/net/wifi.rs +++ b/core/startos/src/net/wifi.rs @@ -43,18 +43,21 @@ pub fn wifi() -> ParentHandler { "add", from_fn_async(add) .no_display() + .with_about("Add wifi ssid and password") .with_call_remote::(), ) .subcommand( "connect", from_fn_async(connect) .no_display() + .with_about("Connect to wifi network") .with_call_remote::(), ) .subcommand( "delete", from_fn_async(delete) .no_display() + .with_about("Remove a wifi network") .with_call_remote::(), ) .subcommand( @@ -64,10 +67,17 @@ pub fn wifi() -> ParentHandler { .with_custom_display_fn(|handle, result| { Ok(display_wifi_info(handle.params, result)) }) + .with_about("List wifi info") .with_call_remote::(), ) - .subcommand("country", country::()) - .subcommand("available", available::()) + .subcommand( + "country", + country::().with_about("Command to set country"), + ) + .subcommand( + "available", + available::().with_about("Command to list available wifi networks"), + ) } pub fn available() -> ParentHandler { @@ -76,6 +86,7 @@ pub fn available() -> ParentHandler { from_fn_async(get_available) .with_display_serializable() .with_custom_display_fn(|handle, result| Ok(display_wifi_list(handle.params, result))) + .with_about("List available wifi networks") .with_call_remote::(), ) } @@ -85,6 +96,7 @@ pub fn country() -> ParentHandler { "set", from_fn_async(set_country) .no_display() + .with_about("Set Country") .with_call_remote::(), ) } diff --git a/core/startos/src/notifications.rs b/core/startos/src/notifications.rs index c99ffb356..b310220b5 100644 --- a/core/startos/src/notifications.rs +++ b/core/startos/src/notifications.rs @@ -7,7 +7,7 @@ use clap::builder::ValueParserFactory; use clap::Parser; use color_eyre::eyre::eyre; use imbl_value::InternedString; -use models::PackageId; +use models::{FromStrParser, PackageId}; use rpc_toolkit::{from_fn_async, Context, HandlerExt, ParentHandler}; use serde::{Deserialize, Serialize}; use tracing::instrument; @@ -17,7 +17,6 @@ use crate::backup::BackupReport; use crate::context::{CliContext, RpcContext}; use crate::db::model::DatabaseModel; use crate::prelude::*; -use crate::util::clap::FromStrParser; use crate::util::serde::HandlerExtSerde; // #[command(subcommands(list, delete, delete_before, create))] @@ -27,24 +26,28 @@ pub fn notification() -> ParentHandler { "list", from_fn_async(list) .with_display_serializable() + .with_about("List notifications") .with_call_remote::(), ) .subcommand( "delete", from_fn_async(delete) .no_display() + .with_about("Delete notification for a given id") .with_call_remote::(), ) .subcommand( "delete-before", from_fn_async(delete_before) .no_display() + .with_about("Delete notifications preceding a given id") .with_call_remote::(), ) .subcommand( "create", from_fn_async(create) .no_display() + .with_about("Persist a newly created notification") .with_call_remote::(), ) } @@ -253,13 +256,13 @@ impl Map for Notifications { #[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Notification { - package_id: Option, - created_at: DateTime, - code: u32, - level: NotificationLevel, - title: String, - message: String, - data: Value, + pub package_id: Option, + pub created_at: DateTime, + pub code: u32, + pub level: NotificationLevel, + pub title: String, + pub message: String, + pub data: Value, } #[derive(Debug, Serialize, Deserialize)] diff --git a/core/startos/src/os_install/mod.rs b/core/startos/src/os_install/mod.rs index 3d80f6cbd..4cd8aac2d 100644 --- a/core/startos/src/os_install/mod.rs +++ b/core/startos/src/os_install/mod.rs @@ -21,7 +21,7 @@ use crate::disk::OsPartitionInfo; use crate::net::utils::find_eth_iface; use crate::prelude::*; use crate::s9pk::merkle_archive::source::multi_cursor_file::MultiCursorFile; -use crate::util::io::{open_file, TmpDir}; +use crate::util::io::{delete_file, open_file, TmpDir}; use crate::util::serde::IoFormat; use crate::util::Invoke; use crate::ARCH; @@ -31,17 +31,19 @@ mod mbr; pub fn install() -> ParentHandler { ParentHandler::new() - .subcommand("disk", disk::()) + .subcommand("disk", disk::().with_about("Command to list disk info")) .subcommand( "execute", from_fn_async(execute::) .no_display() + .with_about("Install StartOS over existing version") .with_call_remote::(), ) .subcommand( "reboot", from_fn_async(reboot) .no_display() + .with_about("Restart the server") .with_call_remote::(), ) } @@ -51,6 +53,7 @@ pub fn disk() -> ParentHandler { "list", from_fn_async(list) .no_display() + .with_about("List disk info") .with_call_remote::(), ) } @@ -147,23 +150,6 @@ pub async fn execute( overwrite |= disk.guid.is_none() && disk.partitions.iter().all(|p| p.guid.is_none()); - if !overwrite - && (disk - .guid - .as_ref() - .map_or(false, |g| g.starts_with("EMBASSY_")) - || disk - .partitions - .iter() - .flat_map(|p| p.guid.as_ref()) - .any(|g| g.starts_with("EMBASSY_"))) - { - return Err(Error::new( - eyre!("installing over versions before 0.3.6 is unsupported"), - ErrorKind::InvalidRequest, - )); - } - let part_info = partition(&mut disk, overwrite).await?; if let Some(efi) = &part_info.efi { @@ -194,18 +180,9 @@ pub async fn execute( { if let Err(e) = async { // cp -r ${guard}/config /tmp/config - if tokio::fs::metadata(guard.path().join("config/upgrade")) - .await - .is_ok() - { - tokio::fs::remove_file(guard.path().join("config/upgrade")).await?; - } - if tokio::fs::metadata(guard.path().join("config/disk.guid")) - .await - .is_ok() - { - tokio::fs::remove_file(guard.path().join("config/disk.guid")).await?; - } + delete_file(guard.path().join("config/upgrade")).await?; + delete_file(guard.path().join("config/overlay/etc/hostname")).await?; + delete_file(guard.path().join("config/disk.guid")).await?; Command::new("cp") .arg("-r") .arg(guard.path().join("config")) diff --git a/core/startos/src/properties.rs b/core/startos/src/properties.rs deleted file mode 100644 index e24b14965..000000000 --- a/core/startos/src/properties.rs +++ /dev/null @@ -1,35 +0,0 @@ -use clap::Parser; -use imbl_value::{json, Value}; -use models::PackageId; -use serde::{Deserialize, Serialize}; - -use crate::context::RpcContext; -use crate::prelude::*; -use crate::Error; - -pub fn display_properties(response: Value) { - println!("{}", response); -} - -#[derive(Deserialize, Serialize, Parser)] -#[serde(rename_all = "camelCase")] -#[command(rename_all = "kebab-case")] -pub struct PropertiesParam { - id: PackageId, -} -// #[command(display(display_properties))] -pub async fn properties( - ctx: RpcContext, - PropertiesParam { id }: PropertiesParam, -) -> Result { - match &*ctx.services.get(&id).await { - Some(service) => Ok(json!({ - "version": 2, - "data": service.properties().await? - })), - None => Err(Error::new( - eyre!("Could not find a service with id {id}"), - ErrorKind::NotFound, - )), - } -} diff --git a/core/startos/src/registry/admin.rs b/core/startos/src/registry/admin.rs index 8125580a4..f3cac9f7e 100644 --- a/core/startos/src/registry/admin.rs +++ b/core/startos/src/registry/admin.rs @@ -18,14 +18,23 @@ use crate::util::serde::{display_serializable, HandlerExtSerde, WithIoFormat}; pub fn admin_api() -> ParentHandler { ParentHandler::new() - .subcommand("signer", signers_api::()) + .subcommand( + "signer", + signers_api::().with_about("Commands to add or list signers"), + ) .subcommand("add", from_fn_async(add_admin).no_cli()) - .subcommand("add", from_fn_async(cli_add_admin).no_display()) + .subcommand( + "add", + from_fn_async(cli_add_admin) + .no_display() + .with_about("Add admin signer"), + ) .subcommand( "list", from_fn_async(list_admins) .with_display_serializable() .with_custom_display_fn(|handle, result| Ok(display_signers(handle.params, result))) + .with_about("List admin signers") .with_call_remote::(), ) } @@ -38,6 +47,7 @@ fn signers_api() -> ParentHandler { .with_metadata("admin", Value::Bool(true)) .with_display_serializable() .with_custom_display_fn(|handle, result| Ok(display_signers(handle.params, result))) + .with_about("List signers") .with_call_remote::(), ) .subcommand( @@ -46,7 +56,17 @@ fn signers_api() -> ParentHandler { .with_metadata("admin", Value::Bool(true)) .no_cli(), ) - .subcommand("add", from_fn_async(cli_add_signer)) + .subcommand( + "add", + from_fn_async(cli_add_signer).with_about("Add signer"), + ) + .subcommand( + "edit", + from_fn_async(edit_signer) + .with_metadata("admin", Value::Bool(true)) + .no_display() + .with_call_remote::(), + ) } impl Model> { @@ -130,6 +150,64 @@ pub async fn add_signer(ctx: RegistryContext, signer: SignerInfo) -> Result, + #[arg(short = 'c', long)] + pub add_contact: Vec, + #[arg(short = 'k', long)] + pub add_key: Vec, + #[arg(short = 'C', long)] + pub remove_contact: Vec, + #[arg(short = 'K', long)] + pub remove_key: Vec, +} + +pub async fn edit_signer( + ctx: RegistryContext, + EditSignerParams { + id, + set_name, + add_contact, + add_key, + remove_contact, + remove_key, + }: EditSignerParams, +) -> Result<(), Error> { + ctx.db + .mutate(|db| { + db.as_index_mut() + .as_signers_mut() + .as_idx_mut(&id) + .or_not_found(&id)? + .mutate(|s| { + if let Some(name) = set_name { + s.name = name; + } + s.contact.extend(add_contact); + for rm in remove_contact { + let Some((idx, _)) = s.contact.iter().enumerate().find(|(_, c)| *c == &rm) + else { + continue; + }; + s.contact.remove(idx); + } + + s.keys.extend(add_key); + for rm in remove_key { + s.keys.remove(&rm); + } + Ok(()) + }) + }) + .await +} + #[derive(Debug, Deserialize, Serialize, Parser)] #[command(rename_all = "kebab-case")] #[serde(rename_all = "camelCase")] diff --git a/core/startos/src/registry/context.rs b/core/startos/src/registry/context.rs index d3eaf3691..16c6465ed 100644 --- a/core/startos/src/registry/context.rs +++ b/core/startos/src/registry/context.rs @@ -255,7 +255,7 @@ impl CallRemote for RpcContext { .header(CONTENT_TYPE, "application/json") .header(ACCEPT, "application/json") .header(CONTENT_LENGTH, body.len()) - .header(DEVICE_INFO_HEADER, DeviceInfo::from(self).to_header_value()) + // .header(DEVICE_INFO_HEADER, DeviceInfo::from(self).to_header_value()) .body(body) .send() .await?; diff --git a/core/startos/src/registry/db.rs b/core/startos/src/registry/db.rs index df39604f1..8de9f8743 100644 --- a/core/startos/src/registry/db.rs +++ b/core/startos/src/registry/db.rs @@ -18,14 +18,24 @@ use crate::util::serde::{apply_expr, HandlerExtSerde}; pub fn db_api() -> ParentHandler { ParentHandler::new() - .subcommand("dump", from_fn_async(cli_dump).with_display_serializable()) + .subcommand( + "dump", + from_fn_async(cli_dump) + .with_display_serializable() + .with_about("Filter/query db to display tables and records"), + ) .subcommand( "dump", from_fn_async(dump) .with_metadata("admin", Value::Bool(true)) .no_cli(), ) - .subcommand("apply", from_fn_async(cli_apply).no_display()) + .subcommand( + "apply", + from_fn_async(cli_apply) + .no_display() + .with_about("Update a db record"), + ) .subcommand( "apply", from_fn_async(apply) diff --git a/core/startos/src/registry/device_info.rs b/core/startos/src/registry/device_info.rs index 172348a10..410e45f8f 100644 --- a/core/startos/src/registry/device_info.rs +++ b/core/startos/src/registry/device_info.rs @@ -15,6 +15,7 @@ use url::Url; use crate::context::RpcContext; use crate::prelude::*; use crate::registry::context::RegistryContext; +use crate::util::lshw::{LshwDevice, LshwDisplay, LshwProcessor}; use crate::util::VersionString; use crate::version::VersionT; @@ -26,12 +27,12 @@ pub struct DeviceInfo { pub os: OsInfo, pub hardware: HardwareInfo, } -impl From<&RpcContext> for DeviceInfo { - fn from(value: &RpcContext) -> Self { - Self { - os: OsInfo::from(value), - hardware: HardwareInfo::from(value), - } +impl DeviceInfo { + pub async fn load(ctx: &RpcContext) -> Result { + Ok(Self { + os: OsInfo::from(ctx), + hardware: HardwareInfo::load(ctx).await?, + }) } } impl DeviceInfo { @@ -44,11 +45,11 @@ impl DeviceInfo { .append_pair("hardware.arch", &*self.hardware.arch) .append_pair("hardware.ram", &self.hardware.ram.to_string()); - for (class, products) in &self.hardware.devices { - for product in products { - url.query_pairs_mut() - .append_pair(&format!("hardware.device.{}", class), product); - } + for device in &self.hardware.devices { + url.query_pairs_mut().append_pair( + &format!("hardware.device.{}", device.class()), + device.product(), + ); } HeaderValue::from_str(url.query().unwrap_or_default()).unwrap() @@ -80,16 +81,20 @@ impl DeviceInfo { devices: identity(query) .split_off("hardware.device.") .into_iter() - .filter_map(|(k, v)| { - k.strip_prefix("hardware.device.") - .map(|k| (k.into(), v.into_owned())) + .filter_map(|(k, v)| match k.strip_prefix("hardware.device.") { + Some("processor") => Some(LshwDevice::Processor(LshwProcessor { + product: v.into_owned(), + })), + Some("display") => Some(LshwDevice::Display(LshwDisplay { + product: v.into_owned(), + })), + Some(class) => { + tracing::warn!("unknown device class: {class}"); + None + } + _ => None, }) - .fold(BTreeMap::new(), |mut acc, (k, v)| { - let mut devs = acc.remove(&k).unwrap_or_default(); - devs.push(v); - acc.insert(k, devs); - acc - }), + .collect(), }, }) } @@ -108,8 +113,8 @@ pub struct OsInfo { impl From<&RpcContext> for OsInfo { fn from(_: &RpcContext) -> Self { Self { - version: crate::version::Current::new().semver(), - compat: crate::version::Current::new().compat().clone(), + version: crate::version::Current::default().semver(), + compat: crate::version::Current::default().compat().clone(), platform: InternedString::intern(&*crate::PLATFORM), } } @@ -122,26 +127,16 @@ pub struct HardwareInfo { pub arch: InternedString, #[ts(type = "number")] pub ram: u64, - #[ts(as = "BTreeMap::>")] - pub devices: BTreeMap>, + pub devices: Vec, } - -impl From<&RpcContext> for HardwareInfo { - fn from(value: &RpcContext) -> Self { - Self { - arch: InternedString::intern(crate::ARCH), - ram: value.hardware.ram, - devices: value - .hardware - .devices - .iter() - .fold(BTreeMap::new(), |mut acc, dev| { - let mut devs = acc.remove(dev.class()).unwrap_or_default(); - devs.push(dev.product().to_owned()); - acc.insert(dev.class().into(), devs); - acc - }), - } +impl HardwareInfo { + pub async fn load(ctx: &RpcContext) -> Result { + let s = ctx.db.peek().await.into_public().into_server_info(); + Ok(Self { + arch: s.as_arch().de()?, + ram: s.as_ram().de()?, + devices: s.as_devices().de()?, + }) } } diff --git a/core/startos/src/registry/info.rs b/core/startos/src/registry/info.rs new file mode 100644 index 000000000..402f0891a --- /dev/null +++ b/core/startos/src/registry/info.rs @@ -0,0 +1,126 @@ +use std::collections::BTreeMap; +use std::path::PathBuf; + +use clap::Parser; +use imbl_value::InternedString; +use itertools::Itertools; +use models::DataUrl; +use rpc_toolkit::{from_fn_async, Context, Empty, HandlerArgs, HandlerExt, ParentHandler}; +use serde::{Deserialize, Serialize}; +use ts_rs::TS; + +use crate::context::CliContext; +use crate::prelude::*; +use crate::registry::context::RegistryContext; +use crate::registry::package::index::Category; +use crate::util::serde::{HandlerExtSerde, WithIoFormat}; + +pub fn info_api() -> ParentHandler> { + ParentHandler::>::new() + .root_handler( + from_fn_async(get_info) + .with_display_serializable() + .with_about("Display registry name, icon, and package categories") + .with_call_remote::(), + ) + .subcommand( + "set-name", + from_fn_async(set_name) + .with_metadata("admin", Value::Bool(true)) + .no_display() + .with_about("Set the name for the registry") + .with_call_remote::(), + ) + .subcommand( + "set-icon", + from_fn_async(set_icon) + .with_metadata("admin", Value::Bool(true)) + .no_cli(), + ) + .subcommand( + "set-icon", + from_fn_async(cli_set_icon) + .no_display() + .with_about("Set the icon for the registry"), + ) +} + +#[derive(Debug, Default, Deserialize, Serialize, TS)] +#[serde(rename_all = "camelCase")] +#[ts(export)] +pub struct RegistryInfo { + pub name: Option, + pub icon: Option>, + #[ts(as = "BTreeMap::")] + pub categories: BTreeMap, +} + +pub async fn get_info(ctx: RegistryContext) -> Result { + let peek = ctx.db.peek().await.into_index(); + Ok(RegistryInfo { + name: peek.as_name().de()?, + icon: peek.as_icon().de()?, + categories: peek.as_package().as_categories().de()?, + }) +} + +#[derive(Debug, Deserialize, Serialize, Parser, TS)] +#[command(rename_all = "kebab-case")] +#[serde(rename_all = "camelCase")] +#[ts(export)] +pub struct SetNameParams { + pub name: String, +} + +pub async fn set_name( + ctx: RegistryContext, + SetNameParams { name }: SetNameParams, +) -> Result<(), Error> { + ctx.db + .mutate(|db| db.as_index_mut().as_name_mut().ser(&Some(name))) + .await +} + +#[derive(Debug, Deserialize, Serialize, TS)] +#[serde(rename_all = "camelCase")] +#[ts(export)] +pub struct SetIconParams { + pub icon: DataUrl<'static>, +} + +pub async fn set_icon( + ctx: RegistryContext, + SetIconParams { icon }: SetIconParams, +) -> Result<(), Error> { + ctx.db + .mutate(|db| db.as_index_mut().as_icon_mut().ser(&Some(icon))) + .await +} + +#[derive(Debug, Deserialize, Serialize, Parser, TS)] +#[command(rename_all = "kebab-case")] +#[serde(rename_all = "camelCase")] +#[ts(export)] +pub struct CliSetIconParams { + pub icon: PathBuf, +} + +pub async fn cli_set_icon( + HandlerArgs { + context: ctx, + parent_method, + method, + params: CliSetIconParams { icon }, + .. + }: HandlerArgs, +) -> Result<(), Error> { + let data_url = DataUrl::from_path(icon).await?; + ctx.call_remote::( + &parent_method.into_iter().chain(method).join("."), + imbl_value::json!({ + "icon": data_url, + }), + ) + .await?; + Ok(()) +} diff --git a/core/startos/src/registry/mod.rs b/core/startos/src/registry/mod.rs index d34ebb841..0cbbce4e0 100644 --- a/core/startos/src/registry/mod.rs +++ b/core/startos/src/registry/mod.rs @@ -28,6 +28,7 @@ pub mod auth; pub mod context; pub mod db; pub mod device_info; +pub mod info; pub mod os; pub mod package; pub mod signer; @@ -57,52 +58,42 @@ pub async fn get_full_index(ctx: RegistryContext) -> Result { ctx.db.peek().await.into_index().de() } -#[derive(Debug, Default, Deserialize, Serialize, TS)] -#[serde(rename_all = "camelCase")] -#[ts(export)] -pub struct RegistryInfo { - pub name: Option, - pub icon: Option>, - #[ts(as = "BTreeMap::")] - pub categories: BTreeMap, -} - -pub async fn get_info(ctx: RegistryContext) -> Result { - let peek = ctx.db.peek().await.into_index(); - Ok(RegistryInfo { - name: peek.as_name().de()?, - icon: peek.as_icon().de()?, - categories: peek.as_package().as_categories().de()?, - }) -} - pub fn registry_api() -> ParentHandler { ParentHandler::new() .subcommand( "index", from_fn_async(get_full_index) .with_display_serializable() + .with_about("List info including registry name and packages") .with_call_remote::(), ) + .subcommand("info", info::info_api::()) + // set info and categories + .subcommand( + "os", + os::os_api::().with_about("Commands related to OS assets and versions"), + ) .subcommand( - "info", - from_fn_async(get_info) - .with_display_serializable() - .with_call_remote::(), + "package", + package::package_api::().with_about("Commands to index, add, or get packages"), + ) + .subcommand( + "admin", + admin::admin_api::().with_about("Commands to add or list admins or signers"), + ) + .subcommand( + "db", + db::db_api::().with_about("Commands to interact with the db i.e. dump and apply"), ) - .subcommand("os", os::os_api::()) - .subcommand("package", package::package_api::()) - .subcommand("admin", admin::admin_api::()) - .subcommand("db", db::db_api::()) } pub fn registry_router(ctx: RegistryContext) -> Router { use axum::extract as x; - use axum::routing::{any, get, post}; + use axum::routing::{any, get}; Router::new() .route("/rpc/*path", { let ctx = ctx.clone(); - post( + any( Server::new(move || ready(Ok(ctx.clone())), registry_api()) .middleware(Cors::new()) .middleware(Auth::new()) diff --git a/core/startos/src/registry/os/asset/get.rs b/core/startos/src/registry/os/asset/get.rs index ad0010dca..a3da7047c 100644 --- a/core/startos/src/registry/os/asset/get.rs +++ b/core/startos/src/registry/os/asset/get.rs @@ -26,11 +26,26 @@ use crate::util::io::open_file; pub fn get_api() -> ParentHandler { ParentHandler::new() .subcommand("iso", from_fn_async(get_iso).no_cli()) - .subcommand("iso", from_fn_async(cli_get_os_asset).no_display()) + .subcommand( + "iso", + from_fn_async(cli_get_os_asset) + .no_display() + .with_about("Download iso"), + ) .subcommand("img", from_fn_async(get_img).no_cli()) - .subcommand("img", from_fn_async(cli_get_os_asset).no_display()) + .subcommand( + "img", + from_fn_async(cli_get_os_asset) + .no_display() + .with_about("Download img"), + ) .subcommand("squashfs", from_fn_async(get_squashfs).no_cli()) - .subcommand("squashfs", from_fn_async(cli_get_os_asset).no_display()) + .subcommand( + "squashfs", + from_fn_async(cli_get_os_asset) + .no_display() + .with_about("Download squashfs"), + ) } #[derive(Debug, Deserialize, Serialize, TS)] @@ -94,7 +109,11 @@ pub async fn get_squashfs( pub struct CliGetOsAssetParams { pub version: Version, pub platform: InternedString, - #[arg(long = "download", short = 'd')] + #[arg( + long = "download", + short = 'd', + help = "The path of the directory to download to" + )] pub download: Option, #[arg( long = "reverify", @@ -119,9 +138,15 @@ async fn cli_get_os_asset( .. }: HandlerArgs, ) -> Result, Error> { + let ext = method + .iter() + .last() + .or_else(|| parent_method.iter().last()) + .unwrap_or(&"bin"); + let res = from_value::>( ctx.call_remote::( - &parent_method.into_iter().chain(method).join("."), + &parent_method.iter().chain(&method).join("."), json!({ "version": version, "platform": platform, @@ -133,6 +158,7 @@ async fn cli_get_os_asset( res.validate(SIG_CONTEXT, res.all_signers())?; if let Some(download) = download { + let download = download.join(format!("startos-{version}_{platform}.{ext}")); let mut file = AtomicFile::new(&download, None::<&Path>) .await .with_kind(ErrorKind::Filesystem)?; diff --git a/core/startos/src/registry/os/asset/mod.rs b/core/startos/src/registry/os/asset/mod.rs index ec9d6cae7..52c12341a 100644 --- a/core/startos/src/registry/os/asset/mod.rs +++ b/core/startos/src/registry/os/asset/mod.rs @@ -7,8 +7,21 @@ pub mod sign; pub fn asset_api() -> ParentHandler { ParentHandler::new() .subcommand("add", add::add_api::()) - .subcommand("add", from_fn_async(add::cli_add_asset).no_display()) + .subcommand( + "add", + from_fn_async(add::cli_add_asset) + .no_display() + .with_about("Add asset to registry"), + ) .subcommand("sign", sign::sign_api::()) - .subcommand("sign", from_fn_async(sign::cli_sign_asset).no_display()) - .subcommand("get", get::get_api::()) + .subcommand( + "sign", + from_fn_async(sign::cli_sign_asset) + .no_display() + .with_about("Sign file and add to registry index"), + ) + .subcommand( + "get", + get::get_api::().with_about("Commands to download image, iso, or squashfs files"), + ) } diff --git a/core/startos/src/registry/os/mod.rs b/core/startos/src/registry/os/mod.rs index 64ce44eaf..a1d18cb03 100644 --- a/core/startos/src/registry/os/mod.rs +++ b/core/startos/src/registry/os/mod.rs @@ -15,8 +15,16 @@ pub fn os_api() -> ParentHandler { "index", from_fn_async(index::get_os_index) .with_display_serializable() + .with_about("List index of OS versions") .with_call_remote::(), ) - .subcommand("asset", asset::asset_api::()) - .subcommand("version", version::version_api::()) + .subcommand( + "asset", + asset::asset_api::().with_about("Commands to add, sign, or get registry assets"), + ) + .subcommand( + "version", + version::version_api::() + .with_about("Commands to add, remove, or list versions or version signers"), + ) } diff --git a/core/startos/src/registry/os/version/mod.rs b/core/startos/src/registry/os/version/mod.rs index 4c0568a80..8e4349ed9 100644 --- a/core/startos/src/registry/os/version/mod.rs +++ b/core/startos/src/registry/os/version/mod.rs @@ -26,6 +26,7 @@ pub fn version_api() -> ParentHandler { .with_metadata("admin", Value::Bool(true)) .with_metadata("get_signer", Value::Bool(true)) .no_display() + .with_about("Add OS version") .with_call_remote::(), ) .subcommand( @@ -33,9 +34,13 @@ pub fn version_api() -> ParentHandler { from_fn_async(remove_version) .with_metadata("admin", Value::Bool(true)) .no_display() + .with_about("Remove OS version") .with_call_remote::(), ) - .subcommand("signer", signer::signer_api::()) + .subcommand( + "signer", + signer::signer_api::().with_about("Add, remove, and list version signers"), + ) .subcommand( "get", from_fn_async(get_version) @@ -43,6 +48,7 @@ pub fn version_api() -> ParentHandler { .with_custom_display_fn(|handle, result| { Ok(display_version_info(handle.params, result)) }) + .with_about("Get OS versions and related version info") .with_call_remote::(), ) } diff --git a/core/startos/src/registry/os/version/signer.rs b/core/startos/src/registry/os/version/signer.rs index 51f7c6719..c72bb5ef4 100644 --- a/core/startos/src/registry/os/version/signer.rs +++ b/core/startos/src/registry/os/version/signer.rs @@ -21,6 +21,7 @@ pub fn signer_api() -> ParentHandler { from_fn_async(add_version_signer) .with_metadata("admin", Value::Bool(true)) .no_display() + .with_about("Add version signer") .with_call_remote::(), ) .subcommand( @@ -28,6 +29,7 @@ pub fn signer_api() -> ParentHandler { from_fn_async(remove_version_signer) .with_metadata("admin", Value::Bool(true)) .no_display() + .with_about("Remove version signer") .with_call_remote::(), ) .subcommand( @@ -35,6 +37,7 @@ pub fn signer_api() -> ParentHandler { from_fn_async(list_version_signers) .with_display_serializable() .with_custom_display_fn(|handle, result| Ok(display_signers(handle.params, result))) + .with_about("List version signers and related signer info") .with_call_remote::(), ) } diff --git a/core/startos/src/registry/package/category.rs b/core/startos/src/registry/package/category.rs new file mode 100644 index 000000000..97b0fb227 --- /dev/null +++ b/core/startos/src/registry/package/category.rs @@ -0,0 +1,147 @@ +use std::collections::BTreeMap; + +use clap::Parser; +use imbl_value::InternedString; +use rpc_toolkit::{from_fn_async, Context, HandlerExt, ParentHandler}; +use serde::{Deserialize, Serialize}; +use ts_rs::TS; + +use crate::context::CliContext; +use crate::prelude::*; +use crate::registry::context::RegistryContext; +use crate::registry::package::index::Category; +use crate::s9pk::manifest::Description; +use crate::util::serde::{display_serializable, HandlerExtSerde, WithIoFormat}; + +pub fn category_api() -> ParentHandler { + ParentHandler::new() + .subcommand( + "add", + from_fn_async(add_category) + .with_metadata("admin", Value::Bool(true)) + .no_display() + .with_about("Add a category to the registry") + .with_call_remote::(), + ) + .subcommand( + "remove", + from_fn_async(remove_category) + .with_metadata("admin", Value::Bool(true)) + .no_display() + .with_about("Remove a category from the registry") + .with_call_remote::(), + ) + .subcommand( + "list", + from_fn_async(list_categories) + .with_display_serializable() + .with_custom_display_fn(|params, categories| { + Ok(display_categories(params.params, categories)) + }) + .with_call_remote::(), + ) +} + +#[derive(Debug, Deserialize, Serialize, Parser, TS)] +#[command(rename_all = "kebab-case")] +#[serde(rename_all = "camelCase")] +#[ts(export)] +pub struct AddCategoryParams { + #[ts(type = "string")] + pub id: InternedString, + pub name: String, + #[arg(short, long, help = "Short description for the category")] + pub short: String, + #[arg(short, long, help = "Long description for the category")] + pub long: String, +} + +pub async fn add_category( + ctx: RegistryContext, + AddCategoryParams { + id, + name, + short, + long, + }: AddCategoryParams, +) -> Result<(), Error> { + ctx.db + .mutate(|db| { + db.as_index_mut() + .as_package_mut() + .as_categories_mut() + .insert( + &id, + &Category { + name, + description: Description { short, long }, + }, + ) + }) + .await?; + Ok(()) +} + +#[derive(Debug, Deserialize, Serialize, Parser, TS)] +#[command(rename_all = "kebab-case")] +#[serde(rename_all = "camelCase")] +#[ts(export)] +pub struct RemoveCategoryParams { + #[ts(type = "string")] + pub id: InternedString, +} + +pub async fn remove_category( + ctx: RegistryContext, + RemoveCategoryParams { id }: RemoveCategoryParams, +) -> Result<(), Error> { + ctx.db + .mutate(|db| { + db.as_index_mut() + .as_package_mut() + .as_categories_mut() + .remove(&id) + }) + .await?; + Ok(()) +} + +pub async fn list_categories( + ctx: RegistryContext, +) -> Result, Error> { + ctx.db + .peek() + .await + .into_index() + .into_package() + .into_categories() + .de() +} + +pub fn display_categories( + params: WithIoFormat, + categories: BTreeMap, +) { + use prettytable::*; + + if let Some(format) = params.format { + return display_serializable(format, categories); + } + + let mut table = Table::new(); + table.add_row(row![bc => + "ID", + "NAME", + "SHORT DESCRIPTION", + "LONG DESCRIPTION", + ]); + for (id, info) in categories { + table.add_row(row![ + &*id, + &info.name, + &info.description.short, + &info.description.long, + ]); + } + table.print_tty(false).unwrap(); +} diff --git a/core/startos/src/registry/package/index.rs b/core/startos/src/registry/package/index.rs index 12a17f634..428200165 100644 --- a/core/startos/src/registry/package/index.rs +++ b/core/startos/src/registry/package/index.rs @@ -180,14 +180,13 @@ impl Model { return Ok(false); } } - for (class, regex) in hw.device { + for device_filter in hw.device { if !device_info .hardware .devices - .get(&*class) - .unwrap_or(&Vec::new()) .iter() - .any(|product| regex.as_ref().is_match(product)) + .filter(|d| d.class() == &*device_filter.class) + .any(|d| device_filter.pattern.as_ref().is_match(d.product())) { return Ok(false); } diff --git a/core/startos/src/registry/package/mod.rs b/core/startos/src/registry/package/mod.rs index cb2d317f9..74d244deb 100644 --- a/core/startos/src/registry/package/mod.rs +++ b/core/startos/src/registry/package/mod.rs @@ -5,8 +5,10 @@ use crate::prelude::*; use crate::util::serde::HandlerExtSerde; pub mod add; +pub mod category; pub mod get; pub mod index; +pub mod signer; pub fn package_api() -> ParentHandler { ParentHandler::new() @@ -14,6 +16,7 @@ pub fn package_api() -> ParentHandler { "index", from_fn_async(index::get_package_index) .with_display_serializable() + .with_about("List packages and categories") .with_call_remote::(), ) .subcommand( @@ -22,7 +25,16 @@ pub fn package_api() -> ParentHandler { .with_metadata("get_signer", Value::Bool(true)) .no_cli(), ) - .subcommand("add", from_fn_async(add::cli_add_package).no_display()) + .subcommand( + "add", + from_fn_async(add::cli_add_package) + .no_display() + .with_about("Add package to registry index"), + ) + .subcommand( + "signer", + signer::signer_api::().with_about("Add, remove, and list package signers"), + ) .subcommand( "get", from_fn_async(get::get_package) @@ -31,6 +43,12 @@ pub fn package_api() -> ParentHandler { .with_custom_display_fn(|handle, result| { get::display_package_info(handle.params, result) }) + .with_about("List installation candidate package(s)") .with_call_remote::(), ) + .subcommand( + "category", + category::category_api::() + .with_about("Update the categories for packages on the registry"), + ) } diff --git a/core/startos/src/registry/package/signer.rs b/core/startos/src/registry/package/signer.rs new file mode 100644 index 000000000..56bfc9b1c --- /dev/null +++ b/core/startos/src/registry/package/signer.rs @@ -0,0 +1,133 @@ +use std::collections::BTreeMap; + +use clap::Parser; +use models::PackageId; +use rpc_toolkit::{from_fn_async, Context, HandlerExt, ParentHandler}; +use serde::{Deserialize, Serialize}; +use ts_rs::TS; + +use crate::context::CliContext; +use crate::prelude::*; +use crate::registry::admin::display_signers; +use crate::registry::context::RegistryContext; +use crate::registry::signer::SignerInfo; +use crate::rpc_continuations::Guid; +use crate::util::serde::HandlerExtSerde; + +pub fn signer_api() -> ParentHandler { + ParentHandler::new() + .subcommand( + "add", + from_fn_async(add_package_signer) + .with_metadata("admin", Value::Bool(true)) + .no_display() + .with_about("Add package signer") + .with_call_remote::(), + ) + .subcommand( + "remove", + from_fn_async(remove_package_signer) + .with_metadata("admin", Value::Bool(true)) + .no_display() + .with_about("Remove package signer") + .with_call_remote::(), + ) + .subcommand( + "list", + from_fn_async(list_package_signers) + .with_display_serializable() + .with_custom_display_fn(|handle, result| Ok(display_signers(handle.params, result))) + .with_about("List package signers and related signer info") + .with_call_remote::(), + ) +} + +#[derive(Debug, Deserialize, Serialize, Parser, TS)] +#[command(rename_all = "kebab-case")] +#[serde(rename_all = "camelCase")] +#[ts(export)] +pub struct PackageSignerParams { + pub id: PackageId, + pub signer: Guid, +} + +pub async fn add_package_signer( + ctx: RegistryContext, + PackageSignerParams { id, signer }: PackageSignerParams, +) -> Result<(), Error> { + ctx.db + .mutate(|db| { + ensure_code!( + db.as_index().as_signers().contains_key(&signer)?, + ErrorKind::InvalidRequest, + "unknown signer {signer}" + ); + + db.as_index_mut() + .as_package_mut() + .as_packages_mut() + .as_idx_mut(&id) + .or_not_found(&id)? + .as_authorized_mut() + .mutate(|s| Ok(s.insert(signer)))?; + + Ok(()) + }) + .await +} + +pub async fn remove_package_signer( + ctx: RegistryContext, + PackageSignerParams { id, signer }: PackageSignerParams, +) -> Result<(), Error> { + ctx.db + .mutate(|db| { + if !db + .as_index_mut() + .as_package_mut() + .as_packages_mut() + .as_idx_mut(&id) + .or_not_found(&id)? + .as_authorized_mut() + .mutate(|s| Ok(s.remove(&signer)))? + { + return Err(Error::new( + eyre!("signer {signer} is not authorized to sign for {id}"), + ErrorKind::NotFound, + )); + } + + Ok(()) + }) + .await +} + +#[derive(Debug, Deserialize, Serialize, Parser, TS)] +#[command(rename_all = "kebab-case")] +#[serde(rename_all = "camelCase")] +#[ts(export)] +pub struct ListPackageSignersParams { + pub id: PackageId, +} + +pub async fn list_package_signers( + ctx: RegistryContext, + ListPackageSignersParams { id }: ListPackageSignersParams, +) -> Result, Error> { + let db = ctx.db.peek().await; + db.as_index() + .as_package() + .as_packages() + .as_idx(&id) + .or_not_found(&id)? + .as_authorized() + .de()? + .into_iter() + .filter_map(|guid| { + db.as_index() + .as_signers() + .as_idx(&guid) + .map(|s| s.de().map(|s| (guid, s))) + }) + .collect() +} diff --git a/core/startos/src/registry/signer/mod.rs b/core/startos/src/registry/signer/mod.rs index 99b23b88e..137c40f0f 100644 --- a/core/startos/src/registry/signer/mod.rs +++ b/core/startos/src/registry/signer/mod.rs @@ -3,6 +3,7 @@ use std::str::FromStr; use clap::builder::ValueParserFactory; use itertools::Itertools; +use models::FromStrParser; use serde::{Deserialize, Serialize}; use ts_rs::TS; use url::Url; @@ -10,7 +11,6 @@ use url::Url; use crate::prelude::*; use crate::registry::signer::commitment::Digestable; use crate::registry::signer::sign::{AnySignature, AnyVerifyingKey, SignatureScheme}; -use crate::util::clap::FromStrParser; pub mod commitment; pub mod sign; @@ -25,7 +25,7 @@ pub struct SignerInfo { pub keys: HashSet, } -#[derive(Clone, Debug, Deserialize, Serialize, TS)] +#[derive(Clone, Debug, Deserialize, Serialize, TS, PartialEq, Eq)] #[serde(rename_all = "camelCase")] #[ts(export)] // TODO: better types diff --git a/core/startos/src/registry/signer/sign/mod.rs b/core/startos/src/registry/signer/sign/mod.rs index a29109864..6a95a2490 100644 --- a/core/startos/src/registry/signer/sign/mod.rs +++ b/core/startos/src/registry/signer/sign/mod.rs @@ -4,6 +4,7 @@ use std::str::FromStr; use ::ed25519::pkcs8::BitStringRef; use clap::builder::ValueParserFactory; use der::referenced::OwnedToRef; +use models::FromStrParser; use pkcs8::der::AnyRef; use pkcs8::{PrivateKeyInfo, SubjectPublicKeyInfo}; use serde::{Deserialize, Serialize}; @@ -13,7 +14,6 @@ use ts_rs::TS; use crate::prelude::*; use crate::registry::signer::commitment::Digestable; use crate::registry::signer::sign::ed25519::Ed25519; -use crate::util::clap::FromStrParser; use crate::util::serde::{deserialize_from_str, serialize_display}; pub mod ed25519; diff --git a/core/startos/src/rpc_continuations.rs b/core/startos/src/rpc_continuations.rs index 043130b69..4614f8fa6 100644 --- a/core/startos/src/rpc_continuations.rs +++ b/core/startos/src/rpc_continuations.rs @@ -13,12 +13,12 @@ use futures::future::BoxFuture; use futures::{Future, FutureExt}; use helpers::TimedResource; use imbl_value::InternedString; +use models::FromStrParser; use tokio::sync::{broadcast, Mutex as AsyncMutex}; use ts_rs::TS; #[allow(unused_imports)] use crate::prelude::*; -use crate::util::clap::FromStrParser; use crate::util::new_guid; #[derive( diff --git a/core/startos/src/s9pk/rpc.rs b/core/startos/src/s9pk/rpc.rs index 92f952077..98b46ac77 100644 --- a/core/startos/src/s9pk/rpc.rs +++ b/core/startos/src/s9pk/rpc.rs @@ -21,11 +21,16 @@ pub const SKIP_ENV: &[&str] = &["TERM", "container", "HOME", "HOSTNAME"]; pub fn s9pk() -> ParentHandler { ParentHandler::new() - .subcommand("pack", from_fn_async(super::v2::pack::pack).no_display()) + .subcommand( + "pack", + from_fn_async(super::v2::pack::pack) + .no_display() + .with_about("Package s9pk input files into valid s9pk"), + ) .subcommand( "list-ingredients", - from_fn_async(super::v2::pack::list_ingredients).with_custom_display_fn( - |_, ingredients| { + from_fn_async(super::v2::pack::list_ingredients) + .with_custom_display_fn(|_, ingredients| { ingredients .into_iter() .map(Some) @@ -39,12 +44,23 @@ pub fn s9pk() -> ParentHandler { }); println!(); Ok(()) - }, - ), + }) + .with_about("List paths of package ingredients"), + ) + .subcommand( + "edit", + edit().with_about("Commands to add an image to an s9pk or edit the manifest"), + ) + .subcommand( + "inspect", + inspect().with_about("Commands to display file paths, file contents, or manifest"), + ) + .subcommand( + "convert", + from_fn_async(convert) + .no_display() + .with_about("Convert s9pk from v1 to v2"), ) - .subcommand("edit", edit()) - .subcommand("inspect", inspect()) - .subcommand("convert", from_fn_async(convert).no_display()) } #[derive(Deserialize, Serialize, Parser)] @@ -59,13 +75,15 @@ fn edit() -> ParentHandler { "add-image", from_fn_async(add_image) .with_inherited(only_parent) - .no_display(), + .no_display() + .with_about("Add image to s9pk"), ) .subcommand( "manifest", from_fn_async(edit_manifest) .with_inherited(only_parent) - .with_display_serializable(), + .with_display_serializable() + .with_about("Edit s9pk manifest"), ) } @@ -76,17 +94,22 @@ fn inspect() -> ParentHandler { "file-tree", from_fn_async(file_tree) .with_inherited(only_parent) - .with_display_serializable(), + .with_display_serializable() + .with_about("Display list of paths"), ) .subcommand( "cat", - from_fn_async(cat).with_inherited(only_parent).no_display(), + from_fn_async(cat) + .with_inherited(only_parent) + .no_display() + .with_about("Display file contents"), ) .subcommand( "manifest", from_fn_async(inspect_manifest) .with_inherited(only_parent) - .with_display_serializable(), + .with_display_serializable() + .with_about("Display s9pk manifest"), ) } diff --git a/core/startos/src/s9pk/v1/manifest.rs b/core/startos/src/s9pk/v1/manifest.rs index 9b3eb9895..31821ad68 100644 --- a/core/startos/src/s9pk/v1/manifest.rs +++ b/core/startos/src/s9pk/v1/manifest.rs @@ -1,7 +1,8 @@ -use std::collections::BTreeMap; +use std::collections::{BTreeMap, BTreeSet}; use std::path::{Path, PathBuf}; use exver::{Version, VersionRange}; +use imbl_value::InternedString; use indexmap::IndexMap; pub use models::PackageId; use models::{ActionId, HealthCheckId, ImageId, VolumeId}; @@ -10,8 +11,8 @@ use url::Url; use crate::prelude::*; use crate::s9pk::git_hash::GitHash; -use crate::s9pk::manifest::{Alerts, Description, HardwareRequirements}; -use crate::util::serde::{Duration, IoFormat}; +use crate::s9pk::manifest::{Alerts, Description}; +use crate::util::serde::{Duration, IoFormat, Regex}; #[derive(Clone, Debug, Deserialize, Serialize)] #[serde(rename_all = "kebab-case")] @@ -192,6 +193,15 @@ impl DependencyRequirement { } } +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct HardwareRequirements { + #[serde(default)] + pub device: BTreeMap, + pub ram: Option, + pub arch: Option>, +} + #[derive(Clone, Debug, Default, Deserialize, Serialize)] #[serde(rename_all = "kebab-case")] pub struct Assets { diff --git a/core/startos/src/s9pk/v2/compat.rs b/core/startos/src/s9pk/v2/compat.rs index 8e62c69d0..db8cbc414 100644 --- a/core/startos/src/s9pk/v2/compat.rs +++ b/core/startos/src/s9pk/v2/compat.rs @@ -10,7 +10,7 @@ use tokio::process::Command; use crate::dependencies::{DepInfo, Dependencies}; use crate::prelude::*; -use crate::s9pk::manifest::Manifest; +use crate::s9pk::manifest::{DeviceFilter, Manifest}; use crate::s9pk::merkle_archive::directory_contents::DirectoryContents; use crate::s9pk::merkle_archive::source::TmpSource; use crate::s9pk::merkle_archive::{Entry, MerkleArchive}; @@ -246,10 +246,25 @@ impl TryFrom for Manifest { }) .collect(), ), - hardware_requirements: value.hardware_requirements, + hardware_requirements: super::manifest::HardwareRequirements { + arch: value.hardware_requirements.arch, + ram: value.hardware_requirements.ram, + device: value + .hardware_requirements + .device + .into_iter() + .map(|(class, product)| DeviceFilter { + pattern_description: format!( + "a {class} device matching the expression {}", + product.as_ref() + ), + class, + pattern: product, + }) + .collect(), + }, git_hash: value.git_hash, os_version: value.eos_version, - has_config: value.config.is_some(), }) } } diff --git a/core/startos/src/s9pk/v2/manifest.rs b/core/startos/src/s9pk/v2/manifest.rs index 1f24a0b73..85f3cd796 100644 --- a/core/startos/src/s9pk/v2/manifest.rs +++ b/core/startos/src/s9pk/v2/manifest.rs @@ -22,7 +22,7 @@ use crate::util::VersionString; use crate::version::{Current, VersionT}; fn current_version() -> Version { - Current::new().semver() + Current::default().semver() } #[derive(Clone, Debug, Deserialize, Serialize, HasModel, TS)] @@ -68,8 +68,6 @@ pub struct Manifest { #[serde(default = "current_version")] #[ts(type = "string")] pub os_version: Version, - #[serde(default = "const_true")] - pub has_config: bool, } impl Manifest { pub fn validate_for<'a, T: Clone>( @@ -163,14 +161,24 @@ impl Manifest { #[ts(export)] pub struct HardwareRequirements { #[serde(default)] - #[ts(type = "{ display?: string, processor?: string }")] - pub device: BTreeMap, // TODO: array + pub device: Vec, #[ts(type = "number | null")] pub ram: Option, #[ts(type = "string[] | null")] pub arch: Option>, } +#[derive(Clone, Debug, Deserialize, Serialize, TS)] +#[serde(rename_all = "camelCase")] +#[ts(export)] +pub struct DeviceFilter { + #[ts(type = "\"processor\" | \"display\"")] + pub class: InternedString, + #[ts(type = "string")] + pub pattern: Regex, + pub pattern_description: String, +} + #[derive(Clone, Debug, Deserialize, Serialize, TS)] #[ts(export)] pub struct Description { diff --git a/core/startos/src/s9pk/v2/mod.rs b/core/startos/src/s9pk/v2/mod.rs index e012480af..7a94c0d79 100644 --- a/core/startos/src/s9pk/v2/mod.rs +++ b/core/startos/src/s9pk/v2/mod.rs @@ -102,6 +102,19 @@ impl S9pk { }) } + pub fn new_with_manifest( + archive: MerkleArchive, + size: Option, + manifest: Manifest, + ) -> Self { + Self { + manifest, + manifest_dirty: true, + archive, + size, + } + } + pub fn validate_and_filter(&mut self, arch: Option<&str>) -> Result<(), Error> { let filter = self.manifest.validate_for(arch, self.archive.contents())?; filter.keep_checked(self.archive.contents_mut()) @@ -263,10 +276,10 @@ impl> + FileSource + Clone> S9pk { impl S9pk> { #[instrument(skip_all)] - pub async fn deserialize( + pub async fn archive( source: &S, commitment: Option<&MerkleArchiveCommitment>, - ) -> Result { + ) -> Result>, Error> { use tokio::io::AsyncReadExt; let mut header = source @@ -283,9 +296,14 @@ impl S9pk> { ErrorKind::ParseS9pk, "Invalid Magic or Unexpected Version" ); - - let mut archive = - MerkleArchive::deserialize(source, SIG_CONTEXT, &mut header, commitment).await?; + MerkleArchive::deserialize(source, SIG_CONTEXT, &mut header, commitment).await + } + #[instrument(skip_all)] + pub async fn deserialize( + source: &S, + commitment: Option<&MerkleArchiveCommitment>, + ) -> Result { + let mut archive = Self::archive(source, commitment).await?; archive.sort_by(|a, b| match (priority(a), priority(b)) { (Some(a), Some(b)) => a.cmp(&b), diff --git a/core/startos/src/s9pk/v2/pack.rs b/core/startos/src/s9pk/v2/pack.rs index aa0fd39f2..be81d9e78 100644 --- a/core/startos/src/s9pk/v2/pack.rs +++ b/core/startos/src/s9pk/v2/pack.rs @@ -1,4 +1,4 @@ -use std::collections::BTreeSet; +use std::collections::{BTreeMap, BTreeSet}; use std::path::{Path, PathBuf}; use std::sync::Arc; @@ -61,8 +61,7 @@ impl SqfsDir { let guid = Guid::new(); let path = self.tmpdir.join(guid.as_ref()).with_extension("squashfs"); if self.path.extension().and_then(|s| s.to_str()) == Some("tar") { - Command::new("tar2sqfs") - .arg(&path) + tar2sqfs(&self.path)? .input(Some(&mut open_file(&self.path).await?)) .invoke(ErrorKind::Filesystem) .await?; @@ -70,6 +69,7 @@ impl SqfsDir { Command::new("mksquashfs") .arg(&self.path) .arg(&path) + .arg("-quiet") .invoke(ErrorKind::Filesystem) .await?; } @@ -294,6 +294,7 @@ impl TryFrom for ImageConfig { ImageSource::DockerBuild { dockerfile: value.dockerfile, workdir: value.workdir, + build_args: None, } } else if let Some(tag) = value.docker_tag { ImageSource::DockerTag(tag) @@ -337,6 +338,15 @@ impl clap::FromArgMatches for ImageConfig { } } +#[derive(Debug, Clone, Deserialize, Serialize, TS)] +#[serde(rename_all = "camelCase")] +#[serde(untagged)] +#[ts(export)] +pub enum BuildArg { + String(String), + EnvVar { env: String }, +} + #[derive(Debug, Clone, Deserialize, Serialize, TS)] #[serde(rename_all = "camelCase")] #[ts(export)] @@ -344,8 +354,13 @@ pub enum ImageSource { Packed, #[serde(rename_all = "camelCase")] DockerBuild { + #[ts(optional)] workdir: Option, + #[ts(optional)] dockerfile: Option, + #[serde(skip_serializing_if = "Option::is_none")] + #[ts(optional)] + build_args: Option>, }, DockerTag(String), } @@ -353,8 +368,15 @@ impl ImageSource { pub fn ingredients(&self) -> Vec { match self { Self::Packed => Vec::new(), - Self::DockerBuild { dockerfile, .. } => { - vec![dockerfile.clone().unwrap_or_else(|| "Dockerfile".into())] + Self::DockerBuild { + dockerfile, + workdir, + .. + } => { + vec![workdir + .as_deref() + .unwrap_or(Path::new(".")) + .join(dockerfile.as_deref().unwrap_or(Path::new("Dockerfile")))] } Self::DockerTag(_) => Vec::new(), } @@ -384,6 +406,7 @@ impl ImageSource { ImageSource::DockerBuild { workdir, dockerfile, + build_args, } => { let workdir = workdir.as_deref().unwrap_or(Path::new(".")); let dockerfile = dockerfile @@ -398,7 +421,8 @@ impl ImageSource { }; // docker buildx build ${path} -o type=image,name=start9/${id} let tag = format!("start9/{id}/{image_id}:{}", new_guid()); - Command::new(CONTAINER_TOOL) + let mut command = Command::new(CONTAINER_TOOL); + command .arg("build") .arg(workdir) .arg("-f") @@ -406,6 +430,29 @@ impl ImageSource { .arg("-t") .arg(&tag) .arg(&docker_platform) + .arg("--build-arg") + .arg(format!("ARCH={}", arch)); + + // add build arguments + if let Some(build_args) = build_args { + for (key, value) in build_args { + let build_arg_value = match value { + BuildArg::String(val) => val.to_string(), + BuildArg::EnvVar { env } => { + match std::env::var(&env) { + Ok(val) => val, + Err(_) => continue, // skip if env var not set or invalid + } + } + }; + + command + .arg("--build-arg") + .arg(format!("{}={}", key, build_arg_value)); + } + } + + command .arg("-o") .arg("type=docker,dest=-") .capture(false) @@ -513,7 +560,7 @@ impl ImageSource { Command::new(CONTAINER_TOOL) .arg("export") .arg(container.trim()) - .pipe(Command::new("tar2sqfs").arg(&dest)) + .pipe(&mut tar2sqfs(&dest)?) .capture(false) .invoke(ErrorKind::Docker) .await?; @@ -535,6 +582,38 @@ impl ImageSource { } } +fn tar2sqfs(dest: impl AsRef) -> Result { + let dest = dest.as_ref(); + + Ok({ + #[cfg(target_os = "linux")] + { + let mut command = Command::new("tar2sqfs"); + command.arg("-q").arg(&dest); + command + } + #[cfg(target_os = "macos")] + { + let directory = dest + .parent() + .unwrap_or_else(|| Path::new("/")) + .to_path_buf(); + let mut command = Command::new(CONTAINER_TOOL); + command + .arg("run") + .arg("-i") + .arg("--rm") + .arg("-v") + .arg(format!("{}:/data:rw", directory.display())) + .arg("ghcr.io/start9labs/sdk/utils:latest") + .arg("tar2sqfs") + .arg("-q") + .arg(Path::new("/data").join(&dest.file_name().unwrap_or_default())); + command + } + }) +} + #[derive(Debug, Clone, Deserialize, Serialize, TS)] #[serde(rename_all = "camelCase")] #[ts(export)] diff --git a/core/startos/src/service/action.rs b/core/startos/src/service/action.rs index 6c5ac4eab..4068d5ad8 100644 --- a/core/startos/src/service/action.rs +++ b/core/startos/src/service/action.rs @@ -1,42 +1,38 @@ +use std::collections::BTreeMap; use std::time::Duration; -use models::{ActionId, ProcedureName}; +use imbl_value::json; +use models::{ActionId, PackageId, ProcedureName, ReplayId}; -use crate::action::ActionResult; +use crate::action::{ActionInput, ActionResult}; +use crate::db::model::package::{ActionRequestCondition, ActionRequestEntry, ActionRequestInput}; use crate::prelude::*; use crate::rpc_continuations::Guid; -use crate::service::config::GetConfig; -use crate::service::dependencies::DependencyConfig; use crate::service::{Service, ServiceActor}; use crate::util::actor::background::BackgroundJobQueue; use crate::util::actor::{ConflictBuilder, Handler}; +use crate::util::serde::is_partial_of; -pub(super) struct Action { +pub(super) struct GetActionInput { id: ActionId, - input: Value, } -impl Handler for ServiceActor { - type Response = Result; - fn conflicts_with(_: &Action) -> ConflictBuilder { - ConflictBuilder::everything() - .except::() - .except::() +impl Handler for ServiceActor { + type Response = Result, Error>; + fn conflicts_with(_: &GetActionInput) -> ConflictBuilder { + ConflictBuilder::nothing() } async fn handle( &mut self, id: Guid, - Action { - id: action_id, - input, - }: Action, + GetActionInput { id: action_id }: GetActionInput, _: &BackgroundJobQueue, ) -> Self::Response { let container = &self.0.persistent_container; container - .execute::( + .execute::>( id, - ProcedureName::RunAction(action_id), - input, + ProcedureName::GetActionInput(action_id), + Value::Null, Some(Duration::from_secs(30)), ) .await @@ -45,16 +41,139 @@ impl Handler for ServiceActor { } impl Service { - pub async fn action( + pub async fn get_action_input( + &self, + id: Guid, + action_id: ActionId, + ) -> Result, Error> { + if !self + .seed + .ctx + .db + .peek() + .await + .as_public() + .as_package_data() + .as_idx(&self.seed.id) + .or_not_found(&self.seed.id)? + .as_actions() + .as_idx(&action_id) + .or_not_found(&action_id)? + .as_has_input() + .de()? + { + return Ok(None); + } + self.actor + .send(id, GetActionInput { id: action_id }) + .await? + } +} + +pub fn update_requested_actions( + requested_actions: &mut BTreeMap, + package_id: &PackageId, + action_id: &ActionId, + input: &Value, + was_run: bool, +) { + requested_actions.retain(|_, v| { + if &v.request.package_id != package_id || &v.request.action_id != action_id { + return true; + } + if let Some(when) = &v.request.when { + match &when.condition { + ActionRequestCondition::InputNotMatches => match &v.request.input { + Some(ActionRequestInput::Partial { value }) => { + if is_partial_of(value, input) { + if when.once { + return !was_run; + } else { + v.active = false; + } + } else { + v.active = true; + } + } + None => { + tracing::error!( + "action request exists in an invalid state {:?}", + v.request + ); + } + }, + } + true + } else { + !was_run + } + }) +} + +pub(super) struct RunAction { + id: ActionId, + input: Value, +} +impl Handler for ServiceActor { + type Response = Result, Error>; + fn conflicts_with(_: &RunAction) -> ConflictBuilder { + ConflictBuilder::everything().except::() + } + async fn handle( + &mut self, + id: Guid, + RunAction { + id: action_id, + input, + }: RunAction, + _: &BackgroundJobQueue, + ) -> Self::Response { + let container = &self.0.persistent_container; + let result = container + .execute::>( + id, + ProcedureName::RunAction(action_id.clone()), + json!({ + "input": input, + }), + Some(Duration::from_secs(30)), + ) + .await + .with_kind(ErrorKind::Action)?; + let package_id = &self.0.id; + self.0 + .ctx + .db + .mutate(|db| { + for (_, pde) in db.as_public_mut().as_package_data_mut().as_entries_mut()? { + pde.as_requested_actions_mut().mutate(|requested_actions| { + Ok(update_requested_actions( + requested_actions, + package_id, + &action_id, + &input, + true, + )) + })?; + } + Ok(()) + }) + .await?; + Ok(result) + } +} + +impl Service { + pub async fn run_action( &self, id: Guid, action_id: ActionId, input: Value, - ) -> Result { + ) -> Result, Error> { self.actor .send( id, - Action { + RunAction { id: action_id, input, }, diff --git a/core/startos/src/service/config.rs b/core/startos/src/service/config.rs deleted file mode 100644 index faa70fc41..000000000 --- a/core/startos/src/service/config.rs +++ /dev/null @@ -1,78 +0,0 @@ -use std::time::Duration; - -use models::ProcedureName; - -use crate::config::action::ConfigRes; -use crate::config::ConfigureContext; -use crate::prelude::*; -use crate::rpc_continuations::Guid; -use crate::service::dependencies::DependencyConfig; -use crate::service::{Service, ServiceActor}; -use crate::util::actor::background::BackgroundJobQueue; -use crate::util::actor::{ConflictBuilder, Handler}; -use crate::util::serde::NoOutput; - -pub(super) struct Configure(ConfigureContext); -impl Handler for ServiceActor { - type Response = Result<(), Error>; - fn conflicts_with(_: &Configure) -> ConflictBuilder { - ConflictBuilder::everything().except::() - } - async fn handle( - &mut self, - id: Guid, - Configure(ConfigureContext { timeout, config }): Configure, - _: &BackgroundJobQueue, - ) -> Self::Response { - let container = &self.0.persistent_container; - let package_id = &self.0.id; - - container - .execute::(id, ProcedureName::SetConfig, to_value(&config)?, timeout) - .await - .with_kind(ErrorKind::ConfigRulesViolation)?; - self.0 - .ctx - .db - .mutate(move |db| { - db.as_public_mut() - .as_package_data_mut() - .as_idx_mut(package_id) - .or_not_found(package_id)? - .as_status_mut() - .as_configured_mut() - .ser(&true) - }) - .await?; - Ok(()) - } -} - -pub(super) struct GetConfig; -impl Handler for ServiceActor { - type Response = Result; - fn conflicts_with(_: &GetConfig) -> ConflictBuilder { - ConflictBuilder::nothing().except::() - } - async fn handle(&mut self, id: Guid, _: GetConfig, _: &BackgroundJobQueue) -> Self::Response { - let container = &self.0.persistent_container; - container - .execute::( - id, - ProcedureName::GetConfig, - Value::Null, - Some(Duration::from_secs(30)), // TODO timeout - ) - .await - .with_kind(ErrorKind::ConfigRulesViolation) - } -} - -impl Service { - pub async fn configure(&self, id: Guid, ctx: ConfigureContext) -> Result<(), Error> { - self.actor.send(id, Configure(ctx)).await? - } - pub async fn get_config(&self, id: Guid) -> Result { - self.actor.send(id, GetConfig).await? - } -} diff --git a/core/startos/src/service/control.rs b/core/startos/src/service/control.rs index 7c4bdf815..8b920bb32 100644 --- a/core/startos/src/service/control.rs +++ b/core/startos/src/service/control.rs @@ -1,7 +1,6 @@ use crate::prelude::*; use crate::rpc_continuations::Guid; -use crate::service::config::GetConfig; -use crate::service::dependencies::DependencyConfig; +use crate::service::action::RunAction; use crate::service::start_stop::StartStop; use crate::service::transition::TransitionKind; use crate::service::{Service, ServiceActor}; @@ -12,9 +11,7 @@ pub(super) struct Start; impl Handler for ServiceActor { type Response = (); fn conflicts_with(_: &Start) -> ConflictBuilder { - ConflictBuilder::everything() - .except::() - .except::() + ConflictBuilder::everything().except::() } async fn handle(&mut self, _: Guid, _: Start, _: &BackgroundJobQueue) -> Self::Response { self.0.persistent_container.state.send_modify(|x| { @@ -33,9 +30,7 @@ struct Stop; impl Handler for ServiceActor { type Response = (); fn conflicts_with(_: &Stop) -> ConflictBuilder { - ConflictBuilder::everything() - .except::() - .except::() + ConflictBuilder::everything().except::() } async fn handle(&mut self, _: Guid, _: Stop, _: &BackgroundJobQueue) -> Self::Response { let mut transition_state = None; diff --git a/core/startos/src/service/dependencies.rs b/core/startos/src/service/dependencies.rs deleted file mode 100644 index e8c6f07c4..000000000 --- a/core/startos/src/service/dependencies.rs +++ /dev/null @@ -1,86 +0,0 @@ -use std::time::Duration; - -use imbl_value::json; -use models::{PackageId, ProcedureName}; - -use crate::prelude::*; -use crate::rpc_continuations::Guid; -use crate::service::{Service, ServiceActor, ServiceActorSeed}; -use crate::util::actor::background::BackgroundJobQueue; -use crate::util::actor::{ConflictBuilder, Handler}; -use crate::Config; - -impl ServiceActorSeed { - async fn dependency_config( - &self, - id: Guid, - dependency_id: PackageId, - remote_config: Option, - ) -> Result, Error> { - let container = &self.persistent_container; - container - .sanboxed::>( - id.clone(), - ProcedureName::UpdateDependency(dependency_id.clone()), - json!({ - "queryResults": container - .execute::( - id, - ProcedureName::QueryDependency(dependency_id), - Value::Null, - Some(Duration::from_secs(30)), - ) - .await - .with_kind(ErrorKind::Dependency)?, - "remoteConfig": remote_config, - }), - Some(Duration::from_secs(30)), - ) - .await - .with_kind(ErrorKind::Dependency) - .map(|res| res.filter(|c| !c.is_empty() && Some(c) != remote_config.as_ref())) - } -} - -pub(super) struct DependencyConfig { - dependency_id: PackageId, - remote_config: Option, -} -impl Handler for ServiceActor { - type Response = Result, Error>; - fn conflicts_with(_: &DependencyConfig) -> ConflictBuilder { - ConflictBuilder::nothing() - } - async fn handle( - &mut self, - id: Guid, - DependencyConfig { - dependency_id, - remote_config, - }: DependencyConfig, - _: &BackgroundJobQueue, - ) -> Self::Response { - self.0 - .dependency_config(id, dependency_id, remote_config) - .await - } -} - -impl Service { - pub async fn dependency_config( - &self, - id: Guid, - dependency_id: PackageId, - remote_config: Option, - ) -> Result, Error> { - self.actor - .send( - id, - DependencyConfig { - dependency_id, - remote_config, - }, - ) - .await? - } -} diff --git a/core/startos/src/service/effects/action.rs b/core/startos/src/service/effects/action.rs index 4719c6d3d..5e3605679 100644 --- a/core/startos/src/service/effects/action.rs +++ b/core/startos/src/service/effects/action.rs @@ -1,22 +1,59 @@ -use std::collections::BTreeMap; +use std::collections::BTreeSet; -use models::{ActionId, PackageId}; +use models::{ActionId, PackageId, ReplayId}; +use rpc_toolkit::{from_fn_async, Context, HandlerExt, ParentHandler}; -use crate::action::ActionResult; -use crate::db::model::package::ActionMetadata; +use crate::action::{display_action_result, ActionInput, ActionResult}; +use crate::db::model::package::{ + ActionMetadata, ActionRequest, ActionRequestCondition, ActionRequestEntry, ActionRequestTrigger, +}; use crate::rpc_continuations::Guid; +use crate::service::cli::ContainerCliContext; use crate::service::effects::prelude::*; +use crate::util::serde::HandlerExtSerde; + +pub fn action_api() -> ParentHandler { + ParentHandler::new() + .subcommand("export", from_fn_async(export_action).no_cli()) + .subcommand( + "clear", + from_fn_async(clear_actions) + .no_display() + .with_call_remote::(), + ) + .subcommand( + "get-input", + from_fn_async(get_action_input) + .with_display_serializable() + .with_call_remote::(), + ) + .subcommand( + "run", + from_fn_async(run_action) + .with_display_serializable() + .with_custom_display_fn(|args, res| Ok(display_action_result(args.params, res))) + .with_call_remote::(), + ) + .subcommand("request", from_fn_async(request_action).no_cli()) + .subcommand( + "clear-requests", + from_fn_async(clear_action_requests) + .no_display() + .with_call_remote::(), + ) +} #[derive(Debug, Clone, Serialize, Deserialize, TS)] #[ts(export)] #[serde(rename_all = "camelCase")] pub struct ExportActionParams { - #[ts(optional)] - package_id: Option, id: ActionId, metadata: ActionMetadata, } -pub async fn export_action(context: EffectContext, data: ExportActionParams) -> Result<(), Error> { +pub async fn export_action( + context: EffectContext, + ExportActionParams { id, metadata }: ExportActionParams, +) -> Result<(), Error> { let context = context.deref()?; let package_id = context.seed.id.clone(); context @@ -31,17 +68,26 @@ pub async fn export_action(context: EffectContext, data: ExportActionParams) -> .or_not_found(&package_id)? .as_actions_mut(); let mut value = model.de()?; - value - .insert(data.id, data.metadata) - .map(|_| ()) - .unwrap_or_default(); + value.insert(id, metadata); model.ser(&value) }) .await?; Ok(()) } -pub async fn clear_actions(context: EffectContext) -> Result<(), Error> { +#[derive(Debug, Clone, Serialize, Deserialize, TS, Parser)] +#[ts(export)] +#[serde(rename_all = "camelCase")] +pub struct ClearActionsParams { + #[arg(long)] + pub except: Vec, +} + +async fn clear_actions( + context: EffectContext, + ClearActionsParams { except }: ClearActionsParams, +) -> Result<(), Error> { + let except: BTreeSet<_> = except.into_iter().collect(); let context = context.deref()?; let package_id = context.seed.id.clone(); context @@ -54,34 +100,32 @@ pub async fn clear_actions(context: EffectContext) -> Result<(), Error> { .as_idx_mut(&package_id) .or_not_found(&package_id)? .as_actions_mut() - .ser(&BTreeMap::new()) + .mutate(|a| Ok(a.retain(|e, _| except.contains(e)))) }) .await?; Ok(()) } -#[derive(Debug, Clone, Serialize, Deserialize, TS)] +#[derive(Debug, Clone, Serialize, Deserialize, TS, Parser)] #[serde(rename_all = "camelCase")] #[ts(export)] -pub struct ExecuteAction { +pub struct GetActionInputParams { #[serde(default)] #[ts(skip)] + #[arg(skip)] procedure_id: Guid, #[ts(optional)] package_id: Option, action_id: ActionId, - #[ts(type = "any")] - input: Value, } -pub async fn execute_action( +async fn get_action_input( context: EffectContext, - ExecuteAction { + GetActionInputParams { procedure_id, package_id, action_id, - input, - }: ExecuteAction, -) -> Result { + }: GetActionInputParams, +) -> Result, Error> { let context = context.deref()?; if let Some(package_id) = package_id { @@ -93,9 +137,179 @@ pub async fn execute_action( .await .as_ref() .or_not_found(&package_id)? - .action(procedure_id, action_id, input) + .get_action_input(procedure_id, action_id) .await } else { - context.action(procedure_id, action_id, input).await + context.get_action_input(procedure_id, action_id).await } } + +#[derive(Debug, Clone, Serialize, Deserialize, TS, Parser)] +#[serde(rename_all = "camelCase")] +#[ts(export)] +pub struct RunActionParams { + #[serde(default)] + #[ts(skip)] + #[arg(skip)] + procedure_id: Guid, + #[ts(optional)] + package_id: Option, + action_id: ActionId, + #[ts(type = "any")] + input: Value, +} +async fn run_action( + context: EffectContext, + RunActionParams { + procedure_id, + package_id, + action_id, + input, + }: RunActionParams, +) -> Result, Error> { + let context = context.deref()?; + + let package_id = package_id.as_ref().unwrap_or(&context.seed.id); + + if package_id != &context.seed.id { + return Err(Error::new( + eyre!("calling actions on other packages is unsupported at this time"), + ErrorKind::InvalidRequest, + )); + context + .seed + .ctx + .services + .get(&package_id) + .await + .as_ref() + .or_not_found(&package_id)? + .run_action(procedure_id, action_id, input) + .await + } else { + context.run_action(procedure_id, action_id, input).await + } +} + +#[derive(Clone, Debug, Deserialize, Serialize, TS)] +#[serde(rename_all = "camelCase")] +#[ts(export)] +pub struct RequestActionParams { + #[serde(default)] + #[ts(skip)] + procedure_id: Guid, + replay_id: ReplayId, + #[serde(flatten)] + request: ActionRequest, +} +async fn request_action( + context: EffectContext, + RequestActionParams { + procedure_id, + replay_id, + request, + }: RequestActionParams, +) -> Result<(), Error> { + let context = context.deref()?; + + let src_id = &context.seed.id; + let active = match &request.when { + Some(ActionRequestTrigger { once, condition }) => match condition { + ActionRequestCondition::InputNotMatches => { + let Some(input) = request.input.as_ref() else { + return Err(Error::new( + eyre!("input-not-matches trigger requires input to be specified"), + ErrorKind::InvalidRequest, + )); + }; + if let Some(service) = context + .seed + .ctx + .services + .get(&request.package_id) + .await + .as_ref() + { + let Some(prev) = service + .get_action_input(procedure_id, request.action_id.clone()) + .await? + else { + return Err(Error::new( + eyre!( + "action {} of {} has no input", + request.action_id, + request.package_id + ), + ErrorKind::InvalidRequest, + )); + }; + if input.matches(prev.value.as_ref()) { + if *once { + return Ok(()); + } else { + false + } + } else { + true + } + } else { + true // update when service is installed + } + } + }, + None => true, + }; + context + .seed + .ctx + .db + .mutate(|db| { + db.as_public_mut() + .as_package_data_mut() + .as_idx_mut(src_id) + .or_not_found(src_id)? + .as_requested_actions_mut() + .insert(&replay_id, &ActionRequestEntry { active, request }) + }) + .await?; + Ok(()) +} + +#[derive(Debug, Clone, Serialize, Deserialize, TS, Parser)] +#[ts(type = "{ only: string[] } | { except: string[] }")] +#[ts(export)] +pub struct ClearActionRequestsParams { + #[arg(long, conflicts_with = "except")] + pub only: Option>, + #[arg(long, conflicts_with = "only")] + pub except: Option>, +} + +async fn clear_action_requests( + context: EffectContext, + ClearActionRequestsParams { only, except }: ClearActionRequestsParams, +) -> Result<(), Error> { + let context = context.deref()?; + let package_id = context.seed.id.clone(); + let only = only.map(|only| only.into_iter().collect::>()); + let except = except.map(|except| except.into_iter().collect::>()); + context + .seed + .ctx + .db + .mutate(|db| { + db.as_public_mut() + .as_package_data_mut() + .as_idx_mut(&package_id) + .or_not_found(&package_id)? + .as_requested_actions_mut() + .mutate(|a| { + Ok(a.retain(|e, _| { + only.as_ref().map_or(true, |only| !only.contains(e)) + && except.as_ref().map_or(true, |except| except.contains(e)) + })) + }) + }) + .await?; + Ok(()) +} diff --git a/core/startos/src/service/effects/callbacks.rs b/core/startos/src/service/effects/callbacks.rs index 1a9250aa8..65eb707d8 100644 --- a/core/startos/src/service/effects/callbacks.rs +++ b/core/startos/src/service/effects/callbacks.rs @@ -3,19 +3,22 @@ use std::collections::{BTreeMap, BTreeSet}; use std::sync::{Arc, Mutex, Weak}; use std::time::{Duration, SystemTime}; +use clap::Parser; use futures::future::join_all; use helpers::NonDetachingJoinHandle; use imbl::{vector, Vector}; use imbl_value::InternedString; use models::{HostId, PackageId, ServiceInterfaceId}; use patch_db::json_ptr::JsonPointer; +use serde::{Deserialize, Serialize}; use tracing::warn; +use ts_rs::TS; use crate::net::ssl::FullchainCertData; use crate::prelude::*; use crate::service::effects::context::EffectContext; use crate::service::effects::net::ssl::Algorithm; -use crate::service::rpc::CallbackHandle; +use crate::service::rpc::{CallbackHandle, CallbackId}; use crate::service::{Service, ServiceActorSeed}; use crate::util::collections::EqMap; @@ -33,6 +36,7 @@ struct ServiceCallbackMap { (NonDetachingJoinHandle<()>, Vec), >, get_store: BTreeMap>>, + get_status: BTreeMap>, } impl ServiceCallbacks { @@ -68,6 +72,10 @@ impl ServiceCallbacks { }); !v.is_empty() }); + this.get_status.retain(|_, v| { + v.retain(|h| h.handle.is_active() && h.seed.strong_count() > 0); + !v.is_empty() + }); }) } @@ -217,6 +225,20 @@ impl ServiceCallbacks { .push(handler); }) } + pub(super) fn add_get_status(&self, package_id: PackageId, handler: CallbackHandler) { + self.mutate(|this| this.get_status.entry(package_id).or_default().push(handler)) + } + #[must_use] + pub fn get_status(&self, package_id: &PackageId) -> Option { + self.mutate(|this| { + if let Some(watched) = this.get_status.remove(package_id) { + Some(CallbackHandlers(watched)) + } else { + None + } + .filter(|cb| !cb.0.is_empty()) + }) + } pub(super) fn add_get_store( &self, @@ -272,6 +294,7 @@ impl CallbackHandler { } } pub async fn call(mut self, args: Vector) -> Result<(), Error> { + dbg!(eyre!("callback fired: {}", self.handle.is_active())); if let Some(seed) = self.seed.upgrade() { seed.persistent_container .callback(self.handle.take(), args) @@ -299,13 +322,29 @@ impl CallbackHandlers { } } -pub(super) fn clear_callbacks(context: EffectContext) -> Result<(), Error> { +#[derive(Debug, Clone, Serialize, Deserialize, TS, Parser)] +#[ts(type = "{ only: number[] } | { except: number[] }")] +#[ts(export)] +pub struct ClearCallbacksParams { + #[arg(long, conflicts_with = "except")] + pub only: Option>, + #[arg(long, conflicts_with = "only")] + pub except: Option>, +} + +pub(super) fn clear_callbacks( + context: EffectContext, + ClearCallbacksParams { only, except }: ClearCallbacksParams, +) -> Result<(), Error> { let context = context.deref()?; - context - .seed - .persistent_container - .state - .send_if_modified(|s| !std::mem::take(&mut s.callbacks).is_empty()); + let only = only.map(|only| only.into_iter().collect::>()); + let except = except.map(|except| except.into_iter().collect::>()); + context.seed.persistent_container.state.send_modify(|s| { + s.callbacks.retain(|cb| { + only.as_ref().map_or(true, |only| !only.contains(cb)) + && except.as_ref().map_or(true, |except| except.contains(cb)) + }) + }); context.seed.ctx.callbacks.gc(); Ok(()) } diff --git a/core/startos/src/service/effects/config.rs b/core/startos/src/service/effects/config.rs deleted file mode 100644 index 647d3e272..000000000 --- a/core/startos/src/service/effects/config.rs +++ /dev/null @@ -1,53 +0,0 @@ -use models::PackageId; - -use crate::service::effects::prelude::*; - -#[derive(Debug, Clone, Serialize, Deserialize, Parser, TS)] -#[serde(rename_all = "camelCase")] -#[ts(export)] -pub struct GetConfiguredParams { - #[ts(optional)] - package_id: Option, -} -pub async fn get_configured(context: EffectContext) -> Result { - let context = context.deref()?; - let peeked = context.seed.ctx.db.peek().await; - let package_id = &context.seed.id; - peeked - .as_public() - .as_package_data() - .as_idx(package_id) - .or_not_found(package_id)? - .as_status() - .as_configured() - .de() -} - -#[derive(Debug, Clone, Serialize, Deserialize, Parser, TS)] -#[serde(rename_all = "camelCase")] -#[ts(export)] -pub struct SetConfigured { - configured: bool, -} -pub async fn set_configured( - context: EffectContext, - SetConfigured { configured }: SetConfigured, -) -> Result<(), Error> { - let context = context.deref()?; - let package_id = &context.seed.id; - context - .seed - .ctx - .db - .mutate(|db| { - db.as_public_mut() - .as_package_data_mut() - .as_idx_mut(package_id) - .or_not_found(package_id)? - .as_status_mut() - .as_configured_mut() - .ser(&configured) - }) - .await?; - Ok(()) -} diff --git a/core/startos/src/service/effects/control.rs b/core/startos/src/service/effects/control.rs index 6b3c6f8a0..4b9817b77 100644 --- a/core/startos/src/service/effects/control.rs +++ b/core/startos/src/service/effects/control.rs @@ -1,9 +1,11 @@ use std::str::FromStr; use clap::builder::ValueParserFactory; +use models::{FromStrParser, PackageId}; use crate::service::effects::prelude::*; -use crate::util::clap::FromStrParser; +use crate::service::rpc::CallbackId; +use crate::status::MainStatus; pub async fn restart( context: EffectContext, @@ -23,6 +25,46 @@ pub async fn shutdown( Ok(()) } +#[derive(Debug, Clone, Serialize, Deserialize, TS, Parser)] +#[serde(rename_all = "camelCase")] +#[ts(export)] +pub struct GetStatusParams { + #[ts(optional)] + pub package_id: Option, + #[ts(optional)] + #[arg(skip)] + pub callback: Option, +} + +pub async fn get_status( + context: EffectContext, + GetStatusParams { + package_id, + callback, + }: GetStatusParams, +) -> Result { + let context = context.deref()?; + let id = package_id.unwrap_or_else(|| context.seed.id.clone()); + let db = context.seed.ctx.db.peek().await; + let status = db + .as_public() + .as_package_data() + .as_idx(&id) + .or_not_found(&id)? + .as_status() + .de()?; + + if let Some(callback) = callback { + let callback = callback.register(&context.seed.persistent_container); + context.seed.ctx.callbacks.add_get_status( + id, + super::callbacks::CallbackHandler::new(&context, callback), + ); + } + + Ok(status) +} + #[derive(Debug, Clone, Serialize, Deserialize, TS)] #[serde(rename_all = "camelCase")] #[ts(export)] diff --git a/core/startos/src/service/effects/dependency.rs b/core/startos/src/service/effects/dependency.rs index 26582d061..ed43b7a9c 100644 --- a/core/startos/src/service/effects/dependency.rs +++ b/core/startos/src/service/effects/dependency.rs @@ -6,13 +6,13 @@ use clap::builder::ValueParserFactory; use exver::VersionRange; use imbl::OrdMap; use imbl_value::InternedString; -use itertools::Itertools; -use models::{HealthCheckId, PackageId, VersionString, VolumeId}; +use models::{FromStrParser, HealthCheckId, PackageId, ReplayId, VersionString, VolumeId}; use patch_db::json_ptr::JsonPointer; use tokio::process::Command; use crate::db::model::package::{ - CurrentDependencies, CurrentDependencyInfo, CurrentDependencyKind, ManifestPreference, + ActionRequestEntry, CurrentDependencies, CurrentDependencyInfo, CurrentDependencyKind, + ManifestPreference, }; use crate::disk::mount::filesystem::bind::Bind; use crate::disk::mount::filesystem::idmapped::IdMapped; @@ -20,7 +20,6 @@ use crate::disk::mount::filesystem::{FileSystem, MountType}; use crate::rpc_continuations::Guid; use crate::service::effects::prelude::*; use crate::status::health_check::NamedHealthCheckResult; -use crate::util::clap::FromStrParser; use crate::util::Invoke; use crate::volume::data_dir; @@ -113,6 +112,7 @@ pub async fn expose_for_dependents( context: EffectContext, ExposeForDependentsParams { paths }: ExposeForDependentsParams, ) -> Result<(), Error> { + // TODO Ok(()) } @@ -192,16 +192,11 @@ impl ValueParserFactory for DependencyRequirement { #[command(rename_all = "camelCase")] #[ts(export)] pub struct SetDependenciesParams { - #[serde(default)] - procedure_id: Guid, dependencies: Vec, } pub async fn set_dependencies( context: EffectContext, - SetDependenciesParams { - procedure_id, - dependencies, - }: SetDependenciesParams, + SetDependenciesParams { dependencies }: SetDependenciesParams, ) -> Result<(), Error> { let context = context.deref()?; let id = &context.seed.id; @@ -222,19 +217,6 @@ pub async fn set_dependencies( version_range, ), }; - let config_satisfied = - if let Some(dep_service) = &*context.seed.ctx.services.get(&dep_id).await { - context - .dependency_config( - procedure_id.clone(), - dep_id.clone(), - dep_service.get_config(procedure_id.clone()).await?.config, - ) - .await? - .is_none() - } else { - true - }; let info = CurrentDependencyInfo { title: context .seed @@ -251,7 +233,6 @@ pub async fn set_dependencies( .await?, kind, version_range, - config_satisfied, }; deps.insert(dep_id, info); } @@ -282,7 +263,8 @@ pub async fn get_dependencies(context: EffectContext) -> Result Result(match kind { + match kind { CurrentDependencyKind::Exists => { DependencyRequirement::Exists { id, version_range } } @@ -301,9 +283,9 @@ pub async fn get_dependencies(context: EffectContext) -> Result, - #[ts(type = "string | null")] - installed_version: Option, - #[ts(type = "string[]")] + installed_version: Option, satisfies: BTreeSet, is_running: bool, - config_satisfied: bool, + requested_actions: BTreeMap, #[ts(as = "BTreeMap::")] health_checks: OrdMap, } @@ -335,14 +315,14 @@ pub async fn check_dependencies( ) -> Result, Error> { let context = context.deref()?; let db = context.seed.ctx.db.peek().await; - let current_dependencies = db + let pde = db .as_public() .as_package_data() .as_idx(&context.seed.id) - .or_not_found(&context.seed.id)? - .as_current_dependencies() - .de()?; - let package_ids: Vec<_> = package_ids + .or_not_found(&context.seed.id)?; + let current_dependencies = pde.as_current_dependencies().de()?; + let requested_actions = pde.as_requested_actions().de()?; + let package_dependency_info: Vec<_> = package_ids .unwrap_or_else(|| current_dependencies.0.keys().cloned().collect()) .into_iter() .filter_map(|x| { @@ -350,18 +330,23 @@ pub async fn check_dependencies( Some((x, info)) }) .collect(); - let mut results = Vec::with_capacity(package_ids.len()); + let mut results = Vec::with_capacity(package_dependency_info.len()); - for (package_id, dependency_info) in package_ids { + for (package_id, dependency_info) in package_dependency_info { let title = dependency_info.title.clone(); let Some(package) = db.as_public().as_package_data().as_idx(&package_id) else { + let requested_actions = requested_actions + .iter() + .filter(|(_, v)| v.request.package_id == package_id) + .map(|(k, v)| (k.clone(), v.clone())) + .collect(); results.push(CheckDependenciesResult { package_id, title, installed_version: None, satisfies: BTreeSet::new(), is_running: false, - config_satisfied: false, + requested_actions, health_checks: Default::default(), }); continue; @@ -369,22 +354,27 @@ pub async fn check_dependencies( let manifest = package.as_state_info().as_manifest(ManifestPreference::New); let installed_version = manifest.as_version().de()?.into_version(); let satisfies = manifest.as_satisfies().de()?; - let installed_version = Some(installed_version.clone()); + let installed_version = Some(installed_version.clone().into()); let is_installed = true; - let status = package.as_status().as_main().de()?; + let status = package.as_status().de()?; let is_running = if is_installed { status.running() } else { false }; let health_checks = status.health().cloned().unwrap_or_default(); + let requested_actions = requested_actions + .iter() + .filter(|(_, v)| v.request.package_id == package_id) + .map(|(k, v)| (k.clone(), v.clone())) + .collect(); results.push(CheckDependenciesResult { package_id, title, installed_version, satisfies, is_running, - config_satisfied: dependency_info.config_satisfied, + requested_actions, health_checks, }); } diff --git a/core/startos/src/service/effects/health.rs b/core/startos/src/service/effects/health.rs index 9bf756d60..c95dea946 100644 --- a/core/startos/src/service/effects/health.rs +++ b/core/startos/src/service/effects/health.rs @@ -29,7 +29,6 @@ pub async fn set_health( .as_idx_mut(package_id) .or_not_found(package_id)? .as_status_mut() - .as_main_mut() .mutate(|main| { match main { MainStatus::Running { ref mut health, .. } diff --git a/core/startos/src/service/effects/mod.rs b/core/startos/src/service/effects/mod.rs index e85481e96..f68985268 100644 --- a/core/startos/src/service/effects/mod.rs +++ b/core/startos/src/service/effects/mod.rs @@ -7,7 +7,6 @@ use crate::service::effects::context::EffectContext; mod action; pub mod callbacks; -mod config; pub mod context; mod control; mod dependency; @@ -26,34 +25,12 @@ pub fn handler() -> ParentHandler { from_fn(echo::).with_call_remote::(), ) // action - .subcommand( - "execute-action", - from_fn_async(action::execute_action).no_cli(), - ) - .subcommand( - "export-action", - from_fn_async(action::export_action).no_cli(), - ) - .subcommand( - "clear-actions", - from_fn_async(action::clear_actions).no_cli(), - ) + .subcommand("action", action::action_api::()) // callbacks .subcommand( "clear-callbacks", from_fn(callbacks::clear_callbacks).no_cli(), ) - // config - .subcommand( - "get-configured", - from_fn_async(config::get_configured).no_cli(), - ) - .subcommand( - "set-configured", - from_fn_async(config::set_configured) - .no_display() - .with_call_remote::(), - ) // control .subcommand( "restart", @@ -73,6 +50,12 @@ pub fn handler() -> ParentHandler { .no_display() .with_call_remote::(), ) + .subcommand( + "get-status", + from_fn_async(control::get_status) + .no_display() + .with_call_remote::(), + ) // dependency .subcommand( "set-dependencies", diff --git a/core/startos/src/service/effects/net/bind.rs b/core/startos/src/service/effects/net/bind.rs index ba273323a..5619375eb 100644 --- a/core/startos/src/service/effects/net/bind.rs +++ b/core/startos/src/service/effects/net/bind.rs @@ -1,6 +1,6 @@ use models::{HostId, PackageId}; -use crate::net::host::binding::{BindOptions, LanInfo}; +use crate::net::host::binding::{BindId, BindOptions, LanInfo}; use crate::net::host::HostKind; use crate::service::effects::prelude::*; @@ -28,10 +28,21 @@ pub async fn bind( svc.bind(kind, id, internal_port, options).await } -pub async fn clear_bindings(context: EffectContext) -> Result<(), Error> { +#[derive(Debug, Clone, Serialize, Deserialize, TS, Parser)] +#[ts(export)] +#[serde(rename_all = "camelCase")] +pub struct ClearBindingsParams { + #[serde(default)] + pub except: Vec, +} + +pub async fn clear_bindings( + context: EffectContext, + ClearBindingsParams { except }: ClearBindingsParams, +) -> Result<(), Error> { let context = context.deref()?; let mut svc = context.seed.persistent_container.net_service.lock().await; - svc.clear_bindings().await?; + svc.clear_bindings(except.into_iter().collect()).await?; Ok(()) } diff --git a/core/startos/src/service/effects/net/interface.rs b/core/startos/src/service/effects/net/interface.rs index 6cd4cd4c9..44258c36a 100644 --- a/core/startos/src/service/effects/net/interface.rs +++ b/core/startos/src/service/effects/net/interface.rs @@ -165,7 +165,17 @@ pub async fn list_service_interfaces( Ok(res) } -pub async fn clear_service_interfaces(context: EffectContext) -> Result<(), Error> { +#[derive(Debug, Clone, Serialize, Deserialize, TS, Parser)] +#[ts(export)] +#[serde(rename_all = "camelCase")] +pub struct ClearServiceInterfacesParams { + pub except: Vec, +} + +pub async fn clear_service_interfaces( + context: EffectContext, + ClearServiceInterfacesParams { except }: ClearServiceInterfacesParams, +) -> Result<(), Error> { let context = context.deref()?; let package_id = context.seed.id.clone(); @@ -179,7 +189,7 @@ pub async fn clear_service_interfaces(context: EffectContext) -> Result<(), Erro .as_idx_mut(&package_id) .or_not_found(&package_id)? .as_service_interfaces_mut() - .ser(&Default::default()) + .mutate(|s| Ok(s.retain(|id, _| except.contains(id)))) }) .await } diff --git a/core/startos/src/service/effects/store.rs b/core/startos/src/service/effects/store.rs index 6c12b425e..1d4a07086 100644 --- a/core/startos/src/service/effects/store.rs +++ b/core/startos/src/service/effects/store.rs @@ -26,6 +26,7 @@ pub async fn get_store( callback, }: GetStoreParams, ) -> Result { + dbg!(&callback); let context = context.deref()?; let peeked = context.seed.ctx.db.peek().await; let package_id = package_id.unwrap_or(context.seed.id.clone()); @@ -33,8 +34,9 @@ pub async fn get_store( .as_private() .as_package_stores() .as_idx(&package_id) - .or_not_found(&package_id)? - .de()?; + .map(|s| s.de()) + .transpose()? + .unwrap_or_default(); if let Some(callback) = callback { let callback = callback.register(&context.seed.persistent_container); @@ -45,10 +47,7 @@ pub async fn get_store( ); } - Ok(path - .get(&value) - .ok_or_else(|| Error::new(eyre!("Did not find value at path"), ErrorKind::NotFound))? - .clone()) + Ok(path.get(&value).cloned().unwrap_or_default()) } #[derive(Debug, Clone, Serialize, Deserialize, TS)] diff --git a/core/startos/src/service/effects/subcontainer/mod.rs b/core/startos/src/service/effects/subcontainer/mod.rs index 0375ef6c2..65fcbd387 100644 --- a/core/startos/src/service/effects/subcontainer/mod.rs +++ b/core/startos/src/service/effects/subcontainer/mod.rs @@ -1,12 +1,15 @@ use std::path::{Path, PathBuf}; +use imbl_value::InternedString; use models::ImageId; use tokio::process::Command; -use crate::disk::mount::filesystem::overlayfs::OverlayGuard; use crate::rpc_continuations::Guid; use crate::service::effects::prelude::*; use crate::util::Invoke; +use crate::{ + disk::mount::filesystem::overlayfs::OverlayGuard, service::persistent_container::Subcontainer, +}; #[cfg(feature = "container-runtime")] mod sync; @@ -38,7 +41,7 @@ pub async fn destroy_subcontainer_fs( .await .remove(&guid) { - overlay.unmount(true).await?; + overlay.overlay.unmount(true).await?; } else { tracing::warn!("Could not find a subcontainer fs to destroy; assumming that it already is destroyed and will be skipping"); } @@ -50,11 +53,13 @@ pub async fn destroy_subcontainer_fs( #[ts(export)] pub struct CreateSubcontainerFsParams { image_id: ImageId, + #[ts(type = "string | null")] + name: Option, } #[instrument(skip_all)] pub async fn create_subcontainer_fs( context: EffectContext, - CreateSubcontainerFsParams { image_id }: CreateSubcontainerFsParams, + CreateSubcontainerFsParams { image_id, name }: CreateSubcontainerFsParams, ) -> Result<(PathBuf, Guid), Error> { let context = context.deref()?; if let Some(image) = context @@ -87,7 +92,13 @@ pub async fn create_subcontainer_fs( .with_kind(ErrorKind::Incoherent)?, ); tracing::info!("Mounting overlay {guid} for {image_id}"); - let guard = OverlayGuard::mount(image, &mountpoint).await?; + let subcontainer_wrapper = Subcontainer { + overlay: OverlayGuard::mount(image, &mountpoint).await?, + name: name + .unwrap_or_else(|| InternedString::intern(format!("subcontainer-{}", image_id))), + image_id: image_id.clone(), + }; + Command::new("chown") .arg("100000:100000") .arg(&mountpoint) @@ -100,7 +111,7 @@ pub async fn create_subcontainer_fs( .subcontainers .lock() .await - .insert(guid.clone(), guard); + .insert(guid.clone(), subcontainer_wrapper); Ok((container_mountpoint, guid)) } else { Err(Error::new( diff --git a/core/startos/src/service/effects/subcontainer/sync.rs b/core/startos/src/service/effects/subcontainer/sync.rs index e18586a54..702f34bbe 100644 --- a/core/startos/src/service/effects/subcontainer/sync.rs +++ b/core/startos/src/service/effects/subcontainer/sync.rs @@ -1,17 +1,16 @@ -use std::borrow::Cow; use std::collections::BTreeMap; use std::ffi::{c_int, OsStr, OsString}; use std::fs::File; +use std::io::IsTerminal; use std::os::unix::process::CommandExt; use std::path::{Path, PathBuf}; use std::process::{Command as StdCommand, Stdio}; use nix::sched::CloneFlags; use nix::unistd::Pid; -use rpc_toolkit::Context; use signal_hook::consts::signal::*; use tokio::sync::oneshot; -use unshare::Command as NSCommand; +use tty_spawn::TtySpawn; use crate::service::effects::prelude::*; use crate::service::effects::ContainerCliContext; @@ -49,11 +48,13 @@ fn open_file_read(path: impl AsRef) -> Result { #[derive(Debug, Clone, Serialize, Deserialize, Parser)] pub struct ExecParams { - #[arg(short = 'e', long = "env")] + #[arg(long)] + force_tty: bool, + #[arg(short, long)] env: Option, - #[arg(short = 'w', long = "workdir")] + #[arg(short, long)] workdir: Option, - #[arg(short = 'u', long = "user")] + #[arg(short, long)] user: Option, chroot: PathBuf, #[arg(trailing_var_arg = true)] @@ -67,6 +68,7 @@ impl ExecParams { user, chroot, command, + .. } = self; let Some(([command], args)) = command.split_at_checked(1) else { return Err(Error::new( @@ -87,16 +89,6 @@ impl ExecParams { .collect::>(); std::os::unix::fs::chroot(chroot) .with_ctx(|_| (ErrorKind::Filesystem, lazy_format!("chroot {chroot:?}")))?; - let command = which::which_in( - command, - env.get("PATH") - .copied() - .map(Cow::Borrowed) - .or_else(|| std::env::var("PATH").ok().map(Cow::Owned)) - .as_deref(), - workdir.as_deref().unwrap_or(Path::new("/")), - ) - .with_kind(ErrorKind::Filesystem)?; let mut cmd = StdCommand::new(command); cmd.args(args); for (k, v) in env { @@ -134,6 +126,7 @@ impl ExecParams { pub fn launch( _: ContainerCliContext, ExecParams { + force_tty, env, workdir, user, @@ -141,47 +134,8 @@ pub fn launch( command, }: ExecParams, ) -> Result<(), Error> { - use unshare::{Namespace, Stdio}; - - use crate::service::cli::ContainerCliContext; - let mut sig = signal_hook::iterator::Signals::new(FWD_SIGNALS)?; - let mut cmd = NSCommand::new("/usr/bin/start-cli"); - cmd.arg("subcontainer").arg("launch-init"); - if let Some(env) = env { - cmd.arg("--env").arg(env); - } - if let Some(workdir) = workdir { - cmd.arg("--workdir").arg(workdir); - } - if let Some(user) = user { - cmd.arg("--user").arg(user); - } - cmd.arg(&chroot); - cmd.args(&command); - cmd.unshare(&[Namespace::Pid, Namespace::Cgroup, Namespace::Ipc]); - cmd.stdin(Stdio::piped()); - cmd.stdout(Stdio::piped()); - cmd.stderr(Stdio::piped()); - let (stdin_send, stdin_recv) = oneshot::channel(); - std::thread::spawn(move || { - if let Ok(mut stdin) = stdin_recv.blocking_recv() { - std::io::copy(&mut std::io::stdin(), &mut stdin).unwrap(); - } - }); - let (stdout_send, stdout_recv) = oneshot::channel(); - std::thread::spawn(move || { - if let Ok(mut stdout) = stdout_recv.blocking_recv() { - std::io::copy(&mut stdout, &mut std::io::stdout()).unwrap(); - } - }); - let (stderr_send, stderr_recv) = oneshot::channel(); - std::thread::spawn(move || { - if let Ok(mut stderr) = stderr_recv.blocking_recv() { - std::io::copy(&mut stderr, &mut std::io::stderr()).unwrap(); - } - }); if chroot.join("proc/1").exists() { - let ns_id = procfs::process::Process::new_with_root(chroot.join("proc")) + let ns_id = procfs::process::Process::new_with_root(chroot.join("proc/1")) .with_ctx(|_| (ErrorKind::Filesystem, "open subcontainer procfs"))? .namespaces() .with_ctx(|_| (ErrorKind::Filesystem, "read subcontainer pid 1 ns"))? @@ -224,20 +178,92 @@ pub fn launch( nix::mount::umount(&chroot.join("proc")) .with_ctx(|_| (ErrorKind::Filesystem, "unmounting subcontainer procfs"))?; } + + if (std::io::stdin().is_terminal() + && std::io::stdout().is_terminal() + && std::io::stderr().is_terminal()) + || force_tty + { + let mut cmd = TtySpawn::new("/usr/bin/start-cli"); + cmd.arg("subcontainer").arg("launch-init"); + if let Some(env) = env { + cmd.arg("--env").arg(env); + } + if let Some(workdir) = workdir { + cmd.arg("--workdir").arg(workdir); + } + if let Some(user) = user { + cmd.arg("--user").arg(user); + } + cmd.arg(&chroot); + cmd.args(command.iter()); + nix::sched::unshare(CloneFlags::CLONE_NEWPID) + .with_ctx(|_| (ErrorKind::Filesystem, "unshare pid ns"))?; + nix::sched::unshare(CloneFlags::CLONE_NEWCGROUP) + .with_ctx(|_| (ErrorKind::Filesystem, "unshare cgroup ns"))?; + nix::sched::unshare(CloneFlags::CLONE_NEWIPC) + .with_ctx(|_| (ErrorKind::Filesystem, "unshare ipc ns"))?; + std::process::exit(cmd.spawn().with_kind(ErrorKind::Filesystem)?); + } + + let mut sig = signal_hook::iterator::Signals::new(FWD_SIGNALS)?; + let (send_pid, recv_pid) = oneshot::channel(); + std::thread::spawn(move || { + if let Ok(pid) = recv_pid.blocking_recv() { + for sig in sig.forever() { + nix::sys::signal::kill( + Pid::from_raw(pid), + Some(nix::sys::signal::Signal::try_from(sig).unwrap()), + ) + .unwrap(); + } + } + }); + let mut cmd = StdCommand::new("/usr/bin/start-cli"); + cmd.arg("subcontainer").arg("launch-init"); + if let Some(env) = env { + cmd.arg("--env").arg(env); + } + if let Some(workdir) = workdir { + cmd.arg("--workdir").arg(workdir); + } + if let Some(user) = user { + cmd.arg("--user").arg(user); + } + cmd.arg(&chroot); + cmd.args(&command); + cmd.stdin(Stdio::piped()); + cmd.stdout(Stdio::piped()); + cmd.stderr(Stdio::piped()); + let (stdin_send, stdin_recv) = oneshot::channel(); + std::thread::spawn(move || { + if let Ok(mut stdin) = stdin_recv.blocking_recv() { + std::io::copy(&mut std::io::stdin(), &mut stdin).unwrap(); + } + }); + let (stdout_send, stdout_recv) = oneshot::channel(); + std::thread::spawn(move || { + if let Ok(mut stdout) = stdout_recv.blocking_recv() { + std::io::copy(&mut stdout, &mut std::io::stdout()).unwrap(); + } + }); + let (stderr_send, stderr_recv) = oneshot::channel(); + std::thread::spawn(move || { + if let Ok(mut stderr) = stderr_recv.blocking_recv() { + std::io::copy(&mut stderr, &mut std::io::stderr()).unwrap(); + } + }); + nix::sched::unshare(CloneFlags::CLONE_NEWPID) + .with_ctx(|_| (ErrorKind::Filesystem, "unshare pid ns"))?; + nix::sched::unshare(CloneFlags::CLONE_NEWCGROUP) + .with_ctx(|_| (ErrorKind::Filesystem, "unshare cgroup ns"))?; + nix::sched::unshare(CloneFlags::CLONE_NEWIPC) + .with_ctx(|_| (ErrorKind::Filesystem, "unshare ipc ns"))?; let mut child = cmd .spawn() .map_err(color_eyre::eyre::Report::msg) .with_ctx(|_| (ErrorKind::Filesystem, "spawning child process"))?; - let pid = child.pid(); - std::thread::spawn(move || { - for sig in sig.forever() { - nix::sys::signal::kill( - Pid::from_raw(pid), - Some(nix::sys::signal::Signal::try_from(sig).unwrap()), - ) - .unwrap(); - } - }); + send_pid.send(child.id() as i32).unwrap_or_default(); stdin_send .send(child.stdin.take().unwrap()) .unwrap_or_default(); @@ -252,16 +278,16 @@ pub fn launch( .wait() .with_ctx(|_| (ErrorKind::Filesystem, "waiting on child process"))?; if let Some(code) = exit.code() { + nix::mount::umount(&chroot.join("proc")) + .with_ctx(|_| (ErrorKind::Filesystem, "umount procfs"))?; std::process::exit(code); + } else if exit.success() { + Ok(()) } else { - if exit.success() { - Ok(()) - } else { - Err(Error::new( - color_eyre::eyre::Report::msg(exit), - ErrorKind::Unknown, - )) - } + Err(Error::new( + color_eyre::eyre::Report::msg(exit), + ErrorKind::Unknown, + )) } } @@ -287,6 +313,7 @@ pub fn launch_init(_: ContainerCliContext, params: ExecParams) -> Result<(), Err pub fn exec( _: ContainerCliContext, ExecParams { + force_tty, env, workdir, user, @@ -294,6 +321,41 @@ pub fn exec( command, }: ExecParams, ) -> Result<(), Error> { + if (std::io::stdin().is_terminal() + && std::io::stdout().is_terminal() + && std::io::stderr().is_terminal()) + || force_tty + { + let mut cmd = TtySpawn::new("/usr/bin/start-cli"); + cmd.arg("subcontainer").arg("exec-command"); + if let Some(env) = env { + cmd.arg("--env").arg(env); + } + if let Some(workdir) = workdir { + cmd.arg("--workdir").arg(workdir); + } + if let Some(user) = user { + cmd.arg("--user").arg(user); + } + cmd.arg(&chroot); + cmd.args(command.iter()); + nix::sched::setns( + open_file_read(chroot.join("proc/1/ns/pid"))?, + CloneFlags::CLONE_NEWPID, + ) + .with_ctx(|_| (ErrorKind::Filesystem, "set pid ns"))?; + nix::sched::setns( + open_file_read(chroot.join("proc/1/ns/cgroup"))?, + CloneFlags::CLONE_NEWCGROUP, + ) + .with_ctx(|_| (ErrorKind::Filesystem, "set cgroup ns"))?; + nix::sched::setns( + open_file_read(chroot.join("proc/1/ns/ipc"))?, + CloneFlags::CLONE_NEWIPC, + ) + .with_ctx(|_| (ErrorKind::Filesystem, "set ipc ns"))?; + std::process::exit(cmd.spawn().with_kind(ErrorKind::Filesystem)?); + } let mut sig = signal_hook::iterator::Signals::new(FWD_SIGNALS)?; let (send_pid, recv_pid) = oneshot::channel(); std::thread::spawn(move || { @@ -375,15 +437,13 @@ pub fn exec( .with_ctx(|_| (ErrorKind::Filesystem, "waiting on child process"))?; if let Some(code) = exit.code() { std::process::exit(code); + } else if exit.success() { + Ok(()) } else { - if exit.success() { - Ok(()) - } else { - Err(Error::new( - color_eyre::eyre::Report::msg(exit), - ErrorKind::Unknown, - )) - } + Err(Error::new( + color_eyre::eyre::Report::msg(exit), + ErrorKind::Unknown, + )) } } diff --git a/core/startos/src/service/mod.rs b/core/startos/src/service/mod.rs index 5eae62756..d73c51beb 100644 --- a/core/startos/src/service/mod.rs +++ b/core/startos/src/service/mod.rs @@ -1,18 +1,32 @@ +use std::collections::{BTreeMap, BTreeSet}; +use std::ffi::OsString; +use std::io::IsTerminal; use std::ops::Deref; +use std::os::unix::process::ExitStatusExt; +use std::path::{Path, PathBuf}; +use std::process::Stdio; use std::sync::{Arc, Weak}; use std::time::Duration; +use axum::extract::ws::WebSocket; use chrono::{DateTime, Utc}; use clap::Parser; use futures::future::BoxFuture; -use imbl::OrdMap; -use models::{HealthCheckId, PackageId, ProcedureName}; -use persistent_container::PersistentContainer; +use futures::stream::FusedStream; +use futures::{SinkExt, StreamExt, TryStreamExt}; +use imbl_value::{json, InternedString}; +use itertools::Itertools; +use models::{ActionId, HostId, ImageId, PackageId, ProcedureName}; +use nix::sys::signal::Signal; +use persistent_container::{PersistentContainer, Subcontainer}; use rpc_toolkit::{from_fn_async, CallRemoteHandler, Empty, HandlerArgs, HandlerFor}; use serde::{Deserialize, Serialize}; use service_actor::ServiceActor; use start_stop::StartStop; +use tokio::io::{AsyncReadExt, AsyncWriteExt}; +use tokio::process::Command; use tokio::sync::Notify; +use tokio_tungstenite::tungstenite::protocol::frame::coding::CloseCode; use ts_rs::TS; use crate::context::{CliContext, RpcContext}; @@ -24,24 +38,23 @@ use crate::install::PKG_ARCHIVE_DIR; use crate::lxc::ContainerId; use crate::prelude::*; use crate::progress::{NamedProgress, Progress}; -use crate::rpc_continuations::Guid; +use crate::rpc_continuations::{Guid, RpcContinuation}; use crate::s9pk::S9pk; +use crate::service::action::update_requested_actions; use crate::service::service_map::InstallProgressHandles; -use crate::status::health_check::NamedHealthCheckResult; use crate::util::actor::concurrent::ConcurrentActor; -use crate::util::io::create_file; +use crate::util::io::{create_file, AsyncReadStream}; +use crate::util::net::WebSocketExt; use crate::util::serde::{NoOutput, Pem}; use crate::util::Never; use crate::volume::data_dir; +use crate::CAP_1_KiB; -mod action; +pub mod action; pub mod cli; -mod config; mod control; -mod dependencies; pub mod effects; pub mod persistent_container; -mod properties; mod rpc; mod service_actor; pub mod service_map; @@ -68,6 +81,34 @@ pub enum LoadDisposition { Undo, } +struct RootCommand(pub String); + +#[derive(Clone, Debug, Serialize, Deserialize, Default, TS)] +pub struct MiB(pub u64); + +impl MiB { + fn new(value: u64) -> Self { + Self(value / 1024 / 1024) + } + fn from_MiB(value: u64) -> Self { + Self(value) + } +} + +impl std::fmt::Display for MiB { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{} MiB", self.0) + } +} + +#[derive(Clone, Debug, Serialize, Deserialize, Default, TS)] +pub struct ServiceStats { + pub container_id: Arc, + pub package_id: PackageId, + pub memory_usage: MiB, + pub memory_limit: MiB, +} + pub struct ServiceRef(Arc); impl ServiceRef { pub fn weak(&self) -> Weak { @@ -81,7 +122,7 @@ impl ServiceRef { .persistent_container .execute::( Guid::new(), - ProcedureName::Uninit, + ProcedureName::PackageUninit, to_value(&target_version)?, None, ) // TODO timeout @@ -116,6 +157,7 @@ impl ServiceRef { ); Ok(()) })?; + d.as_private_mut().as_package_stores_mut().remove(&id)?; Ok(Some(pde)) } else { Ok(None) @@ -183,7 +225,7 @@ impl ServiceRef { impl Deref for ServiceRef { type Target = Service; fn deref(&self) -> &Self::Target { - &*self.0 + &self.0 } } impl From for ServiceRef { @@ -241,7 +283,7 @@ impl Service { tokio::fs::create_dir_all(&path).await?; } } - let start_stop = if i.as_status().as_main().de()?.running() { + let start_stop = if i.as_status().de()?.running() { StartStop::Start } else { StartStop::Stop @@ -354,7 +396,7 @@ impl Service { tracing::debug!("{e:?}") }) { - match ServiceRef::from(service).uninstall(None).await { + match service.uninstall(None).await { Err(e) => { tracing::error!("Error uninstalling service: {e}"); tracing::debug!("{e:?}") @@ -392,6 +434,7 @@ impl Service { let developer_key = s9pk.as_archive().signer(); let icon = s9pk.icon_data_url().await?; let service = Self::new(ctx.clone(), s9pk, StartStop::Stop).await?; + if let Some(recovery_source) = recovery_source { service .actor @@ -413,32 +456,79 @@ impl Service { .clone(), ); } + + let procedure_id = Guid::new(); service .seed .persistent_container .execute::( - Guid::new(), - ProcedureName::Init, + procedure_id.clone(), + ProcedureName::PackageInit, to_value(&src_version)?, None, ) // TODO timeout .await .with_kind(ErrorKind::MigrationFailed)?; // TODO: handle cancellation + if let Some(mut progress) = progress { progress.finalization_progress.complete(); progress.progress.complete(); tokio::task::yield_now().await; } + + let peek = ctx.db.peek().await; + let mut action_input: BTreeMap = BTreeMap::new(); + let requested_actions: BTreeSet<_> = peek + .as_public() + .as_package_data() + .as_entries()? + .into_iter() + .map(|(_, pde)| { + Ok(pde + .as_requested_actions() + .as_entries()? + .into_iter() + .map(|(_, r)| { + Ok::<_, Error>(if r.as_request().as_package_id().de()? == manifest.id { + Some(r.as_request().as_action_id().de()?) + } else { + None + }) + }) + .filter_map_ok(|a| a)) + }) + .flatten_ok() + .map(|a| a.and_then(|a| a)) + .try_collect()?; + for action_id in requested_actions { + if let Some(input) = service + .get_action_input(procedure_id.clone(), action_id.clone()) + .await? + .and_then(|i| i.value) + { + action_input.insert(action_id, input); + } + } ctx.db - .mutate(|d| { - let entry = d + .mutate(|db| { + for (action_id, input) in &action_input { + for (_, pde) in db.as_public_mut().as_package_data_mut().as_entries_mut()? { + pde.as_requested_actions_mut().mutate(|requested_actions| { + Ok(update_requested_actions( + requested_actions, + &manifest.id, + action_id, + input, + false, + )) + })?; + } + } + let entry = db .as_public_mut() .as_package_data_mut() .as_idx_mut(&manifest.id) .or_not_found(&manifest.id)?; - if !manifest.has_config { - entry.as_status_mut().as_configured_mut().ser(&true)?; - } entry .as_state_info_mut() .ser(&PackageState::Installed(InstalledState { manifest }))?; @@ -489,6 +579,54 @@ impl Service { .clone(); Ok(container_id) } + #[instrument(skip_all)] + pub async fn stats(&self) -> Result { + let container = &self.seed.persistent_container; + let lxc_container = container.lxc_container.get().or_not_found("container")?; + let (total, used) = lxc_container + .command(&["free", "-m"]) + .await? + .split("\n") + .map(|x| x.split_whitespace().collect::>()) + .skip(1) + .filter_map(|x| { + Some(( + x.get(1)?.parse::().ok()?, + x.get(2)?.parse::().ok()?, + )) + }) + .fold((0, 0), |acc, (total, used)| (acc.0 + total, acc.1 + used)); + Ok(ServiceStats { + container_id: lxc_container.guid.clone(), + package_id: self.seed.id.clone(), + memory_limit: MiB::from_MiB(total), + memory_usage: MiB::from_MiB(used), + }) + } + + pub async fn update_host(&self, host_id: HostId) -> Result<(), Error> { + let host = self + .seed + .ctx + .db + .peek() + .await + .as_public() + .as_package_data() + .as_idx(&self.seed.id) + .or_not_found(&self.seed.id)? + .as_hosts() + .as_idx(&host_id) + .or_not_found(&host_id)? + .de()?; + self.seed + .persistent_container + .net_service + .lock() + .await + .update(host_id, host) + .await + } } #[derive(Debug, Clone)] @@ -528,6 +666,15 @@ impl ServiceActorSeed { } } +#[derive(Deserialize, Serialize, Parser, TS)] +pub struct RebuildParams { + pub id: PackageId, +} +pub async fn rebuild(ctx: RpcContext, RebuildParams { id }: RebuildParams) -> Result<(), Error> { + ctx.services.load(&ctx, &id, LoadDisposition::Retry).await?; + Ok(()) +} + #[derive(Deserialize, Serialize, Parser, TS)] pub struct ConnectParams { pub id: PackageId, @@ -578,3 +725,488 @@ pub async fn connect_rpc_cli( crate::lxc::connect_cli(&ctx, guid).await } + +#[derive(Deserialize, Serialize, TS)] +#[serde(rename_all = "camelCase")] +pub struct AttachParams { + pub id: PackageId, + #[ts(type = "string[]")] + pub command: Vec, + pub tty: bool, + #[ts(skip)] + #[serde(rename = "__auth_session")] + session: Option, + #[ts(type = "string | null")] + subcontainer: Option, + #[ts(type = "string | null")] + name: Option, + #[ts(type = "string | null")] + image_id: Option, +} +pub async fn attach( + ctx: RpcContext, + AttachParams { + id, + command, + tty, + session, + subcontainer, + image_id, + name, + }: AttachParams, +) -> Result { + let (container_id, subcontainer_id, image_id, workdir, root_command) = { + let id = &id; + + let service = ctx.services.get(id).await; + + let service_ref = service.as_ref().or_not_found(id)?; + + let container = &service_ref.seed.persistent_container; + let root_dir = container + .lxc_container + .get() + .map(|x| x.rootfs_dir().to_owned()) + .or_not_found(format!("container for {id}"))?; + + let subcontainer = subcontainer.map(|x| AsRef::::as_ref(&x).to_uppercase()); + let name = name.map(|x| AsRef::::as_ref(&x).to_uppercase()); + let image_id = image_id.map(|x| AsRef::::as_ref(&x).to_string_lossy().to_uppercase()); + + let subcontainers = container.subcontainers.lock().await; + let subcontainer_ids: Vec<_> = subcontainers + .iter() + .filter(|(x, wrapper)| { + if let Some(subcontainer) = subcontainer.as_ref() { + AsRef::::as_ref(x).contains(AsRef::::as_ref(subcontainer)) + } else if let Some(name) = name.as_ref() { + AsRef::::as_ref(&wrapper.name) + .to_uppercase() + .contains(AsRef::::as_ref(name)) + } else if let Some(image_id) = image_id.as_ref() { + let Some(wrapper_image_id) = AsRef::::as_ref(&wrapper.image_id).to_str() + else { + return false; + }; + wrapper_image_id + .to_uppercase() + .contains(AsRef::::as_ref(&image_id)) + } else { + true + } + }) + .collect(); + let format_subcontainer_pair = |(guid, wrapper): (&Guid, &Subcontainer)| { + format!( + "{guid} imageId: {image_id} name: \"{name}\"", + name = &wrapper.name, + image_id = &wrapper.image_id + ) + }; + let Some((subcontainer_id, image_id)) = subcontainer_ids + .first() + .map::<(Guid, ImageId), _>(|&x| (x.0.clone(), x.1.image_id.clone())) + else { + drop(subcontainers); + let subcontainers = container + .subcontainers + .lock() + .await + .iter() + .map(format_subcontainer_pair) + .join("\n"); + return Err(Error::new( + eyre!("no matching subcontainers are running for {id}; some possible choices are:\n{subcontainers}"), + ErrorKind::NotFound, + )); + }; + + let passwd = root_dir + .join("media/startos/subcontainers") + .join(subcontainer_id.as_ref()) + .join("etc") + .join("passwd"); + + let root_command = get_passwd_root_command(passwd).await; + + let workdir = attach_workdir(&image_id, &root_dir).await?; + + if subcontainer_ids.len() > 1 { + let subcontainer_ids = subcontainer_ids + .into_iter() + .map(format_subcontainer_pair) + .join("\n"); + return Err(Error::new( + eyre!("multiple subcontainers found for {id}: \n{subcontainer_ids}"), + ErrorKind::InvalidRequest, + )); + } + + ( + service_ref.container_id()?, + subcontainer_id, + image_id, + workdir, + root_command, + ) + }; + + let guid = Guid::new(); + async fn handler( + ws: &mut WebSocket, + container_id: ContainerId, + subcontainer_id: Guid, + command: Vec, + tty: bool, + image_id: ImageId, + workdir: Option, + root_command: &RootCommand, + ) -> Result<(), Error> { + use axum::extract::ws::Message; + + let mut ws = ws.fuse(); + + let mut cmd = Command::new("lxc-attach"); + let root_path = Path::new("/media/startos/subcontainers").join(subcontainer_id.as_ref()); + cmd.kill_on_drop(true); + + cmd.arg(&*container_id) + .arg("--") + .arg("start-cli") + .arg("subcontainer") + .arg("exec") + .arg("--env") + .arg( + Path::new("/media/startos/images") + .join(image_id) + .with_extension("env"), + ); + + if let Some(workdir) = workdir { + cmd.arg("--workdir").arg(workdir); + } + + if tty { + cmd.arg("--force-tty"); + } + + cmd.arg(&root_path).arg("--"); + + if command.is_empty() { + cmd.arg(&root_command.0); + } else { + cmd.args(&command); + } + + let mut child = cmd + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn()?; + + let pid = nix::unistd::Pid::from_raw(child.id().or_not_found("child pid")? as i32); + + let mut stdin = child.stdin.take().or_not_found("child stdin")?; + + let mut current_in = "stdin".to_owned(); + let mut current_out = "stdout"; + ws.send(Message::Text(current_out.into())) + .await + .with_kind(ErrorKind::Network)?; + let mut stdout = AsyncReadStream::new( + child.stdout.take().or_not_found("child stdout")?, + 4 * CAP_1_KiB, + ) + .fuse(); + let mut stderr = AsyncReadStream::new( + child.stderr.take().or_not_found("child stderr")?, + 4 * CAP_1_KiB, + ) + .fuse(); + + loop { + futures::select_biased! { + out = stdout.try_next() => { + if let Some(out) = out? { + if current_out != "stdout" { + ws.send(Message::Text("stdout".into())) + .await + .with_kind(ErrorKind::Network)?; + current_out = "stdout"; + } + dbg!(¤t_out); + ws.send(Message::Binary(out)) + .await + .with_kind(ErrorKind::Network)?; + } + } + err = stderr.try_next() => { + if let Some(err) = err? { + if current_out != "stderr" { + ws.send(Message::Text("stderr".into())) + .await + .with_kind(ErrorKind::Network)?; + current_out = "stderr"; + } + dbg!(¤t_out); + ws.send(Message::Binary(err)) + .await + .with_kind(ErrorKind::Network)?; + } + } + msg = ws.try_next() => { + if let Some(msg) = msg.with_kind(ErrorKind::Network)? { + match msg { + Message::Text(in_ty) => { + current_in = in_ty; + } + Message::Binary(data) => { + match &*current_in { + "stdin" => { + stdin.write_all(&data).await?; + } + "signal" => { + if data.len() != 4 { + return Err(Error::new( + eyre!("invalid byte length for signal: {}", data.len()), + ErrorKind::InvalidRequest + )); + } + let mut sig_buf = [0u8; 4]; + sig_buf.clone_from_slice(&data); + nix::sys::signal::kill( + pid, + Signal::try_from(i32::from_be_bytes(sig_buf)) + .with_kind(ErrorKind::InvalidRequest)? + ).with_kind(ErrorKind::Filesystem)?; + } + _ => (), + } + } + _ => () + } + } else { + return Ok(()) + } + } + } + if stdout.is_terminated() && stderr.is_terminated() { + break; + } + } + + let exit = child.wait().await?; + ws.send(Message::Text("exit".into())) + .await + .with_kind(ErrorKind::Network)?; + ws.send(Message::Binary(i32::to_be_bytes(exit.into_raw()).to_vec())) + .await + .with_kind(ErrorKind::Network)?; + + Ok(()) + } + ctx.rpc_continuations + .add( + guid.clone(), + RpcContinuation::ws_authed( + &ctx, + session, + move |mut ws| async move { + if let Err(e) = handler( + &mut ws, + container_id, + subcontainer_id, + command, + tty, + image_id, + workdir, + &root_command, + ) + .await + { + tracing::error!("Error in attach websocket: {e}"); + tracing::debug!("{e:?}"); + ws.close_result(Err::<&str, _>(e)).await.log_err(); + } else { + ws.normal_close("exit").await.log_err(); + } + }, + Duration::from_secs(30), + ), + ) + .await; + + Ok(guid) +} + +async fn attach_workdir(image_id: &ImageId, root_dir: &Path) -> Result, Error> { + let path_str = root_dir.join("media/startos/images/"); + + let mut subcontainer_json = + tokio::fs::File::open(path_str.join(image_id).with_extension("json")).await?; + let mut contents = vec![]; + subcontainer_json.read_to_end(&mut contents).await?; + let subcontainer_json: serde_json::Value = + serde_json::from_slice(&contents).with_kind(ErrorKind::Filesystem)?; + Ok(subcontainer_json["workdir"].as_str().map(|x| x.to_string())) +} + +async fn get_passwd_root_command(etc_passwd_path: PathBuf) -> RootCommand { + async { + let mut file = tokio::fs::File::open(etc_passwd_path).await?; + + let mut contents = vec![]; + file.read_to_end(&mut contents).await?; + + let contents = String::from_utf8_lossy(&contents); + + for line in contents.split('\n') { + let line_information = line.split(':').collect::>(); + if let (Some(&"root"), Some(shell)) = + (line_information.first(), line_information.last()) + { + return Ok(shell.to_string()); + } + } + Err(Error::new( + eyre!("Could not parse /etc/passwd for shell: {}", contents), + ErrorKind::Filesystem, + )) + } + .await + .map(RootCommand) + .unwrap_or_else(|e| { + tracing::error!("Could not get the /etc/passwd: {e}"); + tracing::debug!("{e:?}"); + RootCommand("/bin/sh".to_string()) + }) +} + +#[derive(Deserialize, Serialize, Parser)] +pub struct CliAttachParams { + pub id: PackageId, + #[arg(long)] + pub force_tty: bool, + #[arg(trailing_var_arg = true)] + pub command: Vec, + #[arg(long, short)] + subcontainer: Option, + #[arg(long, short)] + name: Option, + #[arg(long, short)] + image_id: Option, +} +pub async fn cli_attach( + HandlerArgs { + context, + parent_method, + method, + params, + .. + }: HandlerArgs, +) -> Result<(), Error> { + use tokio_tungstenite::tungstenite::Message; + + let guid: Guid = from_value( + context + .call_remote::( + &parent_method.into_iter().chain(method).join("."), + json!({ + "id": params.id, + "command": params.command, + "tty": (std::io::stdin().is_terminal() + && std::io::stdout().is_terminal() + && std::io::stderr().is_terminal()) + || params.force_tty, + "subcontainer": params.subcontainer, + "imageId": params.image_id, + "name": params.name, + }), + ) + .await?, + )?; + let mut ws = context.ws_continuation(guid).await?; + + let mut current_in = "stdin"; + let mut current_out = "stdout".to_owned(); + ws.send(Message::Text(current_in.into())) + .await + .with_kind(ErrorKind::Network)?; + let mut stdin = AsyncReadStream::new(tokio::io::stdin(), 4 * CAP_1_KiB).fuse(); + let mut stdout = tokio::io::stdout(); + let mut stderr = tokio::io::stderr(); + loop { + futures::select_biased! { + // signal = tokio:: => { + // let exit = exit?; + // if current_out != "exit" { + // ws.send(Message::Text("exit".into())) + // .await + // .with_kind(ErrorKind::Network)?; + // current_out = "exit"; + // } + // ws.send(Message::Binary( + // i32::to_be_bytes(exit.into_raw()).to_vec() + // )).await.with_kind(ErrorKind::Network)?; + // } + input = stdin.try_next() => { + if let Some(input) = input? { + if current_in != "stdin" { + ws.send(Message::Text("stdin".into())) + .await + .with_kind(ErrorKind::Network)?; + current_in = "stdin"; + } + ws.send(Message::Binary(input)) + .await + .with_kind(ErrorKind::Network)?; + } + } + msg = ws.try_next() => { + if let Some(msg) = msg.with_kind(ErrorKind::Network)? { + match msg { + Message::Text(out_ty) => { + current_out = out_ty; + } + Message::Binary(data) => { + match &*current_out { + "stdout" => { + stdout.write_all(&data).await?; + stdout.flush().await?; + } + "stderr" => { + stderr.write_all(&data).await?; + stderr.flush().await?; + } + "exit" => { + if data.len() != 4 { + return Err(Error::new( + eyre!("invalid byte length for exit code: {}", data.len()), + ErrorKind::InvalidRequest + )); + } + let mut exit_buf = [0u8; 4]; + exit_buf.clone_from_slice(&data); + let code = i32::from_be_bytes(exit_buf); + std::process::exit(code); + } + _ => (), + } + } + Message::Close(Some(close)) => { + if close.code != CloseCode::Normal { + return Err(Error::new( + color_eyre::eyre::Report::msg(close.reason), + ErrorKind::Network + )); + } + } + _ => () + } + } else { + return Ok(()) + } + } + } + } +} diff --git a/core/startos/src/service/persistent_container.rs b/core/startos/src/service/persistent_container.rs index dd7b5766d..13cb7688c 100644 --- a/core/startos/src/service/persistent_container.rs +++ b/core/startos/src/service/persistent_container.rs @@ -1,12 +1,14 @@ use std::collections::{BTreeMap, BTreeSet}; +use std::ops::Deref; use std::path::Path; use std::sync::{Arc, Weak}; use std::time::Duration; use futures::future::ready; -use futures::{Future, FutureExt}; +use futures::Future; use helpers::NonDetachingJoinHandle; use imbl::Vector; +use imbl_value::InternedString; use models::{ImageId, ProcedureName, VolumeId}; use rpc_toolkit::{Empty, Server, ShutdownHandle}; use serde::de::DeserializeOwned; @@ -36,7 +38,7 @@ use crate::service::{rpc, RunningStatus, Service}; use crate::util::io::create_file; use crate::util::rpc_client::UnixRpcClient; use crate::util::Invoke; -use crate::volume::{asset_dir, data_dir}; +use crate::volume::data_dir; use crate::ARCH; const RPC_CONNECT_TIMEOUT: Duration = Duration::from_secs(10); @@ -84,6 +86,14 @@ impl ServiceState { } } +/// Want to have a wrapper for uses like the inject where we are going to be finding the subcontainer and doing some filtering on it. +/// As well, the imageName is also used for things like env. +pub struct Subcontainer { + pub(super) name: InternedString, + pub(super) image_id: ImageId, + pub(super) overlay: OverlayGuard>, +} + // @DRB On top of this we need to also have the procedures to have the effects and get the results back for them, maybe lock them to the running instance? /// This contains the LXC container running the javascript init system /// that can be used via a JSON RPC Client connected to a unix domain @@ -98,7 +108,7 @@ pub struct PersistentContainer { volumes: BTreeMap, assets: BTreeMap, pub(super) images: BTreeMap>, - pub(super) subcontainers: Arc>>>>, + pub(super) subcontainers: Arc>>, pub(super) state: Arc>, pub(super) net_service: Mutex, destroyed: bool, @@ -378,7 +388,10 @@ impl PersistentContainer { } #[instrument(skip_all)] - fn destroy(&mut self) -> Option> + 'static> { + fn destroy( + &mut self, + error: bool, + ) -> Option> + 'static> { if self.destroyed { return None; } @@ -393,6 +406,24 @@ impl PersistentContainer { self.destroyed = true; Some(async move { let mut errs = ErrorCollection::new(); + if error { + if let Some(lxc_container) = &lxc_container { + if let Some(logs) = errs.handle( + crate::logs::fetch_logs( + crate::logs::LogSource::Container(lxc_container.guid.deref().clone()), + Some(50), + None, + None, + false, + ) + .await, + ) { + for log in logs.entries.iter() { + eprintln!("{log}"); + } + } + } + } if let Some((hdl, shutdown)) = rpc_server { errs.handle(rpc_client.request(rpc::Exit, Empty {}).await); shutdown.shutdown(); @@ -405,7 +436,7 @@ impl PersistentContainer { errs.handle(assets.unmount(true).await); } for (_, overlay) in std::mem::take(&mut *subcontainers.lock().await) { - errs.handle(overlay.unmount(true).await); + errs.handle(overlay.overlay.unmount(true).await); } for (_, images) in images { errs.handle(images.unmount().await); @@ -420,7 +451,7 @@ impl PersistentContainer { #[instrument(skip_all)] pub async fn exit(mut self) -> Result<(), Error> { - if let Some(destroy) = self.destroy() { + if let Some(destroy) = self.destroy(false) { dbg!(destroy.await)?; } tracing::info!("Service for {} exited", self.s9pk.as_manifest().id); @@ -538,8 +569,8 @@ impl PersistentContainer { impl Drop for PersistentContainer { fn drop(&mut self) { - if let Some(destroy) = self.destroy() { - tokio::spawn(async move { destroy.await.unwrap() }); + if let Some(destroy) = self.destroy(true) { + tokio::spawn(async move { destroy.await.log_err() }); } } } diff --git a/core/startos/src/service/properties.rs b/core/startos/src/service/properties.rs deleted file mode 100644 index 3f5201f1d..000000000 --- a/core/startos/src/service/properties.rs +++ /dev/null @@ -1,23 +0,0 @@ -use std::time::Duration; - -use models::ProcedureName; - -use crate::prelude::*; -use crate::rpc_continuations::Guid; -use crate::service::Service; - -impl Service { - // TODO: leave here or switch to Actor Message? - pub async fn properties(&self) -> Result { - let container = &self.seed.persistent_container; - container - .execute::( - Guid::new(), - ProcedureName::Properties, - Value::Null, - Some(Duration::from_secs(30)), - ) - .await - .with_kind(ErrorKind::Unknown) - } -} diff --git a/core/startos/src/service/rpc.rs b/core/startos/src/service/rpc.rs index 25d8fb067..f008de5c7 100644 --- a/core/startos/src/service/rpc.rs +++ b/core/startos/src/service/rpc.rs @@ -1,10 +1,12 @@ use std::collections::BTreeSet; +use std::str::FromStr; use std::sync::{Arc, Weak}; use std::time::Duration; +use clap::builder::ValueParserFactory; use imbl::Vector; use imbl_value::Value; -use models::ProcedureName; +use models::{FromStrParser, ProcedureName}; use rpc_toolkit::yajrc::RpcMethod; use rpc_toolkit::Empty; use ts_rs::TS; @@ -153,6 +155,11 @@ impl serde::Serialize for Sandbox { pub struct CallbackId(u64); impl CallbackId { pub fn register(self, container: &PersistentContainer) -> CallbackHandle { + dbg!(eyre!( + "callback {} registered for {}", + self.0, + container.s9pk.as_manifest().id + )); let this = Arc::new(self); let res = Arc::downgrade(&this); container @@ -161,6 +168,18 @@ impl CallbackId { CallbackHandle(res) } } +impl FromStr for CallbackId { + type Err = Error; + fn from_str(s: &str) -> Result { + u64::from_str(s).map_err(Error::from).map(Self) + } +} +impl ValueParserFactory for CallbackId { + type Parser = FromStrParser; + fn value_parser() -> Self::Parser { + FromStrParser::new() + } +} pub struct CallbackHandle(Weak); impl CallbackHandle { diff --git a/core/startos/src/service/service_actor.rs b/core/startos/src/service/service_actor.rs index 0839afc0b..712baaf1e 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 imbl::vector; + use super::start_stop::StartStop; use super::ServiceActorSeed; use crate::prelude::*; @@ -45,11 +47,12 @@ async fn service_actor_loop( let id = &seed.id; let kinds = current.borrow().kinds(); if let Err(e) = async { - seed.ctx + 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().as_main().de()?; + let previous = i.as_status().de()?; let main_status = match &kinds { ServiceStateKinds { transition_state: Some(TransitionKind::Restarting), @@ -89,11 +92,22 @@ async fn service_actor_loop( .. } => MainStatus::Stopped, }; - i.as_status_mut().as_main_mut().ser(&main_status)?; + let previous = i.as_status().de()?; + i.as_status_mut().ser(&main_status)?; + return Ok(previous + .major_changes(&main_status) + .then_some((previous, main_status))); } - Ok(()) + Ok(None) }) .await?; + 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 { diff --git a/core/startos/src/service/service_map.rs b/core/startos/src/service/service_map.rs index 0e6a959ae..0faab8dd5 100644 --- a/core/startos/src/service/service_map.rs +++ b/core/startos/src/service/service_map.rs @@ -7,6 +7,7 @@ use futures::{Future, FutureExt}; use helpers::NonDetachingJoinHandle; use imbl::OrdMap; use imbl_value::InternedString; +use models::ErrorData; use tokio::sync::{Mutex, OwnedRwLockReadGuard, OwnedRwLockWriteGuard, RwLock}; use tracing::instrument; @@ -22,8 +23,9 @@ use crate::progress::{FullProgressTracker, PhaseProgressTrackerHandle, ProgressT use crate::s9pk::manifest::PackageId; use crate::s9pk::merkle_archive::source::FileSource; use crate::s9pk::S9pk; +use crate::service::start_stop::StartStop; use crate::service::{LoadDisposition, Service, ServiceRef}; -use crate::status::{MainStatus, Status}; +use crate::status::MainStatus; use crate::util::serde::Pem; pub type DownloadInstallFuture = BoxFuture<'static, Result>; @@ -87,8 +89,30 @@ impl ServiceMap { if let Some(service) = service.take() { shutdown_err = service.shutdown().await; } - // TODO: retry on error? - *service = Service::load(ctx, id, disposition).await?.map(From::from); + match Service::load(ctx, id, disposition).await { + Ok(s) => *service = s.into(), + Err(e) => { + let e = ErrorData::from(e); + ctx.db + .mutate(|db| { + if let Some(pde) = db.as_public_mut().as_package_data_mut().as_idx_mut(id) { + pde.as_status_mut().map_mutate(|s| { + Ok(MainStatus::Error { + on_rebuild: if s.running() { + StartStop::Start + } else { + StartStop::Stop + }, + message: e.details, + debug: Some(e.debug), + }) + })?; + } + Ok(()) + }) + .await?; + } + } shutdown_err?; Ok(()) } @@ -174,16 +198,14 @@ impl ServiceMap { PackageState::Installing(installing) }, data_version: None, - status: Status { - configured: false, - main: MainStatus::Stopped, - }, + status: MainStatus::Stopped, registry: None, developer_key: Pem::new(developer_key), icon, last_backup: None, current_dependencies: Default::default(), actions: Default::default(), + requested_actions: Default::default(), service_interfaces: Default::default(), hosts: Default::default(), store_exposed_dependents: Default::default(), @@ -285,7 +307,6 @@ impl ServiceMap { sync_progress_task.await.map_err(|_| { Error::new(eyre!("progress sync task panicked"), ErrorKind::Unknown) })??; - Ok(()) }) .boxed()) diff --git a/core/startos/src/service/transition/backup.rs b/core/startos/src/service/transition/backup.rs index d8606f534..0d4116078 100644 --- a/core/startos/src/service/transition/backup.rs +++ b/core/startos/src/service/transition/backup.rs @@ -9,8 +9,7 @@ use super::TempDesiredRestore; use crate::disk::mount::filesystem::ReadWrite; use crate::prelude::*; use crate::rpc_continuations::Guid; -use crate::service::config::GetConfig; -use crate::service::dependencies::DependencyConfig; +use crate::service::action::GetActionInput; use crate::service::transition::{TransitionKind, TransitionState}; use crate::service::ServiceActor; use crate::util::actor::background::BackgroundJobQueue; @@ -23,9 +22,7 @@ pub(in crate::service) struct Backup { impl Handler for ServiceActor { type Response = Result>, Error>; fn conflicts_with(_: &Backup) -> ConflictBuilder { - ConflictBuilder::everything() - .except::() - .except::() + ConflictBuilder::everything().except::() } async fn handle( &mut self, diff --git a/core/startos/src/service/transition/restart.rs b/core/startos/src/service/transition/restart.rs index 108e232ad..27bef0b91 100644 --- a/core/startos/src/service/transition/restart.rs +++ b/core/startos/src/service/transition/restart.rs @@ -3,8 +3,7 @@ use futures::FutureExt; use super::TempDesiredRestore; use crate::prelude::*; use crate::rpc_continuations::Guid; -use crate::service::config::GetConfig; -use crate::service::dependencies::DependencyConfig; +use crate::service::action::GetActionInput; use crate::service::transition::{TransitionKind, TransitionState}; use crate::service::{Service, ServiceActor}; use crate::util::actor::background::BackgroundJobQueue; @@ -15,9 +14,7 @@ pub(super) struct Restart; impl Handler for ServiceActor { type Response = (); fn conflicts_with(_: &Restart) -> ConflictBuilder { - ConflictBuilder::everything() - .except::() - .except::() + ConflictBuilder::everything().except::() } async fn handle(&mut self, _: Guid, _: Restart, jobs: &BackgroundJobQueue) -> Self::Response { // So Need a handle to just a single field in the state diff --git a/core/startos/src/setup.rs b/core/startos/src/setup.rs index 642dd5476..1319ffae4 100644 --- a/core/startos/src/setup.rs +++ b/core/startos/src/setup.rs @@ -10,6 +10,7 @@ use rpc_toolkit::yajrc::RpcError; use rpc_toolkit::{from_fn_async, Context, HandlerExt, ParentHandler}; use serde::{Deserialize, Serialize}; use tokio::io::AsyncWriteExt; +use tokio::process::Command; use tokio::try_join; use tracing::instrument; use ts_rs::TS; @@ -36,6 +37,7 @@ use crate::progress::{FullProgress, PhaseProgressTrackerHandle}; use crate::rpc_continuations::Guid; use crate::util::crypto::EncryptedWire; use crate::util::io::{create_file, dir_copy, dir_size, Counter}; +use crate::util::Invoke; use crate::{Error, ErrorKind, ResultExt}; pub fn setup() -> ParentHandler { @@ -336,6 +338,11 @@ pub async fn complete(ctx: SetupContext) -> Result { let mut guid_file = create_file("/media/startos/config/disk.guid").await?; guid_file.write_all(ctx.disk_guid.as_bytes()).await?; guid_file.sync_all().await?; + Command::new("systemd-firstboot") + .arg("--root=/media/startos/config/overlay/") + .arg(format!("--hostname={}", res.hostname.0)) + .invoke(ErrorKind::ParseSysInfo) + .await?; Ok(res.clone()) } Some(Err(e)) => Err(e.clone_output()), diff --git a/core/startos/src/ssh.rs b/core/startos/src/ssh.rs index b97fba3e4..afc5a5bf1 100644 --- a/core/startos/src/ssh.rs +++ b/core/startos/src/ssh.rs @@ -5,6 +5,7 @@ use clap::builder::ValueParserFactory; use clap::Parser; use color_eyre::eyre::eyre; use imbl_value::InternedString; +use models::FromStrParser; use rpc_toolkit::{from_fn_async, Context, Empty, HandlerExt, ParentHandler}; use serde::{Deserialize, Serialize}; use tracing::instrument; @@ -12,7 +13,6 @@ use ts_rs::TS; use crate::context::{CliContext, RpcContext}; use crate::prelude::*; -use crate::util::clap::FromStrParser; use crate::util::io::create_file; use crate::util::serde::{display_serializable, HandlerExtSerde, WithIoFormat}; @@ -25,6 +25,12 @@ impl SshKeys { Self(BTreeMap::new()) } } + +impl From>> for SshKeys { + fn from(map: BTreeMap>) -> Self { + Self(map) + } +} impl Map for SshKeys { type Key = InternedString; type Value = WithTimeData; @@ -41,7 +47,7 @@ impl Map for SshKeys { pub struct SshPubKey( #[serde(serialize_with = "crate::util::serde::serialize_display")] #[serde(deserialize_with = "crate::util::serde::deserialize_from_str")] - openssh_keys::PublicKey, + pub openssh_keys::PublicKey, ); impl ValueParserFactory for SshPubKey { type Parser = FromStrParser; @@ -86,12 +92,14 @@ pub fn ssh() -> ParentHandler { "add", from_fn_async(add) .no_display() + .with_about("Add ssh key") .with_call_remote::(), ) .subcommand( "delete", from_fn_async(delete) .no_display() + .with_about("Remove ssh key") .with_call_remote::(), ) .subcommand( @@ -101,6 +109,7 @@ pub fn ssh() -> ParentHandler { .with_custom_display_fn(|handle, result| { Ok(display_all_ssh_keys(handle.params, result)) }) + .with_about("List ssh keys") .with_call_remote::(), ) } diff --git a/core/startos/src/status/health_check.rs b/core/startos/src/status/health_check.rs index 1b1e2a7b6..861954d29 100644 --- a/core/startos/src/status/health_check.rs +++ b/core/startos/src/status/health_check.rs @@ -1,12 +1,11 @@ use std::str::FromStr; use clap::builder::ValueParserFactory; +use models::FromStrParser; pub use models::HealthCheckId; use serde::{Deserialize, Serialize}; use ts_rs::TS; -use crate::util::clap::FromStrParser; - #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, TS)] #[serde(rename_all = "camelCase")] pub struct NamedHealthCheckResult { diff --git a/core/startos/src/status/mod.rs b/core/startos/src/status/mod.rs index c10a7b89f..398797a5a 100644 --- a/core/startos/src/status/mod.rs +++ b/core/startos/src/status/mod.rs @@ -11,20 +11,17 @@ use crate::service::start_stop::StartStop; use crate::status::health_check::NamedHealthCheckResult; pub mod health_check; -#[derive(Clone, Debug, Deserialize, Serialize, HasModel, TS)] -#[serde(rename_all = "camelCase")] -#[model = "Model"] -#[ts(export)] -pub struct Status { - pub configured: bool, - pub main: MainStatus, -} #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, TS)] -#[serde(tag = "status")] +#[serde(tag = "main")] #[serde(rename_all = "camelCase")] #[serde(rename_all_fields = "camelCase")] pub enum MainStatus { + Error { + on_rebuild: StartStop, + message: String, + debug: Option, + }, Stopped, Restarting, Restoring, @@ -51,16 +48,38 @@ impl MainStatus { | MainStatus::Restarting | MainStatus::BackingUp { on_complete: StartStop::Start, + } + | MainStatus::Error { + on_rebuild: StartStop::Start, + .. } => true, MainStatus::Stopped | MainStatus::Restoring | MainStatus::Stopping { .. } | MainStatus::BackingUp { on_complete: StartStop::Stop, + } + | MainStatus::Error { + on_rebuild: StartStop::Stop, + .. } => false, } } + pub fn major_changes(&self, other: &Self) -> bool { + match (self, other) { + (MainStatus::Running { .. }, MainStatus::Running { .. }) => false, + (MainStatus::Starting { .. }, MainStatus::Starting { .. }) => false, + (MainStatus::Stopping, MainStatus::Stopping) => false, + (MainStatus::Stopped, MainStatus::Stopped) => false, + (MainStatus::Restarting, MainStatus::Restarting) => false, + (MainStatus::Restoring, MainStatus::Restoring) => false, + (MainStatus::BackingUp { .. }, MainStatus::BackingUp { .. }) => false, + (MainStatus::Error { .. }, MainStatus::Error { .. }) => false, + _ => true, + } + } + pub fn backing_up(self) -> Self { MainStatus::BackingUp { on_complete: if self.running() { @@ -78,7 +97,8 @@ impl MainStatus { | MainStatus::Stopped | MainStatus::Restoring | MainStatus::Stopping { .. } - | MainStatus::Restarting => None, + | MainStatus::Restarting + | MainStatus::Error { .. } => None, } } } diff --git a/core/startos/src/system.rs b/core/startos/src/system.rs index 7af94588b..e64f30e98 100644 --- a/core/startos/src/system.rs +++ b/core/startos/src/system.rs @@ -31,6 +31,7 @@ pub fn experimental() -> ParentHandler { "zram", from_fn_async(zram) .no_display() + .with_about("Enable zram") .with_call_remote::(), ) .subcommand( @@ -40,6 +41,7 @@ pub fn experimental() -> ParentHandler { .with_custom_display_fn(|handle, result| { Ok(display_governor_info(handle.params, result)) }) + .with_about("Show current and available CPU governors") .with_call_remote::(), ) } diff --git a/core/startos/src/upload.rs b/core/startos/src/upload.rs index 20f294400..73519c603 100644 --- a/core/startos/src/upload.rs +++ b/core/startos/src/upload.rs @@ -25,7 +25,7 @@ use crate::util::io::{create_file, TmpDir}; pub async fn upload( ctx: &RpcContext, - session: InternedString, + session: Option, ) -> Result<(Guid, UploadingFile), Error> { let guid = Guid::new(); let (mut handle, file) = UploadingFile::new().await?; diff --git a/core/startos/src/util/io.rs b/core/startos/src/util/io.rs index 6d9c8a4ff..0e7aada54 100644 --- a/core/startos/src/util/io.rs +++ b/core/startos/src/util/io.rs @@ -1,6 +1,7 @@ use std::collections::VecDeque; use std::future::Future; use std::io::Cursor; +use std::mem::MaybeUninit; use std::os::unix::prelude::MetadataExt; use std::path::{Path, PathBuf}; use std::pin::Pin; @@ -11,7 +12,7 @@ use std::time::Duration; use bytes::{Buf, BytesMut}; use futures::future::{BoxFuture, Fuse}; -use futures::{AsyncSeek, FutureExt, TryStreamExt}; +use futures::{AsyncSeek, FutureExt, Stream, TryStreamExt}; use helpers::NonDetachingJoinHandle; use nix::unistd::{Gid, Uid}; use tokio::fs::File; @@ -23,6 +24,7 @@ use tokio::sync::{Notify, OwnedMutexGuard}; use tokio::time::{Instant, Sleep}; use crate::prelude::*; +use crate::{CAP_1_KiB, CAP_1_MiB}; pub trait AsyncReadSeek: AsyncRead + AsyncSeek {} impl AsyncReadSeek for T {} @@ -440,6 +442,13 @@ impl BackTrackingIO { }, } } + pub fn read_buffer(&self) -> &[u8] { + match &self.buffer { + BTBuffer::NotBuffering => &[], + BTBuffer::Buffering { read, .. } => read, + BTBuffer::Rewound { read } => read.remaining_slice(), + } + } #[must_use] pub fn stop_buffering(&mut self) -> Vec { match std::mem::take(&mut self.buffer) { @@ -510,6 +519,28 @@ impl AsyncRead for BackTrackingIO { } } } +impl std::io::Read for BackTrackingIO { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + match &mut self.buffer { + BTBuffer::Buffering { read, .. } => { + let n = self.io.read(buf)?; + read.extend_from_slice(&buf[..n]); + Ok(n) + } + BTBuffer::NotBuffering => self.io.read(buf), + BTBuffer::Rewound { read } => { + let mut ready = false; + if (read.position() as usize) < read.get_ref().len() { + let n = std::io::Read::read(read, buf)?; + if n != 0 { + return Ok(n); + } + } + self.io.read(buf) + } + } + } +} impl AsyncWrite for BackTrackingIO { fn is_write_vectored(&self) -> bool { @@ -867,7 +898,7 @@ impl Drop for TmpDir { if self.path.exists() { let path = std::mem::take(&mut self.path); tokio::spawn(async move { - tokio::fs::remove_dir_all(&path).await.unwrap(); + tokio::fs::remove_dir_all(&path).await.log_err(); }); } } @@ -892,6 +923,20 @@ pub async fn create_file(path: impl AsRef) -> Result { .with_ctx(|_| (ErrorKind::Filesystem, lazy_format!("create {path:?}"))) } +pub async fn delete_file(path: impl AsRef) -> Result<(), Error> { + let path = path.as_ref(); + tokio::fs::remove_file(path) + .await + .or_else(|e| { + if e.kind() == std::io::ErrorKind::NotFound { + Ok(()) + } else { + Err(e) + } + }) + .with_ctx(|_| (ErrorKind::Filesystem, lazy_format!("delete {path:?}"))) +} + pub async fn rename(src: impl AsRef, dst: impl AsRef) -> Result<(), Error> { let src = src.as_ref(); let dst = dst.as_ref(); @@ -1267,3 +1312,33 @@ impl AsyncWrite for MutexIO { Pin::new(&mut *self.get_mut().0).poll_shutdown(cx) } } + +#[pin_project::pin_project] +pub struct AsyncReadStream { + buffer: Vec>, + #[pin] + pub io: T, +} +impl AsyncReadStream { + pub fn new(io: T, buffer_size: usize) -> Self { + Self { + buffer: vec![MaybeUninit::uninit(); buffer_size], + io, + } + } +} +impl Stream for AsyncReadStream { + type Item = Result, Error>; + fn poll_next( + self: Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> Poll> { + let this = self.project(); + let mut buf = ReadBuf::uninit(this.buffer); + match futures::ready!(this.io.poll_read(cx, &mut buf)) { + Ok(()) if buf.filled().is_empty() => Poll::Ready(None), + Ok(()) => Poll::Ready(Some(Ok(buf.filled().to_vec()))), + Err(e) => Poll::Ready(Some(Err(e.into()))), + } + } +} diff --git a/core/startos/src/util/logger.rs b/core/startos/src/util/logger.rs index c7ab41ba2..c464b328d 100644 --- a/core/startos/src/util/logger.rs +++ b/core/startos/src/util/logger.rs @@ -1,3 +1,5 @@ +use std::io; + use tracing::Subscriber; use tracing_subscriber::util::SubscriberInitExt; @@ -21,7 +23,11 @@ impl EmbassyLogger { let filter_layer = filter_layer .add_directive("tokio=trace".parse().unwrap()) .add_directive("runtime=trace".parse().unwrap()); - let fmt_layer = fmt::layer().with_target(true); + let fmt_layer = fmt::layer() + .with_writer(io::stderr) + .with_line_number(true) + .with_file(true) + .with_target(true); let sub = tracing_subscriber::registry() .with(filter_layer) diff --git a/core/startos/src/util/lshw.rs b/core/startos/src/util/lshw.rs index eb5293d89..df5fff5f8 100644 --- a/core/startos/src/util/lshw.rs +++ b/core/startos/src/util/lshw.rs @@ -10,6 +10,7 @@ const KNOWN_CLASSES: &[&str] = &["processor", "display"]; #[derive(Clone, Debug, Deserialize, Serialize, TS)] #[serde(tag = "class")] #[serde(rename_all = "camelCase")] +#[ts(export)] pub enum LshwDevice { Processor(LshwProcessor), Display(LshwDisplay), diff --git a/core/startos/src/util/mod.rs b/core/startos/src/util/mod.rs index fab0b127d..d6f426135 100644 --- a/core/startos/src/util/mod.rs +++ b/core/startos/src/util/mod.rs @@ -36,7 +36,6 @@ use crate::util::serde::{deserialize_from_str, serialize_display}; use crate::{Error, ErrorKind, ResultExt as _}; pub mod actor; -pub mod clap; pub mod collections; pub mod cpupower; pub mod crypto; @@ -123,7 +122,8 @@ impl<'a> std::ops::DerefMut for ExtendedCommand<'a> { } impl<'a> Invoke<'a> for tokio::process::Command { - type Extended<'ext> = ExtendedCommand<'ext> + type Extended<'ext> + = ExtendedCommand<'ext> where Self: 'ext, 'ext: 'a; @@ -163,7 +163,8 @@ impl<'a> Invoke<'a> for tokio::process::Command { } impl<'a> Invoke<'a> for ExtendedCommand<'a> { - type Extended<'ext> = &'ext mut ExtendedCommand<'ext> + type Extended<'ext> + = &'ext mut ExtendedCommand<'ext> where Self: 'ext, 'ext: 'a; @@ -237,11 +238,7 @@ impl<'a> Invoke<'a> for ExtendedCommand<'a> { .or(Some(&res.stdout)) .filter(|a| !a.is_empty()) .and_then(|a| std::str::from_utf8(a).ok()) - .unwrap_or(&format!( - "{} exited with code {}", - self.cmd.as_std().get_program().to_string_lossy(), - res.status - )) + .unwrap_or(&format!("{} exited with code {}", cmd_str, res.status)) ); Ok(res.stdout) } else { @@ -268,7 +265,7 @@ impl<'a> Invoke<'a> for ExtendedCommand<'a> { if prev.is_some() { cmd.stdin(Stdio::piped()); } - let mut child = cmd.spawn().with_kind(error_kind)?; + let mut child = cmd.spawn().with_ctx(|_| (error_kind, &cmd_str))?; let input = std::mem::replace( &mut prev, child @@ -568,7 +565,7 @@ pub struct FileLock(#[allow(unused)] OwnedMutexGuard<()>, Option>); impl Drop for FileLock { fn drop(&mut self) { if let Some(fd_lock) = self.1.take() { - tokio::task::spawn_blocking(|| fd_lock.unlock(true).map_err(|(_, e)| e).unwrap()); + tokio::task::spawn_blocking(|| fd_lock.unlock(true).map_err(|(_, e)| e).log_err()); } } } @@ -668,8 +665,8 @@ impl FromStr for PathOrUrl { type Err = ::Err; fn from_str(s: &str) -> Result { if let Ok(url) = s.parse::() { - if url.scheme() == "file" { - Ok(Self::Path(url.path().parse()?)) + if let Some(path) = s.strip_prefix("file://") { + Ok(Self::Path(path.parse()?)) } else { Ok(Self::Url(url)) } diff --git a/core/startos/src/util/rpc.rs b/core/startos/src/util/rpc.rs index 80d6d9251..b2dea340e 100644 --- a/core/startos/src/util/rpc.rs +++ b/core/startos/src/util/rpc.rs @@ -1,7 +1,7 @@ use std::path::Path; use clap::Parser; -use rpc_toolkit::{from_fn_async, Context, ParentHandler}; +use rpc_toolkit::{from_fn_async, Context, HandlerExt, ParentHandler}; use serde::{Deserialize, Serialize}; use url::Url; @@ -16,7 +16,10 @@ use crate::util::{Apply, PathOrUrl}; use crate::CAP_10_MiB; pub fn util() -> ParentHandler { - ParentHandler::new().subcommand("b3sum", from_fn_async(b3sum)) + ParentHandler::new().subcommand( + "b3sum", + from_fn_async(b3sum).with_about("Calculate blake3 hash for a file"), + ) } #[derive(Debug, Deserialize, Serialize, Parser)] diff --git a/core/startos/src/util/serde.rs b/core/startos/src/util/serde.rs index 88d7bfc11..5b785ce9a 100644 --- a/core/startos/src/util/serde.rs +++ b/core/startos/src/util/serde.rs @@ -1,4 +1,3 @@ -use std::any::Any; use std::collections::VecDeque; use std::marker::PhantomData; use std::ops::Deref; @@ -9,6 +8,7 @@ use clap::builder::ValueParserFactory; use clap::{ArgMatches, CommandFactory, FromArgMatches}; use color_eyre::eyre::eyre; use imbl::OrdMap; +use models::FromStrParser; use openssl::pkey::{PKey, Private}; use openssl::x509::X509; use rpc_toolkit::{ @@ -17,12 +17,10 @@ use rpc_toolkit::{ use serde::de::DeserializeOwned; use serde::ser::{SerializeMap, SerializeSeq}; use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use serde_json::Value; use ts_rs::TS; use super::IntoDoubleEndedIterator; use crate::prelude::*; -use crate::util::clap::FromStrParser; use crate::util::Apply; pub fn deserialize_from_str< @@ -272,7 +270,7 @@ impl std::fmt::Display for IoFormat { impl std::str::FromStr for IoFormat { type Err = Error; fn from_str(s: &str) -> Result { - serde_json::from_value(Value::String(s.to_owned())) + serde_json::from_value(serde_json::Value::String(s.to_owned())) .with_kind(crate::ErrorKind::Deserialization) } } @@ -566,7 +564,7 @@ where } } -#[derive(Deserialize, Serialize, TS)] +#[derive(Deserialize, Serialize, TS, Clone)] pub struct StdinDeserializable(pub T); impl Default for StdinDeserializable where @@ -1031,6 +1029,12 @@ impl>> FromStr for Base64 { }) } } +impl>> ValueParserFactory for Base64 { + type Parser = FromStrParser; + fn value_parser() -> Self::Parser { + Self::Parser::new() + } +} impl<'de, T: TryFrom>> Deserialize<'de> for Base64 { fn deserialize(deserializer: D) -> Result where @@ -1217,6 +1221,30 @@ impl PemEncoding for ed25519_dalek::SigningKey { } } +#[derive(Clone, Debug)] +pub struct Pkcs8Doc { + pub tag: String, + pub document: pkcs8::Document, +} + +impl PemEncoding for Pkcs8Doc { + fn from_pem(pem: &str) -> Result { + let (tag, document) = pkcs8::Document::from_pem(pem).map_err(E::custom)?; + Ok(Pkcs8Doc { + tag: tag.into(), + document, + }) + } + fn to_pem(&self) -> Result { + der::pem::encode_string( + &self.tag, + pkcs8::LineEnding::default(), + self.document.as_bytes(), + ) + .map_err(E::custom) + } +} + pub mod pem { use serde::{Deserialize, Deserializer, Serializer}; @@ -1358,3 +1386,19 @@ impl Serialize for MaybeUtf8String { } } } + +pub fn is_partial_of(partial: &Value, full: &Value) -> bool { + match (partial, full) { + (Value::Object(partial), Value::Object(full)) => partial.iter().all(|(k, v)| { + if let Some(v_full) = full.get(k) { + is_partial_of(v, v_full) + } else { + false + } + }), + (Value::Array(partial), Value::Array(full)) => partial + .iter() + .all(|v| full.iter().any(|v_full| is_partial_of(v, v_full))), + (_, _) => partial == full, + } +} diff --git a/core/startos/src/version/mod.rs b/core/startos/src/version/mod.rs index 18ff0e5b2..f71cec8b3 100644 --- a/core/startos/src/version/mod.rs +++ b/core/startos/src/version/mod.rs @@ -1,10 +1,15 @@ +use std::any::Any; use std::cmp::Ordering; +use std::panic::{RefUnwindSafe, UnwindSafe}; use color_eyre::eyre::eyre; use futures::future::BoxFuture; use futures::{Future, FutureExt}; -use imbl_value::InternedString; +use imbl::Vector; +use imbl_value::{to_value, InternedString}; +use patch_db::json_ptr::{JsonPointer, ROOT}; +use crate::context::RpcContext; use crate::db::model::Database; use crate::prelude::*; use crate::progress::PhaseProgressTrackerHandle; @@ -21,8 +26,68 @@ mod v0_3_6_alpha_4; mod v0_3_6_alpha_5; mod v0_3_6_alpha_6; mod v0_3_6_alpha_7; +mod v0_3_6_alpha_8; -pub type Current = v0_3_6_alpha_5::Version; // VERSION_BUMP +pub type Current = v0_3_6_alpha_8::Version; // VERSION_BUMP + +impl Current { + #[instrument(skip(self, db))] + pub async fn pre_init(self, db: &PatchDb) -> Result<(), Error> { + let from = from_value::( + version_accessor(&mut db.dump(&ROOT).await.value) + .or_not_found("`version` in db")? + .clone(), + )? + .as_version_t()?; + match from.semver().cmp(&self.semver()) { + Ordering::Greater => { + db.apply_function(|mut db| { + rollback_to_unchecked(&from, &self, &mut db)?; + Ok::<_, Error>((db, ())) + }) + .await?; + } + Ordering::Less => { + let pre_ups = PreUps::load(&from, &self).await?; + db.apply_function(|mut db| { + migrate_from_unchecked(&from, &self, pre_ups, &mut db)?; + Ok::<_, Error>((db, ())) + }) + .await?; + } + Ordering::Equal => (), + } + Ok(()) + } +} + +pub async fn post_init(ctx: &RpcContext) -> Result<(), Error> { + let mut peek; + while let Some(version) = { + peek = ctx.db.peek().await; + peek.as_public() + .as_server_info() + .as_post_init_migration_todos() + .de()? + .first() + .cloned() + .map(Version::from_exver_version) + .as_ref() + .map(Version::as_version_t) + .transpose()? + } { + version.0.post_up(ctx).await?; + ctx.db + .mutate(|db| { + db.as_public_mut() + .as_server_info_mut() + .as_post_init_migration_todos_mut() + .mutate(|m| Ok(m.remove(&version.0.semver()))) + }) + .await?; + } + Ok(()) +} #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] #[serde(untagged)] @@ -40,6 +105,7 @@ enum Version { V0_3_6_alpha_5(Wrapper), V0_3_6_alpha_6(Wrapper), V0_3_6_alpha_7(Wrapper), + V0_3_6_alpha_8(Wrapper), Other(exver::Version), } @@ -52,6 +118,34 @@ impl Version { Version::Other(version) }) } + fn as_version_t(&self) -> Result { + Ok(match self { + Self::LT0_3_5(_) => { + return Err(Error::new( + eyre!("cannot migrate from versions before 0.3.5"), + ErrorKind::MigrationFailed, + )) + } + Self::V0_3_5(v) => DynVersion(Box::new(v.0)), + Self::V0_3_5_1(v) => DynVersion(Box::new(v.0)), + Self::V0_3_5_2(v) => DynVersion(Box::new(v.0)), + Self::V0_3_6_alpha_0(v) => DynVersion(Box::new(v.0)), + Self::V0_3_6_alpha_1(v) => DynVersion(Box::new(v.0)), + Self::V0_3_6_alpha_2(v) => DynVersion(Box::new(v.0)), + Self::V0_3_6_alpha_3(v) => DynVersion(Box::new(v.0)), + Self::V0_3_6_alpha_4(v) => DynVersion(Box::new(v.0)), + Self::V0_3_6_alpha_5(v) => DynVersion(Box::new(v.0)), + Self::V0_3_6_alpha_6(v) => DynVersion(Box::new(v.0)), + Self::V0_3_6_alpha_7(v) => DynVersion(Box::new(v.0)), + Self::V0_3_6_alpha_8(v) => DynVersion(Box::new(v.0)), + Self::Other(v) => { + return Err(Error::new( + eyre!("unknown version {v}"), + ErrorKind::MigrationFailed, + )) + } + }) + } #[cfg(test)] fn as_exver(&self) -> exver::Version { match self { @@ -67,115 +161,262 @@ impl Version { Version::V0_3_6_alpha_5(Wrapper(x)) => x.semver(), Version::V0_3_6_alpha_6(Wrapper(x)) => x.semver(), Version::V0_3_6_alpha_7(Wrapper(x)) => x.semver(), + Version::V0_3_6_alpha_8(Wrapper(x)) => x.semver(), Version::Other(x) => x.clone(), } } } +fn version_accessor(db: &mut Value) -> Option<&mut Value> { + if db.get("public").is_some() { + db.get_mut("public")? + .get_mut("serverInfo")? + .get_mut("version") + } else { + db.get_mut("server-info")?.get_mut("version") + } +} + +fn version_compat_accessor(db: &mut Value) -> Option<&mut Value> { + if db.get("public").is_some() { + let server_info = db.get_mut("public")?.get_mut("serverInfo")?; + if server_info.get("packageVersionCompat").is_some() { + server_info.get_mut("packageVersionCompat") + } else { + if let Some(prev) = server_info.get("eosVersionCompat").cloned() { + server_info + .as_object_mut()? + .insert("packageVersionCompat".into(), prev); + } else if let Some(prev) = server_info.get("versionCompat").cloned() { + server_info + .as_object_mut()? + .insert("packageVersionCompat".into(), prev); + } + server_info.get_mut("packageVersionCompat") + } + } else { + db.get_mut("server-info")?.get_mut("eos-version-compat") + } +} + +fn post_init_migration_todos_accessor(db: &mut Value) -> Option<&mut Value> { + let server_info = if db.get("public").is_some() { + db.get_mut("public")?.get_mut("serverInfo")? + } else { + db.get_mut("server-info")? + }; + if server_info.get("postInitMigrationTodos").is_none() { + server_info + .as_object_mut()? + .insert("postInitMigrationTodos".into(), Value::Array(Vector::new())); + } + server_info.get_mut("postInitMigrationTodos") +} + +struct PreUps { + prev: Option>, + value: Box, +} +impl PreUps { + #[instrument(skip(from, to))] + fn load<'a, VFrom: DynVersionT + ?Sized, VTo: DynVersionT + ?Sized>( + from: &'a VFrom, + to: &'a VTo, + ) -> BoxFuture<'a, Result> { + async { + let previous = to.previous(); + let prev = match from.semver().cmp(&previous.semver()) { + Ordering::Less => Some(Box::new(PreUps::load(from, &previous).await?)), + Ordering::Greater => { + return Err(Error::new( + eyre!( + "NO PATH FROM {}, THIS IS LIKELY A MISTAKE IN THE VERSION DEFINITION", + from.semver() + ), + crate::ErrorKind::MigrationFailed, + )) + } + Ordering::Equal => None, + }; + Ok(Self { + prev, + value: to.pre_up().await?, + }) + } + .boxed() + } +} + +fn migrate_from_unchecked( + from: &VFrom, + to: &VTo, + pre_ups: PreUps, + db: &mut Value, +) -> Result<(), Error> { + let previous = to.previous(); + match pre_ups.prev { + Some(prev) if from.semver() < previous.semver() => { + migrate_from_unchecked(from, &previous, *prev, db)? + } + _ if from.semver() > previous.semver() => { + return Err(Error::new( + eyre!( + "NO PATH FROM {}, THIS IS LIKELY A MISTAKE IN THE VERSION DEFINITION", + from.semver() + ), + crate::ErrorKind::MigrationFailed, + )); + } + _ => (), + }; + to.up(db, pre_ups.value)?; + to.commit(db)?; + Ok(()) +} + +fn rollback_to_unchecked( + from: &VFrom, + to: &VTo, + db: &mut Value, +) -> Result<(), Error> { + let previous = from.previous(); + from.down(db)?; + previous.commit(db)?; + if to.semver() < previous.semver() { + rollback_to_unchecked(&previous, to, db)? + } else if to.semver() > previous.semver() { + return Err(Error::new( + eyre!( + "NO PATH TO {}, THIS IS LIKELY A MISTAKE IN THE VERSION DEFINITION", + to.semver() + ), + crate::ErrorKind::MigrationFailed, + )); + } + Ok(()) +} + pub trait VersionT where - Self: Sized + Send + Sync, + Self: Default + Copy + Sized + RefUnwindSafe + Send + Sync + 'static, { type Previous: VersionT; - fn new() -> Self; + type PreUpRes: Send + UnwindSafe; + fn semver(self) -> exver::Version; + fn compat(self) -> &'static exver::VersionRange; + /// MUST NOT change system state. Intended for async I/O reads + fn pre_up(self) -> impl Future> + Send + 'static; + fn up(self, db: &mut Value, input: Self::PreUpRes) -> Result<(), Error> { + Ok(()) + } + /// MUST be idempotent, and is run after *all* db migrations + fn post_up<'a>( + self, + ctx: &'a RpcContext, + ) -> impl Future> + Send + 'a { + async { Ok(()) } + } + fn down(self, db: &mut Value) -> Result<(), Error> { + Err(Error::new( + eyre!("downgrades prohibited"), + ErrorKind::InvalidRequest, + )) + } + fn commit(self, db: &mut Value) -> Result<(), Error> { + *version_accessor(db).or_not_found("`version` in db")? = to_value(&self.semver())?; + *version_compat_accessor(db).or_not_found("`versionCompat` in db")? = + to_value(self.compat())?; + post_init_migration_todos_accessor(db) + .or_not_found("`serverInfo` in db")? + .as_array_mut() + .ok_or_else(|| { + Error::new( + eyre!("postInitMigrationTodos is not an array"), + ErrorKind::Database, + ) + })? + .push_back(to_value(&self.semver())?); + Ok(()) + } +} + +struct DynVersion(Box); +unsafe impl Send for DynVersion {} + +trait DynVersionT: RefUnwindSafe + Send + Sync { + fn previous(&self) -> DynVersion; fn semver(&self) -> exver::Version; fn compat(&self) -> &'static exver::VersionRange; - fn up(&self, db: &TypedPatchDb) -> impl Future> + Send; - fn down(&self, db: &TypedPatchDb) -> impl Future> + Send; - fn commit( - &self, - db: &TypedPatchDb, - ) -> impl Future> + Send { - async { - let semver = self.semver().into(); - let compat = self.compat().clone(); - db.mutate(|d| { - d.as_public_mut() - .as_server_info_mut() - .as_version_mut() - .ser(&semver)?; - d.as_public_mut() - .as_server_info_mut() - .as_eos_version_compat_mut() - .ser(&compat)?; - Ok(()) - }) - .await?; - Ok(()) - } + fn pre_up(&self) -> BoxFuture<'static, Result, Error>>; + fn up(&self, db: &mut Value, input: Box) -> Result<(), Error>; + fn post_up<'a>(&self, ctx: &'a RpcContext) -> BoxFuture<'a, Result<(), Error>>; + fn down(&self, db: &mut Value) -> Result<(), Error>; + fn commit(&self, db: &mut Value) -> Result<(), Error>; +} +impl DynVersionT for T +where + T: VersionT, +{ + fn previous(&self) -> DynVersion { + DynVersion(Box::new(::Previous::default())) } - fn migrate_to( - &self, - version: &V, - db: &TypedPatchDb, - progress: &mut PhaseProgressTrackerHandle, - ) -> impl Future> + Send { - async { - match self.semver().cmp(&version.semver()) { - Ordering::Greater => self.rollback_to_unchecked(version, db, progress).await, - Ordering::Less => version.migrate_from_unchecked(self, db, progress).await, - Ordering::Equal => Ok(()), - } - } + fn semver(&self) -> exver::Version { + VersionT::semver(*self) } - fn migrate_from_unchecked<'a, V: VersionT>( - &'a self, - version: &'a V, - db: &'a TypedPatchDb, - progress: &'a mut PhaseProgressTrackerHandle, - ) -> BoxFuture<'a, Result<(), Error>> { - progress.add_total(1); - async { - let previous = Self::Previous::new(); - if version.semver() < previous.semver() { - previous - .migrate_from_unchecked(version, db, progress) - .await?; - } else if version.semver() > previous.semver() { - return Err(Error::new( - eyre!( - "NO PATH FROM {}, THIS IS LIKELY A MISTAKE IN THE VERSION DEFINITION", - version.semver() - ), - crate::ErrorKind::MigrationFailed, - )); - } - tracing::info!("{} -> {}", previous.semver(), self.semver(),); - self.up(db).await?; - self.commit(db).await?; - *progress += 1; - Ok(()) - } - .boxed() + fn compat(&self) -> &'static exver::VersionRange { + VersionT::compat(*self) } - fn rollback_to_unchecked<'a, V: VersionT>( - &'a self, - version: &'a V, - db: &'a TypedPatchDb, - progress: &'a mut PhaseProgressTrackerHandle, - ) -> BoxFuture<'a, Result<(), Error>> { - async { - let previous = Self::Previous::new(); - tracing::info!("{} -> {}", self.semver(), previous.semver(),); - self.down(db).await?; - previous.commit(db).await?; - *progress += 1; - if version.semver() < previous.semver() { - previous - .rollback_to_unchecked(version, db, progress) - .await?; - } else if version.semver() > previous.semver() { - return Err(Error::new( - eyre!( - "NO PATH TO {}, THIS IS LIKELY A MISTAKE IN THE VERSION DEFINITION", - version.semver() - ), - crate::ErrorKind::MigrationFailed, - )); - } - Ok(()) - } - .boxed() + fn pre_up(&self) -> BoxFuture<'static, Result, Error>> { + let v = *self; + async move { Ok(Box::new(VersionT::pre_up(v).await?) as Box) } + .boxed() + } + fn up(&self, db: &mut Value, input: Box) -> Result<(), Error> { + VersionT::up( + *self, + db, + *input.downcast().map_err(|_| { + Error::new( + eyre!("pre_up returned unexpected type"), + ErrorKind::Incoherent, + ) + })?, + ) + } + fn post_up<'a>(&self, ctx: &'a RpcContext) -> BoxFuture<'a, Result<(), Error>> { + VersionT::post_up(*self, ctx).boxed() + } + fn down(&self, db: &mut Value) -> Result<(), Error> { + VersionT::down(*self, db) + } + fn commit(&self, db: &mut Value) -> Result<(), Error> { + VersionT::commit(*self, db) + } +} +impl DynVersionT for DynVersion { + fn previous(&self) -> DynVersion { + self.0.previous() + } + fn semver(&self) -> exver::Version { + self.0.semver() + } + fn compat(&self) -> &'static exver::VersionRange { + self.0.compat() + } + fn pre_up(&self) -> BoxFuture<'static, Result, Error>> { + self.0.pre_up() + } + fn up(&self, db: &mut Value, input: Box) -> Result<(), Error> { + self.0.up(db, input) + } + fn post_up<'a>(&self, ctx: &'a RpcContext) -> BoxFuture<'a, Result<(), Error>> { + self.0.post_up(ctx) + } + fn down(&self, db: &mut Value) -> Result<(), Error> { + self.0.down(db) + } + fn commit(&self, db: &mut Value) -> Result<(), Error> { + self.0.commit(db) } } @@ -195,7 +436,7 @@ where { fn deserialize>(deserializer: D) -> Result { let v = exver::Version::deserialize(deserializer)?; - let version = T::new(); + let version = T::default(); if v < version.semver() { Ok(Self(version, v)) } else { @@ -220,7 +461,7 @@ where { fn deserialize>(deserializer: D) -> Result { let v = exver::Version::deserialize(deserializer)?; - let version = T::new(); + let version = T::default(); if v == version.semver() { Ok(Wrapper(version)) } else { @@ -229,62 +470,6 @@ where } } -pub async fn init( - db: &TypedPatchDb, - mut progress: PhaseProgressTrackerHandle, -) -> Result<(), Error> { - progress.start(); - db.mutate(|db| { - db.as_public_mut() - .as_server_info_mut() - .as_version_mut() - .map_mutate(|v| { - Ok(if v == exver::Version::new([0, 3, 6], []) { - v0_3_6_alpha_0::Version::new().semver() - } else { - v - }) - }) - }) - .await?; // TODO: remove before releasing 0.3.6 - let version = Version::from_exver_version( - db.peek() - .await - .as_public() - .as_server_info() - .as_version() - .de()?, - ); - - match version { - Version::LT0_3_5(_) => { - return Err(Error::new( - eyre!("Cannot migrate from pre-0.3.5. Please update to v0.3.5 first."), - ErrorKind::MigrationFailed, - )); - } - Version::V0_3_5(v) => v.0.migrate_to(&Current::new(), &db, &mut progress).await?, - Version::V0_3_5_1(v) => v.0.migrate_to(&Current::new(), &db, &mut progress).await?, - Version::V0_3_5_2(v) => v.0.migrate_to(&Current::new(), &db, &mut progress).await?, - Version::V0_3_6_alpha_0(v) => v.0.migrate_to(&Current::new(), &db, &mut progress).await?, - Version::V0_3_6_alpha_1(v) => v.0.migrate_to(&Current::new(), &db, &mut progress).await?, - Version::V0_3_6_alpha_2(v) => v.0.migrate_to(&Current::new(), &db, &mut progress).await?, - Version::V0_3_6_alpha_3(v) => v.0.migrate_to(&Current::new(), &db, &mut progress).await?, - Version::V0_3_6_alpha_4(v) => v.0.migrate_to(&Current::new(), &db, &mut progress).await?, - Version::V0_3_6_alpha_5(v) => v.0.migrate_to(&Current::new(), &db, &mut progress).await?, - Version::V0_3_6_alpha_6(v) => v.0.migrate_to(&Current::new(), &db, &mut progress).await?, - Version::V0_3_6_alpha_7(v) => v.0.migrate_to(&Current::new(), &db, &mut progress).await?, - Version::Other(_) => { - return Err(Error::new( - eyre!("Cannot downgrade"), - crate::ErrorKind::InvalidRequest, - )) - } - } - progress.complete(); - Ok(()) -} - pub const COMMIT_HASH: &str = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/../../GIT_HASH.txt")); @@ -315,17 +500,17 @@ mod tests { fn versions() -> impl Strategy { prop_oneof![ - Just(Version::V0_3_5(Wrapper(v0_3_5::Version::new()))), - Just(Version::V0_3_5_1(Wrapper(v0_3_5_1::Version::new()))), - Just(Version::V0_3_5_2(Wrapper(v0_3_5_2::Version::new()))), + Just(Version::V0_3_5(Wrapper(v0_3_5::Version::default()))), + Just(Version::V0_3_5_1(Wrapper(v0_3_5_1::Version::default()))), + Just(Version::V0_3_5_2(Wrapper(v0_3_5_2::Version::default()))), Just(Version::V0_3_6_alpha_0(Wrapper( - v0_3_6_alpha_0::Version::new() + v0_3_6_alpha_0::Version::default() ))), Just(Version::V0_3_6_alpha_1(Wrapper( - v0_3_6_alpha_1::Version::new() + v0_3_6_alpha_1::Version::default() ))), Just(Version::V0_3_6_alpha_2(Wrapper( - v0_3_6_alpha_2::Version::new() + v0_3_6_alpha_2::Version::default() ))), em_version().prop_map(Version::Other), ] diff --git a/core/startos/src/version/v0_3_5.rs b/core/startos/src/version/v0_3_5.rs index 167132784..0217b6738 100644 --- a/core/startos/src/version/v0_3_5.rs +++ b/core/startos/src/version/v0_3_5.rs @@ -1,7 +1,6 @@ use exver::{ExtendedVersion, VersionRange}; use super::VersionT; -use crate::db::model::Database; use crate::prelude::*; use crate::version::Current; @@ -17,7 +16,7 @@ lazy_static::lazy_static! { VersionRange::anchor( exver::LTE, ExtendedVersion::new( - Current::new().semver(), + Current::default().semver(), exver::Version::default(), ) ), @@ -25,24 +24,26 @@ lazy_static::lazy_static! { static ref V0_3_5: exver::Version = exver::Version::new([0, 3, 5], []); } -#[derive(Clone, Debug)] +#[derive(Clone, Copy, Debug, Default)] pub struct Version; impl VersionT for Version { type Previous = Self; - fn new() -> Self { - Version - } - fn semver(&self) -> exver::Version { - V0_3_5.clone() - } - fn compat(&self) -> &'static VersionRange { - &V0_3_0_COMPAT - } - async fn up(&self, _db: &TypedPatchDb) -> Result<(), Error> { + type PreUpRes = (); + + async fn pre_up(self) -> Result { Ok(()) } - async fn down(&self, _db: &TypedPatchDb) -> Result<(), Error> { + fn semver(self) -> exver::Version { + V0_3_5.clone() + } + fn compat(self) -> &'static VersionRange { + &V0_3_0_COMPAT + } + fn up(self, _db: &mut Value, _: Self::PreUpRes) -> Result<(), Error> { + Ok(()) + } + fn down(self, _db: &mut Value) -> Result<(), Error> { Ok(()) } } diff --git a/core/startos/src/version/v0_3_5_1.rs b/core/startos/src/version/v0_3_5_1.rs index c6c328f6d..5334cc2a4 100644 --- a/core/startos/src/version/v0_3_5_1.rs +++ b/core/startos/src/version/v0_3_5_1.rs @@ -2,31 +2,32 @@ use exver::VersionRange; use super::v0_3_5::V0_3_0_COMPAT; use super::{v0_3_5, VersionT}; -use crate::db::model::Database; use crate::prelude::*; lazy_static::lazy_static! { static ref V0_3_5_1: exver::Version = exver::Version::new([0, 3, 5, 1], []); } -#[derive(Clone, Debug)] +#[derive(Clone, Copy, Debug, Default)] pub struct Version; impl VersionT for Version { type Previous = v0_3_5::Version; - fn new() -> Self { - Version - } - fn semver(&self) -> exver::Version { - V0_3_5_1.clone() - } - fn compat(&self) -> &'static VersionRange { - &V0_3_0_COMPAT - } - async fn up(&self, _db: &TypedPatchDb) -> Result<(), Error> { + type PreUpRes = (); + + async fn pre_up(self) -> Result { Ok(()) } - async fn down(&self, _db: &TypedPatchDb) -> Result<(), Error> { + fn semver(self) -> exver::Version { + V0_3_5_1.clone() + } + fn compat(self) -> &'static VersionRange { + &V0_3_0_COMPAT + } + fn up(self, _db: &mut Value, _: Self::PreUpRes) -> Result<(), Error> { + Ok(()) + } + fn down(self, _db: &mut Value) -> Result<(), Error> { Ok(()) } } diff --git a/core/startos/src/version/v0_3_5_2.rs b/core/startos/src/version/v0_3_5_2.rs index 00143f8cd..780731d09 100644 --- a/core/startos/src/version/v0_3_5_2.rs +++ b/core/startos/src/version/v0_3_5_2.rs @@ -2,31 +2,32 @@ use exver::VersionRange; use super::v0_3_5::V0_3_0_COMPAT; use super::{v0_3_5_1, VersionT}; -use crate::db::model::Database; use crate::prelude::*; lazy_static::lazy_static! { static ref V0_3_5_2: exver::Version = exver::Version::new([0, 3, 5, 2], []); } -#[derive(Clone, Debug)] +#[derive(Clone, Copy, Debug, Default)] pub struct Version; impl VersionT for Version { type Previous = v0_3_5_1::Version; - fn new() -> Self { - Version - } - fn semver(&self) -> exver::Version { - V0_3_5_2.clone() - } - fn compat(&self) -> &'static VersionRange { - &V0_3_0_COMPAT - } - async fn up(&self, _db: &TypedPatchDb) -> Result<(), Error> { + type PreUpRes = (); + + async fn pre_up(self) -> Result { Ok(()) } - async fn down(&self, _db: &TypedPatchDb) -> Result<(), Error> { + fn semver(self) -> exver::Version { + V0_3_5_2.clone() + } + fn compat(self) -> &'static VersionRange { + &V0_3_0_COMPAT + } + fn up(self, _db: &mut Value, _: Self::PreUpRes) -> Result<(), Error> { + Ok(()) + } + fn down(self, _db: &mut Value) -> Result<(), Error> { Ok(()) } } 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 1da34f708..7a6045a3a 100644 --- a/core/startos/src/version/v0_3_6_alpha_0.rs +++ b/core/startos/src/version/v0_3_6_alpha_0.rs @@ -1,9 +1,44 @@ +use std::collections::BTreeMap; +use std::future::Future; +use std::path::Path; + +use chrono::{DateTime, Utc}; +use ed25519_dalek::SigningKey; use exver::{PreReleaseSegment, VersionRange}; +use imbl_value::{json, InternedString}; +use itertools::Itertools; +use models::PackageId; +use openssl::pkey::{PKey, Private}; +use openssl::x509::X509; +use patch_db::ModelExt; +use sqlx::postgres::PgConnectOptions; +use sqlx::{PgPool, Row}; +use ssh_key::Fingerprint; +use tokio::process::Command; +use torut::onion::TorSecretKeyV3; use super::v0_3_5::V0_3_0_COMPAT; use super::{v0_3_5_2, VersionT}; +use crate::account::AccountInfo; +use crate::auth::Sessions; +use crate::backup::target::cifs::CifsTargets; +use crate::context::RpcContext; use crate::db::model::Database; +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::keys::KeyStore; +use crate::net::ssl::CertStore; +use crate::net::tor; +use crate::net::tor::OnionStore; +use crate::notifications::{Notification, Notifications}; use crate::prelude::*; +use crate::s9pk::merkle_archive::source::multi_cursor_file::MultiCursorFile; +use crate::ssh::{SshKeys, SshPubKey}; +use crate::util::crypto::ed25519_expand_key; +use crate::util::serde::{Pem, PemEncoding}; +use crate::util::Invoke; lazy_static::lazy_static! { static ref V0_3_6_alpha_0: exver::Version = exver::Version::new( @@ -12,24 +47,537 @@ lazy_static::lazy_static! { ); } -#[derive(Clone, Debug)] +#[tracing::instrument(skip_all)] +async fn init_postgres(datadir: impl AsRef) -> Result { + let db_dir = datadir.as_ref().join("main/postgresql"); + if tokio::process::Command::new("mountpoint") + .arg("/var/lib/postgresql") + .stdout(std::process::Stdio::null()) + .stderr(std::process::Stdio::null()) + .status() + .await? + .success() + { + unmount("/var/lib/postgresql", true).await?; + } + let exists = tokio::fs::metadata(&db_dir).await.is_ok(); + if !exists { + Command::new("cp") + .arg("-ra") + .arg("/var/lib/postgresql") + .arg(&db_dir) + .invoke(crate::ErrorKind::Filesystem) + .await?; + } + Command::new("chown") + .arg("-R") + .arg("postgres:postgres") + .arg(&db_dir) + .invoke(crate::ErrorKind::Database) + .await?; + + let mut pg_paths = tokio::fs::read_dir("/usr/lib/postgresql").await?; + let mut pg_version = None; + while let Some(pg_path) = pg_paths.next_entry().await? { + let pg_path_version = pg_path + .file_name() + .to_str() + .map(|v| v.parse()) + .transpose()? + .unwrap_or(0); + if pg_path_version > pg_version.unwrap_or(0) { + pg_version = Some(pg_path_version) + } + } + let pg_version = pg_version.ok_or_else(|| { + Error::new( + eyre!("could not determine postgresql version"), + crate::ErrorKind::Database, + ) + })?; + + 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")) + .invoke(crate::ErrorKind::Database) + .await?; + if !exists { + Command::new("sudo") + .arg("-u") + .arg("postgres") + .arg("createuser") + .arg("root") + .invoke(crate::ErrorKind::Database) + .await?; + Command::new("sudo") + .arg("-u") + .arg("postgres") + .arg("createdb") + .arg("secrets") + .arg("-O") + .arg("root") + .invoke(crate::ErrorKind::Database) + .await?; + } + + let secret_store = + PgPool::connect_with(PgConnectOptions::new().database("secrets").username("root")).await?; + sqlx::migrate!() + .run(&secret_store) + .await + .with_kind(crate::ErrorKind::Database)?; + dbg!("Init Postgres Done"); + Ok(secret_store) +} + +#[derive(Clone, Copy, Debug, Default)] pub struct Version; impl VersionT for Version { type Previous = v0_3_5_2::Version; - fn new() -> Self { - Version - } - fn semver(&self) -> exver::Version { + type PreUpRes = (AccountInfo, SshKeys, CifsTargets, Notifications); + fn semver(self) -> exver::Version { V0_3_6_alpha_0.clone() } - fn compat(&self) -> &'static VersionRange { + fn compat(self) -> &'static VersionRange { &V0_3_0_COMPAT } - async fn up(&self, _db: &TypedPatchDb) -> Result<(), Error> { - Err(Error::new(eyre!("unimplemented"), ErrorKind::Unknown)) + async fn pre_up(self) -> Result { + let pg = init_postgres("/embassy-data").await?; + let account = previous_account_info(&pg).await?; + + let ssh_keys = previous_ssh_keys(&pg).await?; + + let cifs = previous_cifs(&pg).await?; + + let notifications = previous_notifications(pg).await?; + + Ok((account, ssh_keys, cifs, notifications)) } - async fn down(&self, _db: &TypedPatchDb) -> Result<(), Error> { + fn up( + self, + db: &mut Value, + (account, ssh_keys, cifs, notifications): Self::PreUpRes, + ) -> Result<(), Error> { + let wifi = json!({ + "infterface": db["server-info"]["wifi"]["interface"], + "ssids": db["server-info"]["wifi"]["ssids"], + "selected": db["server-info"]["wifi"]["selected"], + "last_region": db["server-info"]["wifi"]["last-region"], + }); + + let ip_info = { + let mut ip_info = json!({}); + let empty = Default::default(); + for (k, v) in db["server-info"]["ip-info"].as_object().unwrap_or(&empty) { + let k: &str = k.as_ref(); + ip_info[k] = json!({ + "ipv4Range": v["ipv4-range"], + "ipv6Range": v["ipv6-range"], + "ipv4": v["ipv4"], + "ipv6": v["ipv6"], + }); + } + ip_info + }; + + let status_info = json!({ + "backupProgress": db["server-info"]["status-info"]["backup-progress"], + "updated": db["server-info"]["status-info"]["updated"], + "updateProgress": db["server-info"]["status-info"]["update-progress"], + "shuttingDown": db["server-info"]["status-info"]["shutting-down"], + "restarting": db["server-info"]["status-info"]["restarting"], + }); + let server_info = { + let mut server_info = json!({ + "arch": db["server-info"]["arch"], + "platform": db["server-info"]["platform"], + "id": db["server-info"]["id"], + "hostname": db["server-info"]["hostname"], + "version": db["server-info"]["version"], + "versionCompat": db["server-info"]["eos-version-compat"], + "lastBackup": db["server-info"]["last-backup"], + "lanAddress": db["server-info"]["lan-address"], + }); + + server_info["postInitMigrationTodos"] = json!([]); + let tor_address: String = from_value(db["server-info"]["tor-address"].clone())?; + // Maybe we do this like the Public::init does + server_info["torAddress"] = json!(tor_address); + server_info["onionAddress"] = json!(tor_address + .replace("https://", "") + .replace("http://", "") + .replace(".onion/", "")); + server_info["ipInfo"] = ip_info; + server_info["statusInfo"] = status_info; + server_info["wifi"] = wifi; + server_info["unreadNotificationCount"] = + db["server-info"]["unread-notification-count"].clone(); + server_info["passwordHash"] = db["server-info"]["password-hash"].clone(); + + server_info["pubkey"] = db["server-info"]["pubkey"].clone(); + server_info["caFingerprint"] = db["server-info"]["ca-fingerprint"].clone(); + server_info["ntpSynced"] = db["server-info"]["ntp-synced"].clone(); + server_info["zram"] = db["server-info"]["zram"].clone(); + server_info["governor"] = db["server-info"]["governor"].clone(); + // This one should always be empty, doesn't exist in the previous. And the smtp is all single word key + server_info["smtp"] = db["server-info"]["smtp"].clone(); + server_info + }; + + let public = json!({ + "serverInfo": server_info, + "packageData": json!({}), + "ui": db["ui"], + }); + + let private = { + let mut value = json!({}); + value["keyStore"] = to_value(&KeyStore::new(&account)?)?; + value["password"] = to_value(&account.password)?; + value["compatS9pkKey"] = to_value(&crate::db::model::private::generate_compat_key())?; + value["sshPrivkey"] = to_value(Pem::new_ref(&account.ssh_key))?; + value["sshPubkeys"] = to_value(&ssh_keys)?; + value["availablePorts"] = to_value(&AvailablePorts::new())?; + value["sessions"] = to_value(&Sessions::new())?; + value["notifications"] = to_value(¬ifications)?; + value["cifs"] = to_value(&cifs)?; + value["packageStores"] = json!({}); + value + }; + let next: Value = json!({ + "public": public, + "private": private, + }); + + dbg!("Should be done with the up"); + *db = next; + Ok(()) + } + fn down(self, _db: &mut Value) -> Result<(), Error> { + Err(Error::new( + eyre!("downgrades prohibited"), + ErrorKind::InvalidRequest, + )) + } + + #[instrument(skip(self, ctx))] + /// MUST be idempotent, and is run after *all* db migrations + async fn post_up(self, ctx: &RpcContext) -> Result<(), Error> { + let path = Path::new("/embassy-data/package-data/archive/"); + if !path.is_dir() { + return Err(Error::new( + eyre!( + "expected path ({}) to be a directory", + path.to_string_lossy() + ), + ErrorKind::Filesystem, + )); + } + // Should be the name of the package + let mut paths = tokio::fs::read_dir(path).await?; + while let Some(path) = paths.next_entry().await? { + let path = path.path(); + if !path.is_dir() { + continue; + } + // Should be the version of the package + let mut paths = tokio::fs::read_dir(path).await?; + while let Some(path) = paths.next_entry().await? { + let path = path.path(); + if !path.is_dir() { + continue; + } + + // Should be s9pk + let mut paths = tokio::fs::read_dir(path).await?; + while let Some(path) = paths.next_entry().await? { + let path = path.path(); + if path.is_dir() { + continue; + } + + let package_s9pk = tokio::fs::File::open(path).await?; + let file = MultiCursorFile::open(&package_s9pk).await?; + + let key = ctx.db.peek().await.into_private().into_compat_s9pk_key(); + ctx.services + .install( + ctx.clone(), + || crate::s9pk::load(file.clone(), || Ok(key.de()?.0), None), + None::, + None, + ) + .await? + .await? + .await?; + } + } + } Ok(()) } } + +async fn previous_notifications(pg: sqlx::Pool) -> Result { + let notification_cursor = sqlx::query(r#"SELECT * FROM notifications"#) + .fetch_all(&pg) + .await?; + let notifications = { + let mut notifications = Notifications::default(); + for row in notification_cursor { + let package_id = serde_json::from_str::( + row.try_get("package_id") + .with_ctx(|_| (ErrorKind::Database, "package_id"))?, + ) + .ok(); + + let created_at = row + .try_get("created_at") + .with_ctx(|_| (ErrorKind::Database, "created_at"))?; + let code = row + .try_get::("code") + .with_ctx(|_| (ErrorKind::Database, "code"))? as u32; + let id = row + .try_get::("id") + .with_ctx(|_| (ErrorKind::Database, "id"))? as u32; + let level = serde_json::from_str( + row.try_get("level") + .with_ctx(|_| (ErrorKind::Database, "level"))?, + ) + .with_kind(ErrorKind::Database) + .with_ctx(|_| (ErrorKind::Database, "level: serde_json "))?; + let title = row + .try_get("title") + .with_ctx(|_| (ErrorKind::Database, "title"))?; + let message = row + .try_get("message") + .with_ctx(|_| (ErrorKind::Database, "message"))?; + let data = serde_json::from_str( + row.try_get("data") + .with_ctx(|_| (ErrorKind::Database, "data"))?, + ) + .unwrap_or_default(); + + notifications.0.insert( + id, + Notification { + package_id, + created_at, + code, + level, + title, + message, + data, + }, + ); + } + notifications + }; + Ok(notifications) +} + +#[tracing::instrument(skip_all)] +async fn previous_cifs(pg: &sqlx::Pool) -> Result { + let cifs = sqlx::query(r#"SELECT * FROM cifs_shares"#) + .fetch_all(pg) + .await? + .into_iter() + .map(|row| { + let id: i64 = row.try_get("id")?; + Ok::<_, Error>(( + id, + Cifs { + hostname: row + .try_get("hostname") + .with_ctx(|_| (ErrorKind::Database, "hostname"))?, + path: serde_json::from_str(row.try_get("path")?) + .with_kind(ErrorKind::Database) + .with_ctx(|_| (ErrorKind::Database, "path"))?, + username: row + .try_get("username") + .with_ctx(|_| (ErrorKind::Database, "username"))?, + password: row + .try_get("password") + .with_ctx(|_| (ErrorKind::Database, "password"))?, + }, + )) + }) + .fold(Ok::<_, Error>(CifsTargets::default()), |cifs, data| { + let mut cifs = cifs?; + let (id, cif_value) = data?; + cifs.0.insert(id as u32, cif_value); + Ok(cifs) + })?; + Ok(cifs) +} + +#[tracing::instrument(skip_all)] +async fn previous_account_info(pg: &sqlx::Pool) -> Result { + let account_query = sqlx::query(r#"SELECT * FROM account"#) + .fetch_one(pg) + .await?; + let account = { + AccountInfo { + password: account_query + .try_get("password") + .with_ctx(|_| (ErrorKind::Database, "password"))?, + tor_key: TorSecretKeyV3::try_from( + if let Some(bytes) = account_query + .try_get::>, _>("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"))? + } else { + ed25519_expand_key( + &<[u8; 32]>::try_from(account_query.try_get::, _>("network_key")?) + .map_err(|e| { + Error::new( + eyre!("expected vec of len 32, got len {}", e.len()), + ErrorKind::ParseDbField, + ) + }) + .with_ctx(|_| (ErrorKind::Database, "password.u8 32"))?, + ) + }, + )?, + server_id: account_query + .try_get("server_id") + .with_ctx(|_| (ErrorKind::Database, "server_id"))?, + hostname: Hostname( + account_query + .try_get::("hostname") + .with_ctx(|_| (ErrorKind::Database, "hostname"))? + .into(), + ), + root_ca_key: PKey::private_key_from_pem( + &account_query + .try_get::("root_ca_key_pem") + .with_ctx(|_| (ErrorKind::Database, "root_ca_key_pem"))? + .as_bytes(), + ) + .with_ctx(|_| (ErrorKind::Database, "private_key_from_pem"))?, + root_ca_cert: X509::from_pem( + account_query + .try_get::("root_ca_cert_pem") + .with_ctx(|_| (ErrorKind::Database, "root_ca_cert_pem"))? + .as_bytes(), + ) + .with_ctx(|_| (ErrorKind::Database, "X509::from_pem"))?, + compat_s9pk_key: SigningKey::generate(&mut rand::thread_rng()), + ssh_key: ssh_key::PrivateKey::random( + &mut rand::thread_rng(), + ssh_key::Algorithm::Ed25519, + ) + .with_ctx(|_| (ErrorKind::Database, "X509::ssh_key::PrivateKey::random"))?, + } + }; + Ok(account) +} +#[tracing::instrument(skip_all)] +async fn previous_ssh_keys(pg: &sqlx::Pool) -> Result { + let ssh_query = sqlx::query(r#"SELECT * FROM ssh_keys"#) + .fetch_all(pg) + .await?; + let ssh_keys: SshKeys = { + let keys = ssh_query.into_iter().fold( + Ok::<_, Error>(BTreeMap::>::new()), + |ssh_keys, row| { + let mut ssh_keys = ssh_keys?; + let time = row + .try_get::("created_at") + .map_err(Error::from) + .and_then(|x| x.parse::>().with_kind(ErrorKind::Database)) + .with_ctx(|_| (ErrorKind::Database, "openssh_pubkey::created_at"))?; + let value: SshPubKey = row + .try_get::("openssh_pubkey") + .map_err(Error::from) + .and_then(|x| x.parse().map(SshPubKey).with_kind(ErrorKind::Database)) + .with_ctx(|_| (ErrorKind::Database, "openssh_pubkey"))?; + let data = WithTimeData { + created_at: time, + updated_at: time, + value, + }; + let fingerprint = row + .try_get::("fingerprint") + .with_ctx(|_| (ErrorKind::Database, "fingerprint"))?; + ssh_keys.insert(fingerprint.into(), data); + Ok(ssh_keys) + }, + )?; + SshKeys::from(keys) + }; + Ok(ssh_keys) +} diff --git a/core/startos/src/version/v0_3_6_alpha_1.rs b/core/startos/src/version/v0_3_6_alpha_1.rs index 8f40c3fde..682486439 100644 --- a/core/startos/src/version/v0_3_6_alpha_1.rs +++ b/core/startos/src/version/v0_3_6_alpha_1.rs @@ -2,7 +2,6 @@ use exver::{PreReleaseSegment, VersionRange}; use super::v0_3_5::V0_3_0_COMPAT; use super::{v0_3_6_alpha_0, VersionT}; -use crate::db::model::Database; use crate::prelude::*; lazy_static::lazy_static! { @@ -12,24 +11,26 @@ lazy_static::lazy_static! { ); } -#[derive(Clone, Debug)] +#[derive(Clone, Copy, Debug, Default)] pub struct Version; impl VersionT for Version { type Previous = v0_3_6_alpha_0::Version; - fn new() -> Self { - Version - } - fn semver(&self) -> exver::Version { - V0_3_6_alpha_1.clone() - } - fn compat(&self) -> &'static VersionRange { - &V0_3_0_COMPAT - } - async fn up(&self, _db: &TypedPatchDb) -> Result<(), Error> { + type PreUpRes = (); + + async fn pre_up(self) -> Result { Ok(()) } - async fn down(&self, _db: &TypedPatchDb) -> Result<(), Error> { + fn semver(self) -> exver::Version { + V0_3_6_alpha_1.clone() + } + fn compat(self) -> &'static VersionRange { + &V0_3_0_COMPAT + } + fn up(self, _db: &mut Value, _: Self::PreUpRes) -> Result<(), Error> { + Ok(()) + } + fn down(self, _db: &mut Value) -> Result<(), Error> { Ok(()) } } diff --git a/core/startos/src/version/v0_3_6_alpha_2.rs b/core/startos/src/version/v0_3_6_alpha_2.rs index 4b26a05dd..cddcc44b2 100644 --- a/core/startos/src/version/v0_3_6_alpha_2.rs +++ b/core/startos/src/version/v0_3_6_alpha_2.rs @@ -2,7 +2,6 @@ use exver::{PreReleaseSegment, VersionRange}; use super::v0_3_5::V0_3_0_COMPAT; use super::{v0_3_6_alpha_1, VersionT}; -use crate::db::model::Database; use crate::prelude::*; lazy_static::lazy_static! { @@ -12,24 +11,26 @@ lazy_static::lazy_static! { ); } -#[derive(Clone, Debug)] +#[derive(Clone, Copy, Debug, Default)] pub struct Version; impl VersionT for Version { type Previous = v0_3_6_alpha_1::Version; - fn new() -> Self { - Version - } - fn semver(&self) -> exver::Version { - V0_3_6_alpha_2.clone() - } - fn compat(&self) -> &'static VersionRange { - &V0_3_0_COMPAT - } - async fn up(&self, _db: &TypedPatchDb) -> Result<(), Error> { + type PreUpRes = (); + + async fn pre_up(self) -> Result { Ok(()) } - async fn down(&self, _db: &TypedPatchDb) -> Result<(), Error> { + fn semver(self) -> exver::Version { + V0_3_6_alpha_2.clone() + } + fn compat(self) -> &'static VersionRange { + &V0_3_0_COMPAT + } + fn up(self, _db: &mut Value, _: Self::PreUpRes) -> Result<(), Error> { + Ok(()) + } + fn down(self, _db: &mut Value) -> Result<(), Error> { Ok(()) } } diff --git a/core/startos/src/version/v0_3_6_alpha_3.rs b/core/startos/src/version/v0_3_6_alpha_3.rs index 3f244a2a0..90164ad60 100644 --- a/core/startos/src/version/v0_3_6_alpha_3.rs +++ b/core/startos/src/version/v0_3_6_alpha_3.rs @@ -2,7 +2,6 @@ use exver::{PreReleaseSegment, VersionRange}; use super::v0_3_5::V0_3_0_COMPAT; use super::{v0_3_6_alpha_2, VersionT}; -use crate::db::model::Database; use crate::prelude::*; lazy_static::lazy_static! { @@ -12,24 +11,26 @@ lazy_static::lazy_static! { ); } -#[derive(Clone, Debug)] +#[derive(Clone, Copy, Debug, Default)] pub struct Version; impl VersionT for Version { type Previous = v0_3_6_alpha_2::Version; - fn new() -> Self { - Version - } - fn semver(&self) -> exver::Version { - V0_3_6_alpha_3.clone() - } - fn compat(&self) -> &'static VersionRange { - &V0_3_0_COMPAT - } - async fn up(&self, _db: &TypedPatchDb) -> Result<(), Error> { + type PreUpRes = (); + + async fn pre_up(self) -> Result { Ok(()) } - async fn down(&self, _db: &TypedPatchDb) -> Result<(), Error> { + fn semver(self) -> exver::Version { + V0_3_6_alpha_3.clone() + } + fn compat(self) -> &'static VersionRange { + &V0_3_0_COMPAT + } + fn up(self, _db: &mut Value, _: Self::PreUpRes) -> Result<(), Error> { + Ok(()) + } + fn down(self, _db: &mut Value) -> Result<(), Error> { Ok(()) } } diff --git a/core/startos/src/version/v0_3_6_alpha_4.rs b/core/startos/src/version/v0_3_6_alpha_4.rs index 0a60764e0..08ff7595e 100644 --- a/core/startos/src/version/v0_3_6_alpha_4.rs +++ b/core/startos/src/version/v0_3_6_alpha_4.rs @@ -2,7 +2,6 @@ use exver::{PreReleaseSegment, VersionRange}; use super::v0_3_5::V0_3_0_COMPAT; use super::{v0_3_6_alpha_3, VersionT}; -use crate::db::model::Database; use crate::prelude::*; lazy_static::lazy_static! { @@ -12,24 +11,26 @@ lazy_static::lazy_static! { ); } -#[derive(Clone, Debug)] +#[derive(Clone, Copy, Debug, Default)] pub struct Version; impl VersionT for Version { type Previous = v0_3_6_alpha_3::Version; - fn new() -> Self { - Version - } - fn semver(&self) -> exver::Version { - V0_3_6_alpha_4.clone() - } - fn compat(&self) -> &'static VersionRange { - &V0_3_0_COMPAT - } - async fn up(&self, _db: &TypedPatchDb) -> Result<(), Error> { + type PreUpRes = (); + + async fn pre_up(self) -> Result { Ok(()) } - async fn down(&self, _db: &TypedPatchDb) -> Result<(), Error> { + fn semver(self) -> exver::Version { + V0_3_6_alpha_4.clone() + } + fn compat(self) -> &'static VersionRange { + &V0_3_0_COMPAT + } + fn up(self, _db: &mut Value, _: Self::PreUpRes) -> Result<(), Error> { + Ok(()) + } + fn down(self, _db: &mut Value) -> Result<(), Error> { Ok(()) } } diff --git a/core/startos/src/version/v0_3_6_alpha_5.rs b/core/startos/src/version/v0_3_6_alpha_5.rs index 1b921d78b..649fe90ca 100644 --- a/core/startos/src/version/v0_3_6_alpha_5.rs +++ b/core/startos/src/version/v0_3_6_alpha_5.rs @@ -2,7 +2,6 @@ use exver::{PreReleaseSegment, VersionRange}; use super::v0_3_5::V0_3_0_COMPAT; use super::{v0_3_6_alpha_4, VersionT}; -use crate::db::model::Database; use crate::prelude::*; lazy_static::lazy_static! { @@ -12,24 +11,26 @@ lazy_static::lazy_static! { ); } -#[derive(Clone, Debug)] +#[derive(Clone, Copy, Debug, Default)] pub struct Version; impl VersionT for Version { type Previous = v0_3_6_alpha_4::Version; - fn new() -> Self { - Version - } - fn semver(&self) -> exver::Version { - V0_3_6_alpha_5.clone() - } - fn compat(&self) -> &'static VersionRange { - &V0_3_0_COMPAT - } - async fn up(&self, _db: &TypedPatchDb) -> Result<(), Error> { + type PreUpRes = (); + + async fn pre_up(self) -> Result { Ok(()) } - async fn down(&self, _db: &TypedPatchDb) -> Result<(), Error> { + fn semver(self) -> exver::Version { + V0_3_6_alpha_5.clone() + } + fn compat(self) -> &'static VersionRange { + &V0_3_0_COMPAT + } + fn up(self, _db: &mut Value, _: Self::PreUpRes) -> Result<(), Error> { + Ok(()) + } + fn down(self, _db: &mut Value) -> Result<(), Error> { Ok(()) } } diff --git a/core/startos/src/version/v0_3_6_alpha_6.rs b/core/startos/src/version/v0_3_6_alpha_6.rs index df91246ae..843e5a45b 100644 --- a/core/startos/src/version/v0_3_6_alpha_6.rs +++ b/core/startos/src/version/v0_3_6_alpha_6.rs @@ -2,7 +2,6 @@ use exver::{PreReleaseSegment, VersionRange}; use super::v0_3_5::V0_3_0_COMPAT; use super::{v0_3_6_alpha_5, VersionT}; -use crate::db::model::Database; use crate::prelude::*; lazy_static::lazy_static! { @@ -12,24 +11,26 @@ lazy_static::lazy_static! { ); } -#[derive(Clone, Debug)] +#[derive(Clone, Copy, Debug, Default)] pub struct Version; impl VersionT for Version { type Previous = v0_3_6_alpha_5::Version; - fn new() -> Self { - Version - } - fn semver(&self) -> exver::Version { - V0_3_6_alpha_6.clone() - } - fn compat(&self) -> &'static VersionRange { - &V0_3_0_COMPAT - } - async fn up(&self, _db: &TypedPatchDb) -> Result<(), Error> { + type PreUpRes = (); + + async fn pre_up(self) -> Result { Ok(()) } - async fn down(&self, _db: &TypedPatchDb) -> Result<(), Error> { + fn semver(self) -> exver::Version { + V0_3_6_alpha_6.clone() + } + fn compat(self) -> &'static VersionRange { + &V0_3_0_COMPAT + } + fn up(self, _db: &mut Value, _: Self::PreUpRes) -> Result<(), Error> { + Ok(()) + } + fn down(self, _db: &mut Value) -> Result<(), Error> { Ok(()) } } 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 7aa63fb2e..bbf9468ff 100644 --- a/core/startos/src/version/v0_3_6_alpha_7.rs +++ b/core/startos/src/version/v0_3_6_alpha_7.rs @@ -1,9 +1,11 @@ use exver::{PreReleaseSegment, VersionRange}; +use imbl_value::{json, InOMap}; +use tokio::process::Command; use super::v0_3_5::V0_3_0_COMPAT; use super::{v0_3_6_alpha_6, VersionT}; -use crate::db::model::Database; use crate::prelude::*; +use crate::util::Invoke; lazy_static::lazy_static! { static ref V0_3_6_alpha_7: exver::Version = exver::Version::new( @@ -12,24 +14,50 @@ lazy_static::lazy_static! { ); } -#[derive(Clone, Debug)] +#[derive(Clone, Copy, Debug, Default)] pub struct Version; impl VersionT for Version { type Previous = v0_3_6_alpha_6::Version; - fn new() -> Self { - Version - } - fn semver(&self) -> exver::Version { - V0_3_6_alpha_7.clone() - } - fn compat(&self) -> &'static VersionRange { - &V0_3_0_COMPAT - } - async fn up(&self, _db: &TypedPatchDb) -> Result<(), Error> { + type PreUpRes = (); + + async fn pre_up(self) -> Result { Ok(()) } - async fn down(&self, _db: &TypedPatchDb) -> Result<(), Error> { + fn semver(self) -> exver::Version { + V0_3_6_alpha_7.clone() + } + fn compat(self) -> &'static VersionRange { + &V0_3_0_COMPAT + } + fn up(self, db: &mut Value, _: Self::PreUpRes) -> Result<(), Error> { + let server_info = db["public"]["serverInfo"] + .as_object_mut() + .or_not_found("public.serverInfo")?; + server_info.insert("ram".into(), json!(0)); + server_info.insert("devices".into(), json!([])); + let package_data = db["public"]["packageData"] + .as_object_mut() + .or_not_found("public.packageData")?; + for (_, pde) in package_data.iter_mut() { + if let Some(manifest) = pde["stateInfo"].get_mut("manifest") { + manifest["hardwareRequirements"]["device"] = json!([]); + } + } + Ok(()) + } + async fn post_up(self, ctx: &crate::context::RpcContext) -> Result<(), Error> { + Command::new("systemd-firstboot") + .arg("--root=/media/startos/config/overlay/") + .arg(format!( + "--hostname={}", + ctx.account.read().await.hostname.0 + )) + .invoke(ErrorKind::ParseSysInfo) + .await?; + Ok(()) + } + fn down(self, _db: &mut Value) -> Result<(), Error> { 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 new file mode 100644 index 000000000..fcef96a69 --- /dev/null +++ b/core/startos/src/version/v0_3_6_alpha_8.rs @@ -0,0 +1,130 @@ +use exver::{PreReleaseSegment, VersionRange}; +use tokio::fs::File; + +use super::v0_3_5::V0_3_0_COMPAT; +use super::{v0_3_6_alpha_7, VersionT}; +use crate::install::PKG_ARCHIVE_DIR; +use crate::prelude::*; +use crate::s9pk::manifest::{DeviceFilter, Manifest}; +use crate::s9pk::merkle_archive::source::multi_cursor_file::MultiCursorFile; +use crate::s9pk::merkle_archive::MerkleArchive; +use crate::s9pk::v2::SIG_CONTEXT; +use crate::s9pk::S9pk; +use crate::service::LoadDisposition; +use crate::util::io::create_file; + +lazy_static::lazy_static! { + static ref V0_3_6_alpha_8: exver::Version = exver::Version::new( + [0, 3, 6], + [PreReleaseSegment::String("alpha".into()), 8.into()] + ); +} + +#[derive(Clone, Copy, Debug, Default)] +pub struct Version; + +impl VersionT for Version { + type Previous = v0_3_6_alpha_7::Version; + type PreUpRes = (); + + async fn pre_up(self) -> Result { + Ok(()) + } + fn semver(self) -> exver::Version { + V0_3_6_alpha_8.clone() + } + fn compat(self) -> &'static VersionRange { + &V0_3_0_COMPAT + } + fn up(self, _: &mut Value, _: Self::PreUpRes) -> Result<(), Error> { + Ok(()) + } + async fn post_up(self, ctx: &crate::context::RpcContext) -> Result<(), Error> { + let s9pk_dir = ctx.datadir.join(PKG_ARCHIVE_DIR).join("installed"); + + if tokio::fs::metadata(&s9pk_dir).await.is_ok() { + let mut read_dir = tokio::fs::read_dir(&s9pk_dir).await?; + while let Some(s9pk_ent) = read_dir.next_entry().await? { + let s9pk_path = s9pk_ent.path(); + let matches_s9pk = s9pk_path.extension().map(|x| x == "s9pk").unwrap_or(false); + if !matches_s9pk { + continue; + } + + let get_archive = async { + let multi_cursor = MultiCursorFile::from(File::open(&s9pk_path).await?); + Ok::<_, Error>(S9pk::archive(&multi_cursor, None).await?) + }; + + let archive: MerkleArchive< + crate::s9pk::merkle_archive::source::Section, + > = match get_archive.await { + Ok(a) => a, + Err(e) => { + tracing::error!("Error opening s9pk for install: {e}"); + tracing::debug!("{e:?}"); + continue; + } + }; + + let previous_manifest: Value = serde_json::from_slice::( + &archive + .contents() + .get_path("manifest.json") + .or_not_found("manifest.json")? + .read_file_to_vec() + .await?, + ) + .with_kind(ErrorKind::Deserialization)? + .into(); + + let mut manifest = previous_manifest.clone(); + + if let Some(device) = + previous_manifest["hardwareRequirements"]["device"].as_object() + { + manifest["hardwareRequirements"]["device"] = to_value( + &device + .into_iter() + .map(|(class, product)| { + Ok::<_, Error>(DeviceFilter { + pattern_description: format!( + "a {class} device matching the expression {}", + &product + ), + class: class.clone(), + pattern: from_value(product.clone())?, + }) + }) + .fold(Ok::<_, Error>(Vec::new()), |acc, value| { + let mut acc = acc?; + acc.push(value?); + Ok(acc) + })?, + )?; + } + + if previous_manifest != manifest { + let tmp_path = s9pk_path.with_extension("s9pk.tmp"); + let mut tmp_file = create_file(&tmp_path).await?; + // TODO, wouldn't this break in the later versions of the manifest that would need changes, this doesn't seem to be a good way to handle this + 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.compat_s9pk_key.clone(); + s9pk.as_archive_mut() + .set_signer(s9pk_compat_key, SIG_CONTEXT); + s9pk.serialize(&mut tmp_file, true).await?; + tmp_file.sync_all().await?; + tokio::fs::rename(&tmp_path, &s9pk_path).await?; + ctx.services.load(ctx, &id, LoadDisposition::Retry).await?; + } + } + } + + Ok(()) + } + fn down(self, _db: &mut Value) -> Result<(), Error> { + Ok(()) + } +} diff --git a/core/startos/startd.service b/core/startos/startd.service index 56cf92e22..6ce17697e 100644 --- a/core/startos/startd.service +++ b/core/startos/startd.service @@ -3,7 +3,7 @@ Description=StartOS Daemon [Service] Type=simple -Environment=RUST_LOG=startos=debug,js_engine=debug,patch_db=warn +Environment=RUST_LOG=startos=debug,patch_db=warn ExecStart=/usr/bin/startd Restart=always RestartSec=3 diff --git a/debian/postinst b/debian/postinst index bbf61f344..d20f778a4 100755 --- a/debian/postinst +++ b/debian/postinst @@ -20,10 +20,15 @@ fi update-initramfs -u -k all if [ -f /etc/default/grub ]; then - sed -i '/\(^\|#\)GRUB_CMDLINE_LINUX=/c\GRUB_CMDLINE_LINUX="boot=startos"' /etc/default/grub + sed -i '/\(^\|#\)GRUB_CMDLINE_LINUX=/c\GRUB_CMDLINE_LINUX="boot=startos console=ttyS0,115200n8"' /etc/default/grub sed -i '/\(^\|#\)GRUB_DISTRIBUTOR=/c\GRUB_DISTRIBUTOR="StartOS v$(cat /usr/lib/startos/VERSION.txt)"' /etc/default/grub + sed -i '/\(^\|#\)GRUB_TERMINAL=/c\GRUB_TERMINAL="serial"\nGRUB_SERIAL_COMMAND="serial --unit=0 --speed=115200 --word=8 --parity=no --stop=1"' /etc/default/grub fi +# set local and remote login prompt +echo "StartOS v$(cat /usr/lib/startos/VERSION.txt) [\m] on \n.local (\l)" > /etc/issue +echo "StartOS v$(cat /usr/lib/startos/VERSION.txt)" > /etc/issue.net + # change timezone rm -f /etc/localtime ln -s /usr/share/zoneinfo/Etc/UTC /etc/localtime @@ -80,6 +85,7 @@ sed -i '/\(^\|#\)ForwardToSyslog=/c\ForwardToSyslog=no' /etc/systemd/journald.co sed -i '/^\s*#\?\s*issue_discards\s*=\s*/c\issue_discards = 1' /etc/lvm/lvm.conf sed -i '/\(^\|#\)\s*unqualified-search-registries\s*=\s*/c\unqualified-search-registries = ["docker.io"]' /etc/containers/registries.conf sed -i 's/\(#\|\^\)\s*\([^=]\+\)=\(suspend\|hibernate\)\s*$/\2=ignore/g' /etc/systemd/logind.conf +sed -i '/\(^\|#\)MulticastDNS=/c\MulticastDNS=no' /etc/systemd/resolved.conf mkdir -p /etc/nginx/ssl @@ -87,6 +93,7 @@ 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 diff --git a/image-recipe/build.sh b/image-recipe/build.sh index 5635e94f3..ae1831704 100755 --- a/image-recipe/build.sh +++ b/image-recipe/build.sh @@ -57,20 +57,14 @@ if [ "$NON_FREE" = 1 ]; then fi fi -PLATFORM_CONFIG_EXTRAS= +PLATFORM_CONFIG_EXTRAS=() if [ "${IB_TARGET_PLATFORM}" = "raspberrypi" ]; then - PLATFORM_CONFIG_EXTRAS="$PLATFORM_CONFIG_EXTRAS --firmware-binary false" - PLATFORM_CONFIG_EXTRAS="$PLATFORM_CONFIG_EXTRAS --firmware-chroot false" - # BEGIN stupid ugly hack - # The actual name of the package is `raspberrypi-kernel` - # live-build determines thte name of the package for the kernel by combining the `linux-packages` flag, with the `linux-flavours` flag - # the `linux-flavours` flag defaults to the architecture, so there's no way to remove the suffix. - # So we're doing this, cause thank the gods our package name contains a hypen. Cause if it didn't we'd be SOL - PLATFORM_CONFIG_EXTRAS="$PLATFORM_CONFIG_EXTRAS --linux-packages raspberrypi" - PLATFORM_CONFIG_EXTRAS="$PLATFORM_CONFIG_EXTRAS --linux-flavours kernel" - # END stupid ugly hack + PLATFORM_CONFIG_EXTRAS+=( --firmware-binary false ) + PLATFORM_CONFIG_EXTRAS+=( --firmware-chroot false ) + PLATFORM_CONFIG_EXTRAS+=( --linux-packages linux-image-6.6.51+rpt ) + PLATFORM_CONFIG_EXTRAS+=( --linux-flavours "rpi-v8 rpi-2712" ) elif [ "${IB_TARGET_PLATFORM}" = "rockchip64" ]; then - PLATFORM_CONFIG_EXTRAS="$PLATFORM_CONFIG_EXTRAS --linux-flavours rockchip64" + PLATFORM_CONFIG_EXTRAS+=( --linux-flavours rockchip64 ) fi @@ -94,7 +88,7 @@ lb config \ --bootstrap-qemu-arch ${IB_TARGET_ARCH} \ --bootstrap-qemu-static /usr/bin/qemu-${QEMU_ARCH}-static \ --archive-areas "${ARCHIVE_AREAS}" \ - $PLATFORM_CONFIG_EXTRAS + ${PLATFORM_CONFIG_EXTRAS[@]} # Overlays @@ -148,13 +142,13 @@ sed -i -e '2i set timeout=5' config/bootloaders/grub-pc/config.cfg mkdir -p config/archives if [ "${IB_TARGET_PLATFORM}" = "raspberrypi" ]; then - curl -fsSL https://archive.raspberrypi.org/debian/raspberrypi.gpg.key | gpg --dearmor -o config/archives/raspi.key - echo "deb https://archive.raspberrypi.org/debian/ bullseye main" > config/archives/raspi.list + curl -fsSL https://archive.raspberrypi.com/debian/raspberrypi.gpg.key | gpg --dearmor -o config/archives/raspi.key + 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: * -Pin: release a=stable-backports +Pin: release n=${IB_SUITE}-backports Pin-Priority: 500 EOF @@ -180,7 +174,7 @@ if [ "$NON_FREE" = 1 ]; then fi if [ "${IB_TARGET_PLATFORM}" = "raspberrypi" ]; then - echo 'raspberrypi-bootloader rpi-update parted' > config/package-lists/bootloader.list.chroot + 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 @@ -205,17 +199,15 @@ if [ "${IB_SUITE}" = bookworm ]; then 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 - update-initramfs -c -k \$v done - ln -sf /usr/bin/pi-beep /usr/local/bin/beep - wget https://archive.raspberrypi.org/debian/pool/main/w/wireless-regdb/wireless-regdb_2018.05.09-0~rpt1_all.deb - echo 1b7b1076257726609535b71d146a5721622d19a0843061ee7568188e836dd10f wireless-regdb_2018.05.09-0~rpt1_all.deb | sha256sum -c - apt-get install -y --allow-downgrades ./wireless-regdb_2018.05.09-0~rpt1_all.deb - rm wireless-regdb_2018.05.09-0~rpt1_all.deb + mkinitramfs -c gzip -o /boot/initramfs8 6.6.51-v8+ + mkinitramfs -c gzip -o /boot/initramfs_2712 6.6.51-v8-16k+ fi useradd --shell /bin/bash -G embassy -m start9 @@ -317,18 +309,31 @@ elif [ "${IMAGE_TYPE}" = img ]; then TMPDIR=$(mktemp -d) - mount `partition_for ${OUTPUT_DEVICE} 2` $TMPDIR - mkdir $TMPDIR/boot + mkdir -p $TMPDIR/boot $TMPDIR/root + mount `partition_for ${OUTPUT_DEVICE} 2` $TMPDIR/root mount `partition_for ${OUTPUT_DEVICE} 1` $TMPDIR/boot - unsquashfs -f -d $TMPDIR $prep_results_dir/binary/live/filesystem.squashfs + unsquashfs -n -f -d $TMPDIR $prep_results_dir/binary/live/filesystem.squashfs boot + + mkdir $TMPDIR/root/images $TMPDIR/root/config + B3SUM=$(b3sum $prep_results_dir/binary/live/filesystem.squashfs | head -c 16) + cp $prep_results_dir/binary/live/filesystem.squashfs $TMPDIR/root/images/$B3SUM.rootfs + ln -rsf $TMPDIR/root/images/$B3SUM.rootfs $TMPDIR/root/config/current.rootfs + + mkdir -p $TMPDIR/next $TMPDIR/lower $TMPDIR/root/config/work $TMPDIR/root/config/overlay + mount $TMPDIR/root/config/current.rootfs $TMPDIR/lower + + mount -t overlay -o lowerdir=$TMPDIR/lower,workdir=$TMPDIR/root/config/work,upperdir=$TMPDIR/root/config/overlay overlay $TMPDIR/next if [ "${IB_TARGET_PLATFORM}" = "raspberrypi" ]; then - sed -i 's| boot=startos| init=/usr/lib/startos/scripts/init_resize\.sh|' $TMPDIR/boot/cmdline.txt - rsync -a $base_dir/raspberrypi/img/ $TMPDIR/ + 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/ fi + umount $TMPDIR/next + umount $TMPDIR/lower + umount $TMPDIR/boot - umount $TMPDIR + umount $TMPDIR/root e2fsck -fy `partition_for ${OUTPUT_DEVICE} 2` resize2fs -M `partition_for ${OUTPUT_DEVICE} 2` diff --git a/image-recipe/prepare.sh b/image-recipe/prepare.sh index 8962d8448..c31f6ada0 100755 --- a/image-recipe/prepare.sh +++ b/image-recipe/prepare.sh @@ -21,7 +21,8 @@ apt-get install -yq \ dosfstools \ e2fsprogs \ squashfs-tools \ - rsync + rsync \ + b3sum # TODO: remove when util-linux is released at v2.39.3 apt-get install -yq \ git \ diff --git a/image-recipe/raspberrypi/img/etc/fstab b/image-recipe/raspberrypi/img/etc/fstab index 816b32bcd..5f5164232 100644 --- a/image-recipe/raspberrypi/img/etc/fstab +++ b/image-recipe/raspberrypi/img/etc/fstab @@ -1,2 +1,2 @@ -/dev/mmcblk0p1 /boot vfat umask=0077 0 2 -/dev/mmcblk0p2 / ext4 defaults 0 1 +/dev/mmcblk0p1 /boot vfat umask=0077 0 2 +/dev/mmcblk0p2 / ext4 defaults 0 1 diff --git a/image-recipe/raspberrypi/img/usr/lib/startos/scripts/init_resize.sh b/image-recipe/raspberrypi/img/usr/lib/startos/scripts/init_resize.sh index cf6489f5f..1fdca1c83 100755 --- a/image-recipe/raspberrypi/img/usr/lib/startos/scripts/init_resize.sh +++ b/image-recipe/raspberrypi/img/usr/lib/startos/scripts/init_resize.sh @@ -1,7 +1,7 @@ #!/bin/bash get_variables () { - ROOT_PART_DEV=$(findmnt / -o source -n) + ROOT_PART_DEV=$(findmnt /media/startos/root -o source -n) ROOT_PART_NAME=$(echo "$ROOT_PART_DEV" | cut -d "/" -f 3) ROOT_DEV_NAME=$(echo /sys/block/*/"${ROOT_PART_NAME}" | cut -d "/" -f 4) ROOT_DEV="/dev/${ROOT_DEV_NAME}" @@ -89,12 +89,12 @@ main () { resize2fs $ROOT_PART_DEV - if ! systemd-machine-id-setup; then + if ! systemd-machine-id-setup --root=/media/startos/config/overlay/; then FAIL_REASON="systemd-machine-id-setup failed" return 1 fi - if ! ssh-keygen -A; then + if ! (mkdir -p /media/startos/config/overlay/etc/ssh && ssh-keygen -A -f /media/startos/config/overlay/); then FAIL_REASON="ssh host key generation failed" return 1 fi @@ -104,9 +104,6 @@ main () { return 0 } -mount -t proc proc /proc -mount -t sysfs sys /sys -mount -t tmpfs tmp /run mkdir -p /run/systemd mount /boot mount / -o remount,ro @@ -114,7 +111,7 @@ mount / -o remount,ro beep if main; then - sed -i 's| init=/usr/lib/startos/scripts/init_resize\.sh| boot=startos|' /boot/cmdline.txt + sed -i 's| init=/usr/lib/startos/scripts/init_resize\.sh||' /boot/cmdline.txt echo "Resized root filesystem. Rebooting in 5 seconds..." sleep 5 else diff --git a/image-recipe/raspberrypi/squashfs/boot/config.txt b/image-recipe/raspberrypi/squashfs/boot/config.txt index 17bd5dc4e..4e1962a65 100644 --- a/image-recipe/raspberrypi/squashfs/boot/config.txt +++ b/image-recipe/raspberrypi/squashfs/boot/config.txt @@ -83,4 +83,5 @@ arm_boost=1 [all] gpu_mem=16 dtoverlay=pwm-2chan,disable-bt -initramfs initrd.img-6.1.21-v8+ + +auto_initramfs=1 \ No newline at end of file diff --git a/image-recipe/raspberrypi/squashfs/etc/embassy/config.yaml b/image-recipe/raspberrypi/squashfs/etc/startos/config.yaml similarity index 100% rename from image-recipe/raspberrypi/squashfs/etc/embassy/config.yaml rename to image-recipe/raspberrypi/squashfs/etc/startos/config.yaml diff --git a/sdk/.gitignore b/sdk/.gitignore index a7ca92b2d..1ac0f02e6 100644 --- a/sdk/.gitignore +++ b/sdk/.gitignore @@ -1,5 +1,6 @@ -.vscode dist/ -node_modules/ -lib/coverage -lib/test/output.ts \ No newline at end of file +baseDist/ +base/lib/coverage +base/lib/node_modules +package/lib/coverage +package/lib/node_modules \ No newline at end of file diff --git a/sdk/.prettierignore b/sdk/.prettierignore index 19b24bbe8..149281301 100644 --- a/sdk/.prettierignore +++ b/sdk/.prettierignore @@ -1 +1 @@ -/lib/exver/exver.ts \ No newline at end of file +/base/lib/exver/exver.ts \ No newline at end of file diff --git a/sdk/Makefile b/sdk/Makefile index 660a476c4..3f8ae533a 100644 --- a/sdk/Makefile +++ b/sdk/Makefile @@ -1,47 +1,73 @@ -TS_FILES := $(shell git ls-files lib) lib/test/output.ts +PACKAGE_TS_FILES := $(shell git ls-files package/lib) package/lib/test/output.ts +BASE_TS_FILES := $(shell git ls-files base/lib) package/lib/test/output.ts version = $(shell git tag --sort=committerdate | tail -1) -.PHONY: test clean bundle fmt buildOutput check +.PHONY: test base/test package/test clean bundle fmt buildOutput check all: bundle -test: $(TS_FILES) lib/test/output.ts - npm test +package/test: $(PACKAGE_TS_FILES) package/lib/test/output.ts package/node_modules base/node_modules + cd package && npm test + +base/test: $(BASE_TS_FILES) base/node_modules + cd base && npm test + +test: base/test package/test clean: + rm -rf base/node_modules rm -rf dist - rm -f lib/test/output.ts - rm -rf node_modules + rm -rf baseDist + rm -f package/lib/test/output.ts + rm -rf package/node_modules -lib/test/output.ts: node_modules lib/test/makeOutput.ts scripts/oldSpecToBuilder.ts - npm run buildOutput +package/lib/test/output.ts: package/node_modules package/lib/test/makeOutput.ts package/scripts/oldSpecToBuilder.ts + cd package && npm run buildOutput -bundle: dist | test fmt +bundle: baseDist dist | test fmt touch dist -lib/exver/exver.ts: node_modules lib/exver/exver.pegjs - npx peggy --allowed-start-rules '*' --plugin ./node_modules/ts-pegjs/dist/tspegjs -o lib/exver/exver.ts lib/exver/exver.pegjs +base/lib/exver/exver.ts: base/node_modules base/lib/exver/exver.pegjs + cd base && npm run peggy -dist: $(TS_FILES) package.json node_modules README.md LICENSE - npx tsc - npx tsc --project tsconfig-cjs.json - cp package.json dist/package.json - cp README.md dist/README.md - cp LICENSE dist/LICENSE +baseDist: $(PACKAGE_TS_FILES) $(BASE_TS_FILES) base/package.json base/node_modules base/README.md base/LICENSE + (cd base && npm run tsc) + rsync -ac base/node_modules baseDist/ + cp base/package.json baseDist/package.json + cp base/README.md baseDist/README.md + cp base/LICENSE baseDist/LICENSE + touch baseDist + +dist: $(PACKAGE_TS_FILES) $(BASE_TS_FILES) package/package.json package/.npmignore package/node_modules package/README.md package/LICENSE + (cd package && npm run tsc) + rsync -ac package/node_modules dist/ + cp package/.npmignore dist/.npmignore + cp package/package.json dist/package.json + cp package/README.md dist/README.md + cp package/LICENSE dist/LICENSE touch dist full-bundle: bundle check: + cd package + npm run check + cd ../base npm run check -fmt: node_modules +fmt: package/node_modules base/node_modules npx prettier . "**/*.ts" --write -node_modules: package.json - npm ci -publish: bundle package.json README.md LICENSE +package/node_modules: package/package.json + cd package && npm ci + +base/node_modules: base/package.json + cd base && npm ci + +node_modules: package/node_modules base/node_modules + +publish: bundle package/package.json package/README.md package/LICENSE cd dist && npm publish --access=public link: bundle diff --git a/sdk/base/.gitignore b/sdk/base/.gitignore new file mode 100644 index 000000000..a7ca92b2d --- /dev/null +++ b/sdk/base/.gitignore @@ -0,0 +1,5 @@ +.vscode +dist/ +node_modules/ +lib/coverage +lib/test/output.ts \ No newline at end of file diff --git a/sdk/LICENSE b/sdk/base/LICENSE similarity index 100% rename from sdk/LICENSE rename to sdk/base/LICENSE diff --git a/sdk/base/README.md b/sdk/base/README.md new file mode 100644 index 000000000..33bf5ff9d --- /dev/null +++ b/sdk/base/README.md @@ -0,0 +1 @@ +# See ../package/README.md diff --git a/sdk/jest.config.js b/sdk/base/jest.config.js similarity index 100% rename from sdk/jest.config.js rename to sdk/base/jest.config.js diff --git a/sdk/base/lib/Effects.ts b/sdk/base/lib/Effects.ts new file mode 100644 index 000000000..00d56cfba --- /dev/null +++ b/sdk/base/lib/Effects.ts @@ -0,0 +1,197 @@ +import { + ActionId, + ActionInput, + ActionMetadata, + SetMainStatus, + DependencyRequirement, + CheckDependenciesResult, + SetHealth, + BindParams, + HostId, + LanInfo, + Host, + ExportServiceInterfaceParams, + ServiceInterface, + ActionRequest, + RequestActionParams, + MainStatus, +} from "./osBindings" +import { StorePath } from "./util/PathBuilder" +import { + PackageId, + Dependencies, + ServiceInterfaceId, + SmtpValue, + ActionResult, +} from "./types" +import { UrlString } from "./util/getServiceInterface" + +/** Used to reach out from the pure js runtime */ + +export type Effects = { + constRetry: () => void + clearCallbacks: ( + options: { only: number[] } | { except: number[] }, + ) => Promise + + // action + action: { + /** Define an action that can be invoked by a user or service */ + export(options: { id: ActionId; metadata: ActionMetadata }): Promise + /** Remove all exported actions */ + clear(options: { except: ActionId[] }): Promise + getInput(options: { + packageId?: PackageId + actionId: ActionId + }): Promise + run>(options: { + packageId?: PackageId + actionId: ActionId + input?: Input + }): Promise + request>( + options: RequestActionParams, + ): Promise + clearRequests( + options: { only: string[] } | { except: string[] }, + ): Promise + } + + // control + /** restart this service's main function */ + restart(): Promise + /** stop this service's main function */ + shutdown(): Promise + /** ask the host os what the service's current status is */ + getStatus(options: { + packageId?: PackageId + callback?: () => void + }): Promise + /** indicate to the host os what runstate the service is in */ + setMainStatus(options: SetMainStatus): Promise + + // dependency + /** Set the dependencies of what the service needs, usually run during the inputSpec action as a best practice */ + setDependencies(options: { dependencies: Dependencies }): Promise + /** Get the list of the dependencies, both the dynamic set by the effect of setDependencies and the end result any required in the manifest */ + getDependencies(): Promise + /** Test whether current dependency requirements are satisfied */ + checkDependencies(options: { + packageIds?: PackageId[] + }): Promise + /** mount a volume of a dependency */ + mount(options: { + location: string + target: { + packageId: string + volumeId: string + subpath: string | null + readonly: boolean + } + }): Promise + /** Returns a list of the ids of all installed packages */ + getInstalledPackages(): Promise + /** grants access to certain paths in the store to dependents */ + exposeForDependents(options: { paths: string[] }): Promise + + // health + /** sets the result of a health check */ + setHealth(o: SetHealth): Promise + + // subcontainer + subcontainer: { + /** A low level api used by SubContainer */ + createFs(options: { + imageId: string + name: string | null + }): Promise<[string, string]> + /** A low level api used by SubContainer */ + destroyFs(options: { guid: string }): Promise + } + + // net + // bind + /** Creates a host connected to the specified port with the provided options */ + bind(options: BindParams): Promise + /** Get the port address for a service */ + getServicePortForward(options: { + packageId?: PackageId + hostId: HostId + internalPort: number + }): Promise + /** Removes all network bindings, called in the setupInputSpec */ + clearBindings(options: { + except: { id: HostId; internalPort: number }[] + }): Promise + // host + /** Returns information about the specified host, if it exists */ + getHostInfo(options: { + packageId?: PackageId + hostId: HostId + callback?: () => void + }): Promise + /** Returns the primary url that a user has selected for a host, if it exists */ + getPrimaryUrl(options: { + packageId?: PackageId + hostId: HostId + callback?: () => void + }): Promise + /** Returns the IP address of the container */ + getContainerIp(): Promise + // interface + /** Creates an interface bound to a specific host and port to show to the user */ + exportServiceInterface(options: ExportServiceInterfaceParams): Promise + /** Returns an exported service interface */ + getServiceInterface(options: { + packageId?: PackageId + serviceInterfaceId: ServiceInterfaceId + callback?: () => void + }): Promise + /** Returns all exported service interfaces for a package */ + listServiceInterfaces(options: { + packageId?: PackageId + callback?: () => void + }): Promise> + /** Removes all service interfaces */ + clearServiceInterfaces(options: { + except: ServiceInterfaceId[] + }): Promise + // ssl + /** Returns a PEM encoded fullchain for the hostnames specified */ + getSslCertificate: (options: { + hostnames: string[] + algorithm?: "ecdsa" | "ed25519" + callback?: () => void + }) => Promise<[string, string, string]> + /** Returns a PEM encoded private key corresponding to the certificate for the hostnames specified */ + getSslKey: (options: { + hostnames: string[] + algorithm?: "ecdsa" | "ed25519" + }) => Promise + + // store + store: { + /** Get a value in a json like data, can be observed and subscribed */ + get(options: { + /** If there is no packageId it is assumed the current package */ + packageId?: string + /** The path defaults to root level, using the [JsonPath](https://jsonpath.com/) */ + path: StorePath + callback?: () => void + }): Promise + /** Used to store values that can be accessed and subscribed to */ + set(options: { + /** Sets the value for the wrapper at the path, it will override, using the [JsonPath](https://jsonpath.com/) */ + path: StorePath + value: ExtractStore + }): Promise + } + /** sets the version that this service's data has been migrated to */ + setDataVersion(options: { version: string }): Promise + /** returns the version that this service's data has been migrated to */ + getDataVersion(): Promise + + // system + /** Returns globally configured SMTP settings, if they exist */ + getSystemSmtp(options: { callback?: () => void }): Promise +} diff --git a/sdk/base/lib/actions/index.ts b/sdk/base/lib/actions/index.ts new file mode 100644 index 000000000..4bcbec8b1 --- /dev/null +++ b/sdk/base/lib/actions/index.ts @@ -0,0 +1,100 @@ +import * as T from "../types" +import * as IST from "../actions/input/inputSpecTypes" +import { Action } from "./setupActions" +import { ExtractInputSpecType } from "./input/builder/inputSpec" + +export type RunActionInput = + | Input + | ((prev?: { spec: IST.InputSpec; value: Input | null }) => Input) + +export const runAction = async < + Input extends Record, +>(options: { + effects: T.Effects + // packageId?: T.PackageId + actionId: T.ActionId + input?: RunActionInput +}) => { + if (options.input) { + if (options.input instanceof Function) { + const prev = await options.effects.action.getInput({ + // packageId: options.packageId, + actionId: options.actionId, + }) + const input = options.input( + prev + ? { spec: prev.spec as IST.InputSpec, value: prev.value as Input } + : undefined, + ) + return options.effects.action.run({ + // packageId: options.packageId, + actionId: options.actionId, + input, + }) + } else { + return options.effects.action.run({ + // packageId: options.packageId, + actionId: options.actionId, + input: options.input, + }) + } + } else { + return options.effects.action.run({ + // packageId: options.packageId, + actionId: options.actionId, + }) + } +} +type GetActionInputType> = + A extends Action ? ExtractInputSpecType : never + +type ActionRequestBase = { + reason?: string + replayId?: string +} +type ActionRequestInput> = { + kind: "partial" + value: Partial> +} +export type ActionRequestOptions> = + ActionRequestBase & + ( + | { + when?: Exclude< + T.ActionRequestTrigger, + { condition: "input-not-matches" } + > + input?: ActionRequestInput + } + | { + when: T.ActionRequestTrigger & { condition: "input-not-matches" } + input: ActionRequestInput + } + ) + +const _validate: T.ActionRequest = {} as ActionRequestOptions & { + actionId: string + packageId: string + severity: T.ActionSeverity +} + +export const requestAction = >(options: { + effects: T.Effects + packageId: T.PackageId + action: T + severity: T.ActionSeverity + options?: ActionRequestOptions +}) => { + const request = options.options || {} + const actionId = options.action.id + const req = { + ...request, + actionId, + packageId: options.packageId, + action: undefined, + severity: options.severity, + replayId: request.replayId || `${options.packageId}:${actionId}`, + } + delete req.action + return options.effects.action.request(req) +} diff --git a/sdk/lib/config/builder/index.ts b/sdk/base/lib/actions/input/builder/index.ts similarity index 51% rename from sdk/lib/config/builder/index.ts rename to sdk/base/lib/actions/input/builder/index.ts index 6b6ddc730..618c4856f 100644 --- a/sdk/lib/config/builder/index.ts +++ b/sdk/base/lib/actions/input/builder/index.ts @@ -1,6 +1,6 @@ -import { Config } from "./config" +import { InputSpec } from "./inputSpec" import { List } from "./list" import { Value } from "./value" import { Variants } from "./variants" -export { Config, List, Value, Variants } +export { InputSpec as InputSpec, List, Value, Variants } diff --git a/sdk/lib/config/builder/config.ts b/sdk/base/lib/actions/input/builder/inputSpec.ts similarity index 67% rename from sdk/lib/config/builder/config.ts rename to sdk/base/lib/actions/input/builder/inputSpec.ts index c30f37890..31e06df4f 100644 --- a/sdk/lib/config/builder/config.ts +++ b/sdk/base/lib/actions/input/builder/inputSpec.ts @@ -1,8 +1,9 @@ -import { ValueSpec } from "../configTypes" +import { ValueSpec } from "../inputSpecTypes" import { Value } from "./value" -import { _ } from "../../util" -import { Effects } from "../../types" +import { _ } from "../../../util" +import { Effects } from "../../../Effects" import { Parser, object } from "ts-matches" +import { DeepPartial } from "../../../types" export type LazyBuildOptions = { effects: Effects @@ -12,20 +13,29 @@ export type LazyBuild = ( ) => Promise | ExpectedOut // prettier-ignore -export type ExtractConfigType | Config, any> | Config, never>> = - A extends Config | Config ? B : +export type ExtractInputSpecType | InputSpec, any> | InputSpec, never>> = + A extends InputSpec | InputSpec ? B : A -export type ConfigSpecOf, Store = never> = { +export type ExtractPartialInputSpecType< + A extends + | Record + | InputSpec, any> + | InputSpec, never>, +> = A extends InputSpec | InputSpec + ? DeepPartial + : DeepPartial + +export type InputSpecOf, Store = never> = { [K in keyof A]: Value } export type MaybeLazyValues = LazyBuild | A /** - * Configs are the specs that are used by the os configuration form for this service. - * Here is an example of a simple configuration + * InputSpecs are the specs that are used by the os input specification form for this service. + * Here is an example of a simple input specification ```ts - const smallConfig = Config.of({ + const smallInputSpec = InputSpec.of({ test: Value.boolean({ name: "Test", description: "This is the description for the test", @@ -35,17 +45,17 @@ export type MaybeLazyValues = LazyBuild | A }); ``` - The idea of a config is that now the form is going to ask for + The idea of an inputSpec is that now the form is going to ask for Test: [ ] and the value is going to be checked as a boolean. There are more complex values like selects, lists, and objects. See {@link Value} - Also, there is the ability to get a validator/parser from this config spec. + Also, there is the ability to get a validator/parser from this inputSpec spec. ```ts - const matchSmallConfig = smallConfig.validator(); - type SmallConfig = typeof matchSmallConfig._TYPE; + const matchSmallInputSpec = smallInputSpec.validator(); + type SmallInputSpec = typeof matchSmallInputSpec._TYPE; ``` - Here is an example of a more complex configuration which came from a configuration for a service + Here is an example of a more complex input specification which came from an input specification for a service that works with bitcoin, like c-lightning. ```ts @@ -73,17 +83,19 @@ export const port = Value.number({ units: null, placeholder: null, }); -export const addNodesSpec = Config.of({ hostname: hostname, port: port }); +export const addNodesSpec = InputSpec.of({ hostname: hostname, port: port }); ``` */ -export class Config, Store = never> { +export class InputSpec, Store = never> { private constructor( private readonly spec: { [K in keyof Type]: Value | Value }, public validator: Parser, ) {} + _TYPE: Type = null as any as Type + _PARTIAL: DeepPartial = null as any as DeepPartial async build(options: LazyBuildOptions) { const answer = {} as { [K in keyof Type]: ValueSpec @@ -105,7 +117,7 @@ export class Config, Store = never> { validatorObj[key] = spec[key].validator } const validator = object(validatorObj) - return new Config< + return new InputSpec< { [K in keyof Spec]: Spec[K] extends | Value @@ -119,19 +131,19 @@ export class Config, Store = never> { /** * Use this during the times that the input needs a more specific type. - * Used in types that the value/ variant/ list/ config is constructed somewhere else. + * Used in types that the value/ variant/ list/ inputSpec is constructed somewhere else. ```ts - const a = Config.text({ + const a = InputSpec.text({ name: "a", required: false, }) - return Config.of()({ + return InputSpec.of()({ myValue: a.withStore(), }) ``` */ withStore() { - return this as any as Config + return this as any as InputSpec } } diff --git a/sdk/lib/config/builder/list.ts b/sdk/base/lib/actions/input/builder/list.ts similarity index 74% rename from sdk/lib/config/builder/list.ts rename to sdk/base/lib/actions/input/builder/list.ts index f230b8608..726dc961e 100644 --- a/sdk/lib/config/builder/list.ts +++ b/sdk/base/lib/actions/input/builder/list.ts @@ -1,4 +1,4 @@ -import { Config, LazyBuild } from "./config" +import { InputSpec, LazyBuild } from "./inputSpec" import { ListValueSpecText, Pattern, @@ -6,45 +6,55 @@ import { UniqueBy, ValueSpecList, ValueSpecListOf, -} from "../configTypes" -import { Parser, arrayOf, number, string } from "ts-matches" -/** - * Used as a subtype of Value.list -```ts -export const authorizationList = List.string({ - "name": "Authorization", - "range": "[0,*)", - "default": [], - "description": "Username and hashed password for JSON-RPC connections. RPC clients connect using the usual http basic authentication.", - "warning": null -}, {"masked":false,"placeholder":null,"pattern":"^[a-zA-Z0-9_-]+:([0-9a-fA-F]{2})+\\$([0-9a-fA-F]{2})+$","patternDescription":"Each item must be of the form \":$\"."}); -export const auth = Value.list(authorizationList); -``` -*/ +} from "../inputSpecTypes" +import { Parser, arrayOf, string } from "ts-matches" + export class List { private constructor( public build: LazyBuild, public validator: Parser, ) {} + static text( a: { name: string description?: string | null warning?: string | null - /** Default = [] */ default?: string[] minLength?: number | null maxLength?: number | null }, aSpec: { - /** Default = false */ + /** + * @description Mask (aka camouflage) text input with dots: ● ● ● + * @default false + */ masked?: boolean placeholder?: string | null minLength?: number | null maxLength?: number | null - patterns: Pattern[] - /** Default = "text" */ + /** + * @description A list of regular expressions to which the text must conform to pass validation. A human readable description is provided in case the validation fails. + * @default [] + * @example + * ``` + [ + { + regex: "[a-z]", + description: "May only contain lower case letters from the English alphabet." + } + ] + * ``` + */ + patterns?: Pattern[] + /** + * @description Informs the browser how to behave and which keyboard to display on mobile + * @default "text" + */ inputmode?: ListValueSpecText["inputmode"] + /** + * @description Displays a button that will generate a random string according to the provided charset and len attributes. + */ generate?: null | RandomString }, ) { @@ -57,6 +67,7 @@ export class List { masked: false, inputmode: "text" as const, generate: null, + patterns: aSpec.patterns || [], ...aSpec, } const built: ValueSpecListOf<"text"> = { @@ -73,6 +84,7 @@ export class List { return built }, arrayOf(string)) } + static dynamicText( getA: LazyBuild< Store, @@ -80,20 +92,17 @@ export class List { name: string description?: string | null warning?: string | null - /** Default = [] */ default?: string[] minLength?: number | null maxLength?: number | null disabled?: false | string generate?: null | RandomString spec: { - /** Default = false */ masked?: boolean placeholder?: string | null minLength?: number | null maxLength?: number | null - patterns: Pattern[] - /** Default = "text" */ + patterns?: Pattern[] inputmode?: ListValueSpecText["inputmode"] } } @@ -109,6 +118,7 @@ export class List { masked: false, inputmode: "text" as const, generate: null, + patterns: aSpec.patterns || [], ...aSpec, } const built: ValueSpecListOf<"text"> = { @@ -125,18 +135,18 @@ export class List { return built }, arrayOf(string)) } + static obj, Store>( a: { name: string description?: string | null warning?: string | null - /** Default [] */ default?: [] minLength?: number | null maxLength?: number | null }, aSpec: { - spec: Config + spec: InputSpec displayAs?: null | string uniqueBy?: null | UniqueBy }, @@ -170,14 +180,14 @@ export class List { /** * Use this during the times that the input needs a more specific type. - * Used in types that the value/ variant/ list/ config is constructed somewhere else. + * Used in types that the value/ variant/ list/ inputSpec is constructed somewhere else. ```ts - const a = Config.text({ + const a = InputSpec.text({ name: "a", required: false, }) - return Config.of()({ + return InputSpec.of()({ myValue: a.withStore(), }) ``` diff --git a/sdk/lib/config/builder/value.ts b/sdk/base/lib/actions/input/builder/value.ts similarity index 54% rename from sdk/lib/config/builder/value.ts rename to sdk/base/lib/actions/input/builder/value.ts index 01673a6df..676c4aac1 100644 --- a/sdk/lib/config/builder/value.ts +++ b/sdk/base/lib/actions/input/builder/value.ts @@ -1,4 +1,4 @@ -import { Config, LazyBuild, LazyBuildOptions } from "./config" +import { InputSpec, LazyBuild } from "./inputSpec" import { List } from "./list" import { Variants } from "./variants" import { @@ -7,13 +7,15 @@ import { RandomString, ValueSpec, ValueSpecDatetime, + ValueSpecHidden, ValueSpecText, ValueSpecTextarea, -} from "../configTypes" -import { DefaultString } from "../configTypes" -import { _ } from "../../util" +} from "../inputSpecTypes" +import { DefaultString } from "../inputSpecTypes" +import { _, once } from "../../../util" import { Parser, + any, anyOf, arrayOf, boolean, @@ -24,77 +26,24 @@ import { string, unknown, } from "ts-matches" -import { once } from "../../util/once" +import { DeepPartial } from "../../../types" -export type RequiredDefault = - | false - | { - default: A | null - } +type AsRequired = Required extends true + ? T + : T | null -function requiredLikeToAbove, A>( - requiredLike: Input, -) { - // prettier-ignore - return { - required: (typeof requiredLike === 'object' ? true : requiredLike) as ( - Input extends { default: unknown} ? true: - Input extends true ? true : - false - ), - default:(typeof requiredLike === 'object' ? requiredLike.default : null) as ( - Input extends { default: infer Default } ? Default : - null - ) - }; -} -type AsRequired = MaybeRequiredType extends - | { default: unknown } - | never - ? Type - : Type | null | undefined - -type InputAsRequired = A extends - | { required: { default: any } | never } - | never - ? Type - : Type | null | undefined const testForAsRequiredParser = once( - () => object({ required: object({ default: unknown }) }).test, + () => object({ required: literal(true) }).test, ) function asRequiredParser< Type, Input, - Return extends - | Parser - | Parser, + Return extends Parser | Parser, >(parser: Parser, input: Input): Return { if (testForAsRequiredParser()(input)) return parser as any - return parser.optional() as any + return parser.nullable() as any } -/** - * A value is going to be part of the form in the FE of the OS. - * Something like a boolean, a string, a number, etc. - * in the fe it will ask for the name of value, and use the rest of the value to determine how to render it. - * While writing with a value, you will start with `Value.` then let the IDE suggest the rest. - * for things like string, the options are going to be in {}. - * Keep an eye out for another config builder types as params. - * Note, usually this is going to be used in a `Config` {@link Config} builder. - ```ts -const username = Value.string({ - name: "Username", - default: "bitcoin", - description: "The username for connecting to Bitcoin over RPC.", - warning: null, - required: true, - masked: true, - placeholder: null, - pattern: "^[a-zA-Z0-9_]+$", - patternDescription: "Must be alphanumeric (can contain underscore).", -}); - ``` - */ export class Value { protected constructor( public build: LazyBuild, @@ -103,10 +52,13 @@ export class Value { static toggle(a: { name: string description?: string | null + /** Presents a warning prompt before permitting the value to change. */ warning?: string | null default: boolean - /** Immutable means it can only be configed at the first config then never again - Default is false */ + /** + * @description Once set, the value can never be changed. + * @default false + */ immutable?: boolean }) { return new Value( @@ -145,25 +97,56 @@ export class Value { boolean, ) } - static text>(a: { + static text(a: { name: string description?: string | null + /** Presents a warning prompt before permitting the value to change. */ warning?: string | null + /** + * provide a default value. + * @type { string | RandomString | null } + * @example default: null + * @example default: 'World' + * @example default: { charset: 'abcdefg', len: 16 } + */ + default: string | RandomString | null required: Required - - /** Default = false */ + /** + * @description Mask (aka camouflage) text input with dots: ● ● ● + * @default false + */ masked?: boolean placeholder?: string | null minLength?: number | null maxLength?: number | null + /** + * @description A list of regular expressions to which the text must conform to pass validation. A human readable description is provided in case the validation fails. + * @default [] + * @example + * ``` + [ + { + regex: "[a-z]", + description: "May only contain lower case letters from the English alphabet." + } + ] + * ``` + */ patterns?: Pattern[] - /** Default = 'text' */ + /** + * @description Informs the browser how to behave and which keyboard to display on mobile + * @default "text" + */ inputmode?: ValueSpecText["inputmode"] - /** Immutable means it can only be configured at the first config then never again - * Default is false + /** + * @description Once set, the value can never be changed. + * @default false */ immutable?: boolean - generate?: null | RandomString + /** + * @description Displays a button that will generate a random string according to the provided charset and len attributes. + */ + generate?: RandomString | null }) { return new Value, never>( async () => ({ @@ -180,7 +163,6 @@ export class Value { immutable: a.immutable ?? false, generate: a.generate ?? null, ...a, - ...requiredLikeToAbove(a.required), }), asRequiredParser(string, a), ) @@ -192,25 +174,20 @@ export class Value { name: string description?: string | null warning?: string | null - required: RequiredDefault - - /** Default = false */ + default: DefaultString | null + required: boolean masked?: boolean placeholder?: string | null minLength?: number | null maxLength?: number | null patterns?: Pattern[] - /** Default = 'text' */ inputmode?: ValueSpecText["inputmode"] disabled?: string | false - /** Immutable means it can only be configured at the first config then never again - * Default is false - */ generate?: null | RandomString } >, ) { - return new Value(async (options) => { + return new Value(async (options) => { const a = await getA(options) return { type: "text" as const, @@ -226,36 +203,42 @@ export class Value { immutable: false, generate: a.generate ?? null, ...a, - ...requiredLikeToAbove(a.required), } - }, string.optional()) + }, string.nullable()) } - static textarea(a: { + static textarea(a: { name: string description?: string | null + /** Presents a warning prompt before permitting the value to change. */ warning?: string | null - required: boolean + default: string | null + required: Required minLength?: number | null maxLength?: number | null placeholder?: string | null - /** Immutable means it can only be configed at the first config then never again - Default is false */ + /** + * @description Once set, the value can never be changed. + * @default false + */ immutable?: boolean }) { - return new Value(async () => { - const built: ValueSpecTextarea = { - description: null, - warning: null, - minLength: null, - maxLength: null, - placeholder: null, - type: "textarea" as const, - disabled: false, - immutable: a.immutable ?? false, - ...a, - } - return built - }, string) + return new Value, never>( + async () => { + const built: ValueSpecTextarea = { + description: null, + warning: null, + minLength: null, + maxLength: null, + placeholder: null, + type: "textarea" as const, + disabled: false, + immutable: a.immutable ?? false, + ...a, + } + return built + }, + asRequiredParser(string, a), + ) } static dynamicTextarea( getA: LazyBuild< @@ -264,6 +247,7 @@ export class Value { name: string description?: string | null warning?: string | null + default: string | null required: boolean minLength?: number | null maxLength?: number | null @@ -272,7 +256,7 @@ export class Value { } >, ) { - return new Value(async (options) => { + return new Value(async (options) => { const a = await getA(options) return { description: null, @@ -285,22 +269,41 @@ export class Value { immutable: false, ...a, } - }, string) + }, string.nullable()) } - static number>(a: { + static number(a: { name: string description?: string | null + /** Presents a warning prompt before permitting the value to change. */ warning?: string | null + /** + * @description optionally provide a default value. + * @type { default: number | null } + * @example default: null + * @example default: 7 + */ + default: number | null required: Required min?: number | null max?: number | null - /** Default = '1' */ + /** + * @description How much does the number increase/decrease when using the arrows provided by the browser. + * @default 1 + */ step?: number | null + /** + * @description Requires the number to be an integer. + */ integer: boolean + /** + * @description Optionally display units to the right of the input box. + */ units?: string | null placeholder?: string | null - /** Immutable means it can only be configed at the first config then never again - Default is false */ + /** + * @description Once set, the value can never be changed. + * @default false + */ immutable?: boolean }) { return new Value, never>( @@ -316,7 +319,6 @@ export class Value { disabled: false, immutable: a.immutable ?? false, ...a, - ...requiredLikeToAbove(a.required), }), asRequiredParser(number, a), ) @@ -328,10 +330,10 @@ export class Value { name: string description?: string | null warning?: string | null - required: RequiredDefault + default: number | null + required: boolean min?: number | null max?: number | null - /** Default = '1' */ step?: number | null integer: boolean units?: string | null @@ -340,7 +342,7 @@ export class Value { } >, ) { - return new Value(async (options) => { + return new Value(async (options) => { const a = await getA(options) return { type: "number" as const, @@ -354,17 +356,26 @@ export class Value { disabled: false, immutable: false, ...a, - ...requiredLikeToAbove(a.required), } - }, number.optional()) + }, number.nullable()) } - static color>(a: { + static color(a: { name: string description?: string | null + /** Presents a warning prompt before permitting the value to change. */ warning?: string | null + /** + * @description optionally provide a default value. + * @type { default: string | null } + * @example default: null + * @example default: 'ffffff' + */ + default: string | null required: Required - /** Immutable means it can only be configed at the first config then never again - Default is false */ + /** + * @description Once set, the value can never be changed. + * @default false + */ immutable?: boolean }) { return new Value, never>( @@ -375,9 +386,7 @@ export class Value { disabled: false, immutable: a.immutable ?? false, ...a, - ...requiredLikeToAbove(a.required), }), - asRequiredParser(string, a), ) } @@ -389,12 +398,13 @@ export class Value { name: string description?: string | null warning?: string | null - required: RequiredDefault + default: string | null + required: boolean disabled?: false | string } >, ) { - return new Value(async (options) => { + return new Value(async (options) => { const a = await getA(options) return { type: "color" as const, @@ -403,21 +413,33 @@ export class Value { disabled: false, immutable: false, ...a, - ...requiredLikeToAbove(a.required), } - }, string.optional()) + }, string.nullable()) } - static datetime>(a: { + static datetime(a: { name: string description?: string | null + /** Presents a warning prompt before permitting the value to change. */ warning?: string | null + /** + * @description optionally provide a default value. + * @type { default: string | null } + * @example default: null + * @example default: '1985-12-16 18:00:00.000' + */ + default: string | null required: Required - /** Default = 'datetime-local' */ + /** + * @description Informs the browser how to behave and which date/time component to display. + * @default "datetime-local" + */ inputmode?: ValueSpecDatetime["inputmode"] min?: string | null max?: string | null - /** Immutable means it can only be configed at the first config then never again - Default is false */ + /** + * @description Once set, the value can never be changed. + * @default false + */ immutable?: boolean }) { return new Value, never>( @@ -432,7 +454,6 @@ export class Value { disabled: false, immutable: a.immutable ?? false, ...a, - ...requiredLikeToAbove(a.required), }), asRequiredParser(string, a), ) @@ -444,8 +465,8 @@ export class Value { name: string description?: string | null warning?: string | null - required: RequiredDefault - /** Default = 'datetime-local' */ + default: string | null + required: boolean inputmode?: ValueSpecDatetime["inputmode"] min?: string | null max?: string | null @@ -453,7 +474,7 @@ export class Value { } >, ) { - return new Value(async (options) => { + return new Value(async (options) => { const a = await getA(options) return { type: "datetime" as const, @@ -465,30 +486,40 @@ export class Value { disabled: false, immutable: false, ...a, - ...requiredLikeToAbove(a.required), } - }, string.optional()) + }, string.nullable()) } - static select< - Required extends RequiredDefault, - B extends Record, - >(a: { + static select>(a: { name: string description?: string | null + /** Presents a warning prompt before permitting the value to change. */ warning?: string | null - required: Required - values: B /** - * Disabled: false means that there is nothing disabled, good to modify - * string means that this is the message displayed and the whole thing is disabled - * string[] means that the options are disabled + * @description Determines if the field is required. If so, optionally provide a default value from the list of values. + * @type { (keyof Values & string) | null } + * @example default: null + * @example default: 'radio1' + */ + default: keyof Values & string + /** + * @description A mapping of unique radio options to their human readable display format. + * @example + * ``` + { + radio1: "Radio 1" + radio2: "Radio 2" + radio3: "Radio 3" + } + * ``` + */ + values: Values + /** + * @description Once set, the value can never be changed. + * @default false */ - disabled?: false | string | (string & keyof B)[] - /** Immutable means it can only be configed at the first config then never again - Default is false */ immutable?: boolean }) { - return new Value, never>( + return new Value( () => ({ description: null, warning: null, @@ -496,14 +527,10 @@ export class Value { disabled: false, immutable: a.immutable ?? false, ...a, - ...requiredLikeToAbove(a.required), }), - asRequiredParser( - anyOf( - ...Object.keys(a.values).map((x: keyof B & string) => literal(x)), - ), - a, - ) as any, + anyOf( + ...Object.keys(a.values).map((x: keyof Values & string) => literal(x)), + ), ) } static dynamicSelect( @@ -513,18 +540,13 @@ export class Value { name: string description?: string | null warning?: string | null - required: RequiredDefault + default: string values: Record - /** - * Disabled: false means that there is nothing disabled, good to modify - * string means that this is the message displayed and the whole thing is disabled - * string[] means that the options are disabled - */ disabled?: false | string | string[] } >, ) { - return new Value(async (options) => { + return new Value(async (options) => { const a = await getA(options) return { description: null, @@ -533,27 +555,37 @@ export class Value { disabled: false, immutable: false, ...a, - ...requiredLikeToAbove(a.required), } - }, string.optional()) + }, string) } static multiselect>(a: { name: string description?: string | null + /** Presents a warning prompt before permitting the value to change. */ warning?: string | null - default: string[] + /** + * @description A simple list of which options should be checked by default. + */ + default: (keyof Values & string)[] + /** + * @description A mapping of checkbox options to their human readable display format. + * @example + * ``` + { + option1: "Option 1" + option2: "Option 2" + option3: "Option 3" + } + * ``` + */ values: Values minLength?: number | null maxLength?: number | null - /** Immutable means it can only be configed at the first config then never again - Default is false */ - immutable?: boolean /** - * Disabled: false means that there is nothing disabled, good to modify - * string means that this is the message displayed and the whole thing is disabled - * string[] means that the options are disabled + * @description Once set, the value can never be changed. + * @default false */ - disabled?: false | string | (string & keyof Values)[] + immutable?: boolean }) { return new Value<(keyof Values)[], never>( () => ({ @@ -582,11 +614,6 @@ export class Value { values: Record minLength?: number | null maxLength?: number | null - /** - * Disabled: false means that there is nothing disabled, good to modify - * string means that this is the message displayed and the whole thing is disabled - * string[] means that the options are disabled - */ disabled?: false | string | string[] } >, @@ -609,9 +636,8 @@ export class Value { a: { name: string description?: string | null - warning?: string | null }, - spec: Config, + spec: InputSpec, ) { return new Value(async (options) => { const built = await spec.build(options as any) @@ -624,69 +650,76 @@ export class Value { } }, spec.validator) } - static file, Store>(a: { - name: string - description?: string | null - warning?: string | null - extensions: string[] - required: Required - }) { - const buildValue = { - type: "file" as const, - description: null, - warning: null, - ...a, - } - return new Value, Store>( - () => ({ - ...buildValue, - - ...requiredLikeToAbove(a.required), - }), - asRequiredParser(object({ filePath: string }), a), - ) - } - static dynamicFile( - a: LazyBuild< - Store, - { + // static file(a: { + // name: string + // description?: string | null + // extensions: string[] + // required: Required + // }) { + // const buildValue = { + // type: "file" as const, + // description: null, + // warning: null, + // ...a, + // } + // return new Value, Store>( + // () => ({ + // ...buildValue, + // }), + // asRequiredParser(object({ filePath: string }), a), + // ) + // } + // static dynamicFile( + // a: LazyBuild< + // Store, + // { + // name: string + // description?: string | null + // warning?: string | null + // extensions: string[] + // required: boolean + // } + // >, + // ) { + // return new Value( + // async (options) => ({ + // type: "file" as const, + // description: null, + // warning: null, + // ...(await a(options)), + // }), + // object({ filePath: string }).nullable(), + // ) + // } + static union< + VariantValues extends { + [K in string]: { name: string - description?: string | null - warning?: string | null - extensions: string[] - required: Required + spec: InputSpec | InputSpec } - >, - ) { - return new Value( - async (options) => ({ - type: "file" as const, - description: null, - warning: null, - ...(await a(options)), - }), - string.optional(), - ) - } - static union, Type, Store>( + }, + Store, + >( a: { name: string description?: string | null + /** Presents a warning prompt before permitting the value to change. */ warning?: string | null - required: Required - /** Immutable means it can only be configed at the first config then never again - Default is false */ - immutable?: boolean /** - * Disabled: false means that there is nothing disabled, good to modify - * string means that this is the message displayed and the whole thing is disabled - * string[] means that the options are disabled + * @description Provide a default value from the list of variants. + * @type { string } + * @example default: 'variant1' */ - disabled?: false | string | string[] + default: keyof VariantValues & string + /** + * @description Once set, the value can never be changed. + * @default false + */ + immutable?: boolean }, - aVariants: Variants, + aVariants: Variants, ) { - return new Value, Store>( + return new Value( async (options) => ({ type: "union" as const, description: null, @@ -694,85 +727,106 @@ export class Value { disabled: false, ...a, variants: await aVariants.build(options as any), - ...requiredLikeToAbove(a.required), immutable: a.immutable ?? false, }), - asRequiredParser(aVariants.validator, a), + aVariants.validator, ) } static filteredUnion< - Required extends RequiredDefault, - Type extends Record, - Store = never, + VariantValues extends { + [K in string]: { + name: string + spec: InputSpec | InputSpec + } + }, + Store, >( getDisabledFn: LazyBuild, a: { name: string description?: string | null warning?: string | null - required: Required + default: keyof VariantValues & string }, - aVariants: Variants | Variants, + aVariants: Variants | Variants, ) { - return new Value, Store>( + return new Value( async (options) => ({ type: "union" as const, description: null, warning: null, ...a, variants: await aVariants.build(options as any), - ...requiredLikeToAbove(a.required), disabled: (await getDisabledFn(options)) || false, immutable: false, }), - asRequiredParser(aVariants.validator, a), + aVariants.validator, ) } static dynamicUnion< - Required extends RequiredDefault, - Type extends Record, - Store = never, + VariantValues extends { + [K in string]: { + name: string + spec: InputSpec | InputSpec + } + }, + Store, >( getA: LazyBuild< Store, { - disabled: string[] | false | string name: string description?: string | null warning?: string | null - required: Required + default: keyof VariantValues & string + disabled: string[] | false | string } >, - aVariants: Variants | Variants, + aVariants: Variants | Variants, ) { - return new Value(async (options) => { - const newValues = await getA(options) - return { - type: "union" as const, - description: null, - warning: null, - ...newValues, - variants: await aVariants.build(options as any), - ...requiredLikeToAbove(newValues.required), - immutable: false, - } - }, aVariants.validator.optional()) + return new Value( + async (options) => { + const newValues = await getA(options) + return { + type: "union" as const, + description: null, + warning: null, + ...newValues, + variants: await aVariants.build(options as any), + immutable: false, + } + }, + aVariants.validator, + ) } static list(a: List) { return new Value((options) => a.build(options), a.validator) } + static hidden(parser: Parser = any) { + return new Value(async () => { + const built: ValueSpecHidden = { + type: "hidden" as const, + } + return built + }, parser) + } + + map(fn: (value: Type) => U): Value { + return new Value(this.build, this.validator.map(fn)) + } + /** * Use this during the times that the input needs a more specific type. - * Used in types that the value/ variant/ list/ config is constructed somewhere else. + * Used in types that the value/ variant/ list/ inputSpec is constructed somewhere else. ```ts - const a = Config.text({ + const a = InputSpec.text({ name: "a", required: false, }) - return Config.of()({ + return InputSpec.of()({ myValue: a.withStore(), }) ``` diff --git a/sdk/lib/config/builder/variants.ts b/sdk/base/lib/actions/input/builder/variants.ts similarity index 57% rename from sdk/lib/config/builder/variants.ts rename to sdk/base/lib/actions/input/builder/variants.ts index 352f16828..93453d73c 100644 --- a/sdk/lib/config/builder/variants.ts +++ b/sdk/base/lib/actions/input/builder/variants.ts @@ -1,6 +1,33 @@ -import { InputSpec, ValueSpecUnion } from "../configTypes" -import { LazyBuild, Config } from "./config" -import { Parser, anyOf, literals, object } from "ts-matches" +import { DeepPartial } from "../../../types" +import { ValueSpec, ValueSpecUnion } from "../inputSpecTypes" +import { + LazyBuild, + InputSpec, + ExtractInputSpecType, + ExtractPartialInputSpecType, +} from "./inputSpec" +import { Parser, anyOf, literal, object } from "ts-matches" + +export type UnionRes< + Store, + VariantValues extends { + [K in string]: { + name: string + spec: InputSpec | InputSpec + } + }, + K extends keyof VariantValues & string = keyof VariantValues & string, +> = { + [key in keyof VariantValues]: { + selection: key + value: ExtractInputSpecType + other?: { + [key2 in Exclude]?: DeepPartial< + ExtractInputSpecType + > + } + } +}[K] /** * Used in the the Value.select { @link './value.ts' } @@ -8,7 +35,7 @@ import { Parser, anyOf, literals, object } from "ts-matches" * key to the tag.id in the Value.select ```ts -export const disabled = Config.of({}); +export const disabled = InputSpec.of({}); export const size = Value.number({ name: "Max Chain Size", default: 550, @@ -20,7 +47,7 @@ export const size = Value.number({ units: "MiB", placeholder: null, }); -export const automatic = Config.of({ size: size }); +export const automatic = InputSpec.of({ size: size }); export const size1 = Value.number({ name: "Failsafe Chain Size", default: 65536, @@ -32,7 +59,7 @@ export const size1 = Value.number({ units: "MiB", placeholder: null, }); -export const manual = Config.of({ size: size1 }); +export const manual = InputSpec.of({ size: size1 }); export const pruningSettingsVariants = Variants.of({ disabled: { name: "Disabled", spec: disabled }, automatic: { name: "Automatic", spec: automatic }, @@ -44,51 +71,49 @@ export const pruning = Value.union( description: '- Disabled: Disable pruning\n- Automatic: Limit blockchain size on disk to a certain number of megabytes\n- Manual: Prune blockchain with the "pruneblockchain" RPC\n', warning: null, - required: true, default: "disabled", }, pruningSettingsVariants ); ``` */ -export class Variants { - static text: any +export class Variants< + VariantValues extends { + [K in string]: { + name: string + spec: InputSpec | InputSpec + } + }, + Store, +> { private constructor( public build: LazyBuild, - public validator: Parser, + public validator: Parser>, ) {} static of< VariantValues extends { [K in string]: { name: string - spec: Config | Config + spec: InputSpec | InputSpec } }, Store = never, >(a: VariantValues) { const validator = anyOf( - ...Object.entries(a).map(([name, { spec }]) => + ...Object.entries(a).map(([id, { spec }]) => object({ - selection: literals(name), + selection: literal(id), value: spec.validator, }), ), ) as Parser - return new Variants< - { - [K in keyof VariantValues]: { - selection: K - // prettier-ignore - value: - VariantValues[K]["spec"] extends (Config | Config) ? B : - never - } - }[keyof VariantValues], - Store - >(async (options) => { + return new Variants(async (options) => { const variants = {} as { - [K in keyof VariantValues]: { name: string; spec: InputSpec } + [K in keyof VariantValues]: { + name: string + spec: Record + } } for (const key in a) { const value = a[key] @@ -102,19 +127,19 @@ export class Variants { } /** * Use this during the times that the input needs a more specific type. - * Used in types that the value/ variant/ list/ config is constructed somewhere else. + * Used in types that the value/ variant/ list/ inputSpec is constructed somewhere else. ```ts - const a = Config.text({ + const a = InputSpec.text({ name: "a", required: false, }) - return Config.of()({ + return InputSpec.of()({ myValue: a.withStore(), }) ``` */ withStore() { - return this as any as Variants + return this as any as Variants } } diff --git a/sdk/base/lib/actions/input/index.ts b/sdk/base/lib/actions/input/index.ts new file mode 100644 index 000000000..3fc16f585 --- /dev/null +++ b/sdk/base/lib/actions/input/index.ts @@ -0,0 +1,3 @@ +export * as constants from "./inputSpecConstants" +export * as types from "./inputSpecTypes" +export * as builder from "./builder" diff --git a/sdk/lib/config/configConstants.ts b/sdk/base/lib/actions/input/inputSpecConstants.ts similarity index 62% rename from sdk/lib/config/configConstants.ts rename to sdk/base/lib/actions/input/inputSpecConstants.ts index aa0e024c9..57bf8a79b 100644 --- a/sdk/lib/config/configConstants.ts +++ b/sdk/base/lib/actions/input/inputSpecConstants.ts @@ -1,53 +1,51 @@ -import { SmtpValue } from "../types" -import { GetSystemSmtp } from "../util/GetSystemSmtp" -import { email } from "../util/patterns" -import { Config, ConfigSpecOf } from "./builder/config" +import { SmtpValue } from "../../types" +import { GetSystemSmtp, Patterns } from "../../util" +import { InputSpec, InputSpecOf } from "./builder/inputSpec" import { Value } from "./builder/value" import { Variants } from "./builder/variants" /** * Base SMTP settings, to be used by StartOS for system wide SMTP */ -export const customSmtp = Config.of, never>({ +export const customSmtp = InputSpec.of, never>({ server: Value.text({ name: "SMTP Server", - required: { - default: null, - }, + required: true, + default: null, }), port: Value.number({ name: "Port", - required: { default: 587 }, + required: true, + default: 587, min: 1, max: 65535, integer: true, }), from: Value.text({ name: "From Address", - required: { - default: null, - }, + required: true, + default: null, placeholder: "test@example.com", inputmode: "email", - patterns: [email], + patterns: [Patterns.email], }), login: Value.text({ name: "Login", - required: { - default: null, - }, + required: true, + default: null, }), password: Value.text({ name: "Password", required: false, + default: null, masked: true, }), }) /** - * For service config. Gives users 3 options for SMTP: (1) disabled, (2) use system SMTP settings, (3) use custom SMTP settings + * For service inputSpec. Gives users 3 options for SMTP: (1) disabled, (2) use system SMTP settings, (3) use custom SMTP settings */ -export const smtpConfig = Value.filteredUnion( +export const smtpInputSpec = Value.filteredUnion( async ({ effects }) => { const smtp = await new GetSystemSmtp(effects).once() return smtp ? [] : ["system"] @@ -55,21 +53,22 @@ export const smtpConfig = Value.filteredUnion( { name: "SMTP", description: "Optionally provide an SMTP server for sending emails", - required: { default: "disabled" }, + default: "disabled", }, Variants.of({ - disabled: { name: "Disabled", spec: Config.of({}) }, + disabled: { name: "Disabled", spec: InputSpec.of({}) }, system: { name: "System Credentials", - spec: Config.of({ + spec: InputSpec.of({ customFrom: Value.text({ name: "Custom From Address", description: "A custom from address for this service. If not provided, the system from address will be used.", required: false, + default: null, placeholder: "test@example.com", inputmode: "email", - patterns: [email], + patterns: [Patterns.email], }), }), }, diff --git a/sdk/lib/config/configTypes.ts b/sdk/base/lib/actions/input/inputSpecTypes.ts similarity index 74% rename from sdk/lib/config/configTypes.ts rename to sdk/base/lib/actions/input/inputSpecTypes.ts index 0179e531e..362a56ea1 100644 --- a/sdk/lib/config/configTypes.ts +++ b/sdk/base/lib/actions/input/inputSpecTypes.ts @@ -12,6 +12,7 @@ export type ValueType = | "object" | "file" | "union" + | "hidden" export type ValueSpec = ValueSpecOf /** core spec types. These types provide the metadata for performing validations */ // prettier-ignore @@ -28,6 +29,7 @@ export type ValueSpecOf = T extends "object" ? ValueSpecObject : T extends "file" ? ValueSpecFile : T extends "union" ? ValueSpecUnion : + T extends "hidden" ? ValueSpecHidden : never export type ValueSpecText = { @@ -48,7 +50,6 @@ export type ValueSpecText = { default: DefaultString | null disabled: false | string generate: null | RandomString - /** Immutable means it can only be configured at the first config then never again */ immutable: boolean } export type ValueSpecTextarea = { @@ -62,7 +63,6 @@ export type ValueSpecTextarea = { maxLength: number | null required: boolean disabled: false | string - /** Immutable means it can only be configured at the first config then never again */ immutable: boolean } @@ -83,7 +83,6 @@ export type ValueSpecNumber = { required: boolean default: number | null disabled: false | string - /** Immutable means it can only be configured at the first config then never again */ immutable: boolean } export type ValueSpecColor = { @@ -95,7 +94,6 @@ export type ValueSpecColor = { required: boolean default: string | null disabled: false | string - /** Immutable means it can only be configured at the first config then never again */ immutable: boolean } export type ValueSpecDatetime = { @@ -109,7 +107,6 @@ export type ValueSpecDatetime = { max: string | null default: string | null disabled: false | string - /** Immutable means it can only be configured at the first config then never again */ immutable: boolean } export type ValueSpecSelect = { @@ -118,15 +115,8 @@ export type ValueSpecSelect = { description: string | null warning: string | null type: "select" - required: boolean default: string | null - /** - * Disabled: false means that there is nothing disabled, good to modify - * string means that this is the message displayed and the whole thing is disabled - * string[] means that the options are disabled - */ disabled: false | string | string[] - /** Immutable means it can only be configured at the first config then never again */ immutable: boolean } export type ValueSpecMultiselect = { @@ -139,14 +129,8 @@ export type ValueSpecMultiselect = { type: "multiselect" minLength: number | null maxLength: number | null - /** - * Disabled: false means that there is nothing disabled, good to modify - * string means that this is the message displayed and the whole thing is disabled - * string[] means that the options are disabled - */ disabled: false | string | string[] default: string[] - /** Immutable means it can only be configured at the first config then never again */ immutable: boolean } export type ValueSpecToggle = { @@ -157,7 +141,6 @@ export type ValueSpecToggle = { type: "toggle" default: boolean | null disabled: false | string - /** Immutable means it can only be configured at the first config then never again */ immutable: boolean } export type ValueSpecUnion = { @@ -173,15 +156,8 @@ export type ValueSpecUnion = { spec: InputSpec } > - /** - * Disabled: false means that there is nothing disabled, good to modify - * string means that this is the message displayed and the whole thing is disabled - * string[] means that the options are disabled - */ disabled: false | string | string[] - required: boolean default: string | null - /** Immutable means it can only be configured at the first config then never again */ immutable: boolean } export type ValueSpecFile = { @@ -199,14 +175,15 @@ export type ValueSpecObject = { type: "object" spec: InputSpec } +export type ValueSpecHidden = { + type: "hidden" +} export type ListValueSpecType = "text" | "object" -/** represents a spec for the values of a list */ // prettier-ignore export type ListValueSpecOf = T extends "text" ? ListValueSpecText : T extends "object" ? ListValueSpecObject : never -/** represents a spec for a list */ export type ValueSpecList = ValueSpecListOf export type ValueSpecListOf = { name: string @@ -242,13 +219,13 @@ export type ListValueSpecText = { } export type ListValueSpecObject = { type: "object" - /** this is a mapped type of the config object at this level, replacing the object's values with specs on those values */ spec: InputSpec - /** indicates whether duplicates can be permitted in the list */ uniqueBy: UniqueBy - /** this should be a handlebars template which can make use of the entire config which corresponds to 'spec' */ displayAs: string | null } +// TODO Aiden do we really want this expressivity? Why not the below. Also what's with the "readonly" portion? +// export type UniqueBy = null | string | { any: string[] } | { all: string[] } + export type UniqueBy = | null | string diff --git a/sdk/base/lib/actions/setupActions.ts b/sdk/base/lib/actions/setupActions.ts new file mode 100644 index 000000000..081225569 --- /dev/null +++ b/sdk/base/lib/actions/setupActions.ts @@ -0,0 +1,155 @@ +import { InputSpec } from "./input/builder" +import { + ExtractInputSpecType, + ExtractPartialInputSpecType, +} from "./input/builder/inputSpec" +import * as T from "../types" +import { once } from "../util" + +export type Run< + A extends + | Record + | InputSpec, any> + | InputSpec, never>, +> = (options: { + effects: T.Effects + input: ExtractInputSpecType & Record +}) => Promise +export type GetInput< + A extends + | Record + | InputSpec, any> + | InputSpec, never>, +> = (options: { + effects: T.Effects +}) => Promise< + | null + | void + | undefined + | (ExtractPartialInputSpecType & Record) +> + +export type MaybeFn = T | ((options: { effects: T.Effects }) => Promise) +function callMaybeFn( + maybeFn: MaybeFn, + options: { effects: T.Effects }, +): Promise { + if (maybeFn instanceof Function) { + return maybeFn(options) + } else { + return Promise.resolve(maybeFn) + } +} +function mapMaybeFn( + maybeFn: MaybeFn, + map: (value: T) => U, +): MaybeFn { + if (maybeFn instanceof Function) { + return async (...args) => map(await maybeFn(...args)) + } else { + return map(maybeFn) + } +} + +export class Action< + Id extends T.ActionId, + Store, + InputSpecType extends + | Record + | InputSpec + | InputSpec, +> { + private constructor( + readonly id: Id, + private readonly metadataFn: MaybeFn, + private readonly inputSpec: InputSpecType, + private readonly getInputFn: GetInput>, + private readonly runFn: Run>, + ) {} + static withInput< + Id extends T.ActionId, + Store, + InputSpecType extends + | Record + | InputSpec + | InputSpec, + >( + id: Id, + metadata: MaybeFn>, + inputSpec: InputSpecType, + getInput: GetInput>, + run: Run>, + ): Action { + return new Action( + id, + mapMaybeFn(metadata, (m) => ({ ...m, hasInput: true })), + inputSpec, + getInput, + run, + ) + } + static withoutInput( + id: Id, + metadata: MaybeFn>, + run: Run<{}>, + ): Action { + return new Action( + id, + mapMaybeFn(metadata, (m) => ({ ...m, hasInput: false })), + {}, + async () => null, + run, + ) + } + async exportMetadata(options: { + effects: T.Effects + }): Promise { + const metadata = await callMaybeFn(this.metadataFn, options) + await options.effects.action.export({ id: this.id, metadata }) + return metadata + } + async getInput(options: { effects: T.Effects }): Promise { + return { + spec: await this.inputSpec.build(options), + value: (await this.getInputFn(options)) || null, + } + } + async run(options: { + effects: T.Effects + input: ExtractInputSpecType + }): Promise { + return (await this.runFn(options)) || null + } +} + +export class Actions< + Store, + AllActions extends Record>, +> { + private constructor(private readonly actions: AllActions) {} + static of(): Actions { + return new Actions({}) + } + addAction>( + action: A, + ): Actions { + return new Actions({ ...this.actions, [action.id]: action }) + } + async update(options: { effects: T.Effects }): Promise { + options.effects = { + ...options.effects, + constRetry: once(() => { + this.update(options) // yes, this reuses the options object, but the const retry function will be overwritten each time, so the once-ness is not a problem + }), + } + for (let action of Object.values(this.actions)) { + await action.exportMetadata(options) + } + await options.effects.action.clear({ except: Object.keys(this.actions) }) + + return null + } + get(actionId: Id): AllActions[Id] { + return this.actions[actionId] + } +} diff --git a/sdk/base/lib/backup/Backups.ts b/sdk/base/lib/backup/Backups.ts new file mode 100644 index 000000000..3e644014a --- /dev/null +++ b/sdk/base/lib/backup/Backups.ts @@ -0,0 +1,208 @@ +import * as T from "../types" +import * as child_process from "child_process" +import { asError } from "../util" + +export const DEFAULT_OPTIONS: T.SyncOptions = { + delete: true, + exclude: [], +} +export type BackupSync = { + dataPath: `/media/startos/volumes/${Volumes}/${string}` + backupPath: `/media/startos/backup/${string}` + options?: Partial + backupOptions?: Partial + restoreOptions?: Partial +} +/** + * This utility simplifies the volume backup process. + * ```ts + * export const { createBackup, restoreBackup } = Backups.volumes("main").build(); + * ``` + * + * Changing the options of the rsync, (ie excludes) use either + * ```ts + * Backups.volumes("main").set_options({exclude: ['bigdata/']}).volumes('excludedVolume').build() + * // or + * Backups.with_options({exclude: ['bigdata/']}).volumes('excludedVolume').build() + * ``` + * + * Using the more fine control, using the addSets for more control + * ```ts + * Backups.addSets({ + * srcVolume: 'main', srcPath:'smallData/', dstPath: 'main/smallData/', dstVolume: : Backups.BACKUP + * }, { + * srcVolume: 'main', srcPath:'bigData/', dstPath: 'main/bigData/', dstVolume: : Backups.BACKUP, options: {exclude:['bigData/excludeThis']}} + * ).build()q + * ``` + */ +export class Backups { + private constructor( + private options = DEFAULT_OPTIONS, + private restoreOptions: Partial = {}, + private backupOptions: Partial = {}, + private backupSet = [] as BackupSync[], + ) {} + + static withVolumes( + ...volumeNames: Array + ): Backups { + return Backups.withSyncs( + ...volumeNames.map((srcVolume) => ({ + dataPath: `/media/startos/volumes/${srcVolume}/` as const, + backupPath: `/media/startos/backup/${srcVolume}/` as const, + })), + ) + } + + static withSyncs( + ...syncs: BackupSync[] + ) { + return syncs.reduce((acc, x) => acc.addSync(x), new Backups()) + } + + static withOptions( + options?: Partial, + ) { + return new Backups({ ...DEFAULT_OPTIONS, ...options }) + } + + setOptions(options?: Partial) { + this.options = { + ...this.options, + ...options, + } + return this + } + + setBackupOptions(options?: Partial) { + this.backupOptions = { + ...this.backupOptions, + ...options, + } + return this + } + + setRestoreOptions(options?: Partial) { + this.restoreOptions = { + ...this.restoreOptions, + ...options, + } + return this + } + + addVolume( + volume: M["volumes"][number], + options?: Partial<{ + options: T.SyncOptions + backupOptions: T.SyncOptions + restoreOptions: T.SyncOptions + }>, + ) { + return this.addSync({ + dataPath: `/media/startos/volumes/${volume}/` as const, + backupPath: `/media/startos/backup/${volume}/` as const, + ...options, + }) + } + addSync(sync: BackupSync) { + this.backupSet.push({ + ...sync, + options: { ...this.options, ...sync.options }, + }) + return this + } + + async createBackup() { + for (const item of this.backupSet) { + const rsyncResults = await runRsync({ + srcPath: item.dataPath, + dstPath: item.backupPath, + options: { + ...this.options, + ...this.backupOptions, + ...item.options, + ...item.backupOptions, + }, + }) + await rsyncResults.wait() + } + return + } + + async restoreBackup() { + for (const item of this.backupSet) { + const rsyncResults = await runRsync({ + srcPath: item.backupPath, + dstPath: item.dataPath, + options: { + ...this.options, + ...this.backupOptions, + ...item.options, + ...item.backupOptions, + }, + }) + await rsyncResults.wait() + } + return + } +} + +async function runRsync(rsyncOptions: { + srcPath: string + dstPath: string + options: T.SyncOptions +}): Promise<{ + id: () => Promise + wait: () => Promise + progress: () => Promise +}> { + const { srcPath, dstPath, options } = rsyncOptions + + const command = "rsync" + const args: string[] = [] + if (options.delete) { + args.push("--delete") + } + for (const exclude of options.exclude) { + args.push(`--exclude=${exclude}`) + } + args.push("-actAXH") + args.push("--info=progress2") + args.push("--no-inc-recursive") + args.push(srcPath) + args.push(dstPath) + const spawned = child_process.spawn(command, args, { detached: true }) + let percentage = 0.0 + spawned.stdout.on("data", (data: unknown) => { + const lines = String(data).replace("\r", "\n").split("\n") + for (const line of lines) { + const parsed = /$([0-9.]+)%/.exec(line)?.[1] + if (!parsed) continue + percentage = Number.parseFloat(parsed) + } + }) + + spawned.stderr.on("data", (data: unknown) => { + console.error(`Backups.runAsync`, asError(data)) + }) + + const id = async () => { + const pid = spawned.pid + if (pid === undefined) { + throw new Error("rsync process has no pid") + } + return String(pid) + } + const waitPromise = new Promise((resolve, reject) => { + spawned.on("exit", (code: any) => { + if (code === 0) { + resolve(null) + } else { + reject(new Error(`rsync exited with code ${code}`)) + } + }) + }) + const wait = () => waitPromise + const progress = () => Promise.resolve(percentage) + return { id, wait, progress } +} diff --git a/sdk/base/lib/backup/setupBackups.ts b/sdk/base/lib/backup/setupBackups.ts new file mode 100644 index 000000000..b41a61f42 --- /dev/null +++ b/sdk/base/lib/backup/setupBackups.ts @@ -0,0 +1,39 @@ +import { Backups } from "./Backups" +import * as T from "../types" +import { _ } from "../util" + +export type SetupBackupsParams = + | M["volumes"][number][] + | ((_: { effects: T.Effects }) => Promise>) + +type SetupBackupsRes = { + createBackup: T.ExpectedExports.createBackup + restoreBackup: T.ExpectedExports.restoreBackup +} + +export function setupBackups( + options: SetupBackupsParams, +) { + let backupsFactory: (_: { effects: T.Effects }) => Promise> + if (options instanceof Function) { + backupsFactory = options + } else { + backupsFactory = async () => Backups.withVolumes(...options) + } + const answer: { + createBackup: T.ExpectedExports.createBackup + restoreBackup: T.ExpectedExports.restoreBackup + } = { + get createBackup() { + return (async (options) => { + return (await backupsFactory(options)).createBackup() + }) as T.ExpectedExports.createBackup + }, + get restoreBackup() { + return (async (options) => { + return (await backupsFactory(options)).restoreBackup() + }) as T.ExpectedExports.restoreBackup + }, + } + return answer +} diff --git a/sdk/lib/dependencies/dependencies.ts b/sdk/base/lib/dependencies/dependencies.ts similarity index 85% rename from sdk/lib/dependencies/dependencies.ts rename to sdk/base/lib/dependencies/dependencies.ts index 287f63b06..20049b5e8 100644 --- a/sdk/lib/dependencies/dependencies.ts +++ b/sdk/base/lib/dependencies/dependencies.ts @@ -1,33 +1,27 @@ import { ExtendedVersion, VersionRange } from "../exver" -import { - Effects, - PackageId, - DependencyRequirement, - SetHealth, - CheckDependenciesResult, - HealthCheckId, -} from "../types" +import { PackageId, HealthCheckId } from "../types" +import { Effects } from "../Effects" export type CheckDependencies = { installedSatisfied: (packageId: DependencyId) => boolean installedVersionSatisfied: (packageId: DependencyId) => boolean runningSatisfied: (packageId: DependencyId) => boolean - configSatisfied: (packageId: DependencyId) => boolean + actionsSatisfied: (packageId: DependencyId) => boolean healthCheckSatisfied: ( packageId: DependencyId, healthCheckId: HealthCheckId, ) => boolean satisfied: () => boolean - throwIfInstalledNotSatisfied: (packageId: DependencyId) => void - throwIfInstalledVersionNotSatisfied: (packageId: DependencyId) => void - throwIfRunningNotSatisfied: (packageId: DependencyId) => void - throwIfConfigNotSatisfied: (packageId: DependencyId) => void + throwIfInstalledNotSatisfied: (packageId: DependencyId) => null + throwIfInstalledVersionNotSatisfied: (packageId: DependencyId) => null + throwIfRunningNotSatisfied: (packageId: DependencyId) => null + throwIfActionsNotSatisfied: (packageId: DependencyId) => null throwIfHealthNotSatisfied: ( packageId: DependencyId, healthCheckId?: HealthCheckId, - ) => void - throwIfNotSatisfied: (packageId?: DependencyId) => void + ) => null + throwIfNotSatisfied: (packageId?: DependencyId) => null } export async function checkDependencies< DependencyId extends PackageId = PackageId, @@ -71,8 +65,8 @@ export async function checkDependencies< const dep = find(packageId) return dep.requirement.kind !== "running" || dep.result.isRunning } - const configSatisfied = (packageId: DependencyId) => - find(packageId).result.configSatisfied + const actionsSatisfied = (packageId: DependencyId) => + Object.keys(find(packageId).result.requestedActions).length === 0 const healthCheckSatisfied = ( packageId: DependencyId, healthCheckId?: HealthCheckId, @@ -94,7 +88,7 @@ export async function checkDependencies< installedSatisfied(packageId) && installedVersionSatisfied(packageId) && runningSatisfied(packageId) && - configSatisfied(packageId) && + actionsSatisfied(packageId) && healthCheckSatisfied(packageId) const satisfied = (packageId?: DependencyId) => packageId @@ -106,6 +100,7 @@ export async function checkDependencies< if (!dep.result.installedVersion) { throw new Error(`${dep.result.title || packageId} is not installed`) } + return null } const throwIfInstalledVersionNotSatisfied = (packageId: DependencyId) => { const dep = find(packageId) @@ -123,20 +118,24 @@ export async function checkDependencies< `Installed version ${dep.result.installedVersion} of ${dep.result.title || packageId} does not match expected version range ${dep.requirement.versionRange}`, ) } + return null } const throwIfRunningNotSatisfied = (packageId: DependencyId) => { const dep = find(packageId) if (dep.requirement.kind === "running" && !dep.result.isRunning) { throw new Error(`${dep.result.title || packageId} is not running`) } + return null } - const throwIfConfigNotSatisfied = (packageId: DependencyId) => { + const throwIfActionsNotSatisfied = (packageId: DependencyId) => { const dep = find(packageId) - if (!dep.result.configSatisfied) { + const reqs = Object.keys(dep.result.requestedActions) + if (reqs.length) { throw new Error( - `${dep.result.title || packageId}'s configuration does not satisfy requirements`, + `The following action requests have not been fulfilled: ${reqs.join(", ")}`, ) } + return null } const throwIfHealthNotSatisfied = ( packageId: DependencyId, @@ -163,13 +162,15 @@ export async function checkDependencies< .join("; "), ) } + return null } const throwIfPkgNotSatisfied = (packageId: DependencyId) => { throwIfInstalledNotSatisfied(packageId) throwIfInstalledVersionNotSatisfied(packageId) throwIfRunningNotSatisfied(packageId) - throwIfConfigNotSatisfied(packageId) + throwIfActionsNotSatisfied(packageId) throwIfHealthNotSatisfied(packageId) + return null } const throwIfNotSatisfied = (packageId?: DependencyId) => packageId @@ -187,19 +188,20 @@ export async function checkDependencies< if (err.length) { throw new Error(err.join("; ")) } + return null })() return { installedSatisfied, installedVersionSatisfied, runningSatisfied, - configSatisfied, + actionsSatisfied, healthCheckSatisfied, satisfied, throwIfInstalledNotSatisfied, throwIfInstalledVersionNotSatisfied, throwIfRunningNotSatisfied, - throwIfConfigNotSatisfied, + throwIfActionsNotSatisfied, throwIfHealthNotSatisfied, throwIfNotSatisfied, } diff --git a/sdk/lib/dependencies/index.ts b/sdk/base/lib/dependencies/index.ts similarity index 78% rename from sdk/lib/dependencies/index.ts rename to sdk/base/lib/dependencies/index.ts index 3fe78b4f3..09e2b33ad 100644 --- a/sdk/lib/dependencies/index.ts +++ b/sdk/base/lib/dependencies/index.ts @@ -4,6 +4,3 @@ export type ReadonlyDeep = A extends {} ? { readonly [K in keyof A]: ReadonlyDeep } : A; export type MaybePromise = Promise | A export type Message = string - -import "./DependencyConfig" -import "./setupDependencyConfig" diff --git a/sdk/base/lib/dependencies/setupDependencies.ts b/sdk/base/lib/dependencies/setupDependencies.ts new file mode 100644 index 000000000..6b15ef0d1 --- /dev/null +++ b/sdk/base/lib/dependencies/setupDependencies.ts @@ -0,0 +1,62 @@ +import * as T from "../types" +import { once } from "../util" + +export type RequiredDependenciesOf = { + [K in keyof Manifest["dependencies"]]: Manifest["dependencies"][K]["optional"] extends false + ? K + : never +}[keyof Manifest["dependencies"]] +export type OptionalDependenciesOf = Exclude< + keyof Manifest["dependencies"], + RequiredDependenciesOf +> + +type DependencyRequirement = + | { + kind: "running" + healthChecks: Array + versionRange: string + } + | { + kind: "exists" + versionRange: string + } +type Matches = T extends U ? (U extends T ? null : never) : never +const _checkType: Matches< + DependencyRequirement & { id: T.PackageId }, + T.DependencyRequirement +> = null + +export type CurrentDependenciesResult = { + [K in RequiredDependenciesOf]: DependencyRequirement +} & { + [K in OptionalDependenciesOf]?: DependencyRequirement +} & Record + +export function setupDependencies( + fn: (options: { + effects: T.Effects + }) => Promise>, +): (options: { effects: T.Effects }) => Promise { + const cell = { updater: async (_: { effects: T.Effects }) => null } + cell.updater = async (options: { effects: T.Effects }) => { + options.effects = { + ...options.effects, + constRetry: once(() => { + cell.updater(options) + }), + } + const dependencyType = await fn(options) + return await options.effects.setDependencies({ + dependencies: Object.entries(dependencyType).map( + ([id, { versionRange, ...x }, ,]) => + ({ + // id, + ...x, + versionRange: versionRange.toString(), + }) as T.DependencyRequirement, + ), + }) + } + return cell.updater +} diff --git a/sdk/lib/exver/exver.pegjs b/sdk/base/lib/exver/exver.pegjs similarity index 100% rename from sdk/lib/exver/exver.pegjs rename to sdk/base/lib/exver/exver.pegjs diff --git a/sdk/lib/exver/exver.ts b/sdk/base/lib/exver/exver.ts similarity index 100% rename from sdk/lib/exver/exver.ts rename to sdk/base/lib/exver/exver.ts diff --git a/sdk/lib/exver/index.ts b/sdk/base/lib/exver/index.ts similarity index 100% rename from sdk/lib/exver/index.ts rename to sdk/base/lib/exver/index.ts diff --git a/sdk/lib/index.browser.ts b/sdk/base/lib/index.ts similarity index 51% rename from sdk/lib/index.browser.ts rename to sdk/base/lib/index.ts index f7d645133..0aa8e4758 100644 --- a/sdk/lib/index.browser.ts +++ b/sdk/base/lib/index.ts @@ -1,13 +1,12 @@ export { S9pk } from "./s9pk" export { VersionRange, ExtendedVersion, Version } from "./exver" -export * as config from "./config" -export * as CB from "./config/builder" -export * as CT from "./config/configTypes" -export * as dependencyConfig from "./dependencies" +export * as inputSpec from "./actions/input" +export * as ISB from "./actions/input/builder" +export * as IST from "./actions/input/inputSpecTypes" export * as types from "./types" export * as T from "./types" export * as yaml from "yaml" export * as matches from "ts-matches" -export * as utils from "./util/index.browser" +export * as utils from "./util" diff --git a/sdk/lib/interfaces/AddressReceipt.ts b/sdk/base/lib/interfaces/AddressReceipt.ts similarity index 100% rename from sdk/lib/interfaces/AddressReceipt.ts rename to sdk/base/lib/interfaces/AddressReceipt.ts diff --git a/sdk/lib/interfaces/Host.ts b/sdk/base/lib/interfaces/Host.ts similarity index 82% rename from sdk/lib/interfaces/Host.ts rename to sdk/base/lib/interfaces/Host.ts index aa27a289c..b90dc1c60 100644 --- a/sdk/lib/interfaces/Host.ts +++ b/sdk/base/lib/interfaces/Host.ts @@ -1,10 +1,10 @@ -import { number, object, string } from "ts-matches" -import { Effects } from "../types" +import { object, string } from "ts-matches" +import { Effects } from "../Effects" import { Origin } from "./Origin" -import { AddSslOptions, BindParams } from ".././osBindings" -import { Security } from ".././osBindings" -import { BindOptions } from ".././osBindings" -import { AlpnInfo } from ".././osBindings" +import { AddSslOptions, BindParams } from "../osBindings" +import { Security } from "../osBindings" +import { BindOptions } from "../osBindings" +import { AlpnInfo } from "../osBindings" export { AddSslOptions, Security, BindOptions } @@ -94,6 +94,22 @@ export class Host { }, ) {} + /** + * @description Use this function to bind the host to an internal port and configured options for protocol, security, and external port. + * + * @param internalPort - The internal port to be bound. + * @param options - The protocol options for this binding. + * @returns A multi-origin that is capable of exporting one or more service interfaces. + * @example + * In this example, we bind a previously created multi-host to port 80, then select the http protocol and request an external port of 8332. + * + * ``` + const uiMultiOrigin = await uiMulti.bindPort(80, { + protocol: 'http', + preferredExternalPort: 8332, + }) + * ``` + */ async bindPort( internalPort: number, options: BindOptionsByProtocol, diff --git a/sdk/lib/interfaces/Origin.ts b/sdk/base/lib/interfaces/Origin.ts similarity index 89% rename from sdk/lib/interfaces/Origin.ts rename to sdk/base/lib/interfaces/Origin.ts index cc84728ec..5e12713e6 100644 --- a/sdk/lib/interfaces/Origin.ts +++ b/sdk/base/lib/interfaces/Origin.ts @@ -1,6 +1,6 @@ import { AddressInfo } from "../types" import { AddressReceipt } from "./AddressReceipt" -import { Host, BindOptions, Scheme } from "./Host" +import { Host, Scheme } from "./Host" import { ServiceInterfaceBuilder } from "./ServiceInterfaceBuilder" export class Origin { @@ -31,9 +31,9 @@ export class Origin { } /** - * A function to register a group of origins ( :// : ) with StartOS + * @description A function to register a group of origins ( :// : ) with StartOS * - * The returned addressReceipt serves as proof that the addresses were registered + * The returned addressReceipt serves as proof that the addresses were registered * * @param addressInfo * @returns diff --git a/sdk/lib/interfaces/ServiceInterfaceBuilder.ts b/sdk/base/lib/interfaces/ServiceInterfaceBuilder.ts similarity index 90% rename from sdk/lib/interfaces/ServiceInterfaceBuilder.ts rename to sdk/base/lib/interfaces/ServiceInterfaceBuilder.ts index 49d8020d6..4ef294b4f 100644 --- a/sdk/lib/interfaces/ServiceInterfaceBuilder.ts +++ b/sdk/base/lib/interfaces/ServiceInterfaceBuilder.ts @@ -1,5 +1,5 @@ -import { ServiceInterfaceType } from "../StartSdk" -import { Effects } from "../types" +import { ServiceInterfaceType } from "../types" +import { Effects } from "../Effects" import { Scheme } from "./Host" /** diff --git a/sdk/lib/interfaces/interfaceReceipt.ts b/sdk/base/lib/interfaces/interfaceReceipt.ts similarity index 100% rename from sdk/lib/interfaces/interfaceReceipt.ts rename to sdk/base/lib/interfaces/interfaceReceipt.ts diff --git a/sdk/base/lib/interfaces/setupInterfaces.ts b/sdk/base/lib/interfaces/setupInterfaces.ts new file mode 100644 index 000000000..ba284bcb3 --- /dev/null +++ b/sdk/base/lib/interfaces/setupInterfaces.ts @@ -0,0 +1,57 @@ +import * as T from "../types" +import { once } from "../util" +import { AddressReceipt } from "./AddressReceipt" + +declare const UpdateServiceInterfacesProof: unique symbol +export type UpdateServiceInterfacesReceipt = { + [UpdateServiceInterfacesProof]: never +} + +export type ServiceInterfacesReceipt = Array +export type SetServiceInterfaces = + (opts: { effects: T.Effects }) => Promise +export type UpdateServiceInterfaces = + (opts: { + effects: T.Effects + }) => Promise +export type SetupServiceInterfaces = ( + fn: SetServiceInterfaces, +) => UpdateServiceInterfaces +export const NO_INTERFACE_CHANGES = {} as UpdateServiceInterfacesReceipt +export const setupServiceInterfaces: SetupServiceInterfaces = < + Output extends ServiceInterfacesReceipt, +>( + fn: SetServiceInterfaces, +) => { + const cell = { + updater: (async (options: { effects: T.Effects }) => + [] as any as Output) as UpdateServiceInterfaces, + } + cell.updater = (async (options: { effects: T.Effects }) => { + options.effects = { + ...options.effects, + constRetry: once(() => { + cell.updater(options) + }), + } + const bindings: T.BindId[] = [] + const interfaces: T.ServiceInterfaceId[] = [] + const res = await fn({ + effects: { + ...options.effects, + bind: (params: T.BindParams) => { + bindings.push({ id: params.id, internalPort: params.internalPort }) + return options.effects.bind(params) + }, + exportServiceInterface: (params: T.ExportServiceInterfaceParams) => { + interfaces.push(params.id) + return options.effects.exportServiceInterface(params) + }, + }, + }) + await options.effects.clearBindings({ except: bindings }) + await options.effects.clearServiceInterfaces({ except: interfaces }) + return res + }) as UpdateServiceInterfaces + return cell.updater +} diff --git a/sdk/lib/osBindings/AcceptSigners.ts b/sdk/base/lib/osBindings/AcceptSigners.ts similarity index 100% rename from sdk/lib/osBindings/AcceptSigners.ts rename to sdk/base/lib/osBindings/AcceptSigners.ts diff --git a/sdk/base/lib/osBindings/AcmeSettings.ts b/sdk/base/lib/osBindings/AcmeSettings.ts new file mode 100644 index 000000000..bdf151ec7 --- /dev/null +++ b/sdk/base/lib/osBindings/AcmeSettings.ts @@ -0,0 +1,13 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type AcmeSettings = { + provider: string + /** + * email addresses for letsencrypt + */ + contact: Array + /** + * domains to get letsencrypt certs for + */ + domains: string[] +} diff --git a/sdk/lib/osBindings/ActionId.ts b/sdk/base/lib/osBindings/ActionId.ts similarity index 100% rename from sdk/lib/osBindings/ActionId.ts rename to sdk/base/lib/osBindings/ActionId.ts diff --git a/sdk/base/lib/osBindings/ActionInput.ts b/sdk/base/lib/osBindings/ActionInput.ts new file mode 100644 index 000000000..a19a5f1a4 --- /dev/null +++ b/sdk/base/lib/osBindings/ActionInput.ts @@ -0,0 +1,6 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type ActionInput = { + spec: Record + value: Record | null +} diff --git a/sdk/lib/osBindings/ActionMetadata.ts b/sdk/base/lib/osBindings/ActionMetadata.ts similarity index 74% rename from sdk/lib/osBindings/ActionMetadata.ts rename to sdk/base/lib/osBindings/ActionMetadata.ts index b103b82b0..ade129fd4 100644 --- a/sdk/lib/osBindings/ActionMetadata.ts +++ b/sdk/base/lib/osBindings/ActionMetadata.ts @@ -1,12 +1,13 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { ActionVisibility } from "./ActionVisibility" import type { AllowedStatuses } from "./AllowedStatuses" export type ActionMetadata = { name: string description: string warning: string | null - input: any - disabled: boolean + visibility: ActionVisibility allowedStatuses: AllowedStatuses + hasInput: boolean group: string | null } diff --git a/sdk/base/lib/osBindings/ActionRequest.ts b/sdk/base/lib/osBindings/ActionRequest.ts new file mode 100644 index 000000000..552f37bc6 --- /dev/null +++ b/sdk/base/lib/osBindings/ActionRequest.ts @@ -0,0 +1,15 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { ActionId } from "./ActionId" +import type { ActionRequestInput } from "./ActionRequestInput" +import type { ActionRequestTrigger } from "./ActionRequestTrigger" +import type { ActionSeverity } from "./ActionSeverity" +import type { PackageId } from "./PackageId" + +export type ActionRequest = { + packageId: PackageId + actionId: ActionId + severity: ActionSeverity + reason?: string + when?: ActionRequestTrigger + input?: ActionRequestInput +} diff --git a/sdk/lib/osBindings/AllowedStatuses.ts b/sdk/base/lib/osBindings/ActionRequestCondition.ts similarity index 61% rename from sdk/lib/osBindings/AllowedStatuses.ts rename to sdk/base/lib/osBindings/ActionRequestCondition.ts index 960187fd9..0f06caf3c 100644 --- a/sdk/lib/osBindings/AllowedStatuses.ts +++ b/sdk/base/lib/osBindings/ActionRequestCondition.ts @@ -1,3 +1,3 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -export type AllowedStatuses = "onlyRunning" | "onlyStopped" | "any" +export type ActionRequestCondition = "input-not-matches" diff --git a/sdk/base/lib/osBindings/ActionRequestEntry.ts b/sdk/base/lib/osBindings/ActionRequestEntry.ts new file mode 100644 index 000000000..0e716abe4 --- /dev/null +++ b/sdk/base/lib/osBindings/ActionRequestEntry.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 { ActionRequest } from "./ActionRequest" + +export type ActionRequestEntry = { request: ActionRequest; active: boolean } diff --git a/sdk/base/lib/osBindings/ActionRequestInput.ts b/sdk/base/lib/osBindings/ActionRequestInput.ts new file mode 100644 index 000000000..a1cde7789 --- /dev/null +++ b/sdk/base/lib/osBindings/ActionRequestInput.ts @@ -0,0 +1,6 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type ActionRequestInput = { + kind: "partial" + value: Record +} diff --git a/sdk/base/lib/osBindings/ActionRequestTrigger.ts b/sdk/base/lib/osBindings/ActionRequestTrigger.ts new file mode 100644 index 000000000..ebd0963e5 --- /dev/null +++ b/sdk/base/lib/osBindings/ActionRequestTrigger.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. +import type { ActionRequestCondition } from "./ActionRequestCondition" + +export type ActionRequestTrigger = { + once: boolean + condition: ActionRequestCondition +} diff --git a/sdk/base/lib/osBindings/ActionResult.ts b/sdk/base/lib/osBindings/ActionResult.ts new file mode 100644 index 000000000..7422dcde3 --- /dev/null +++ b/sdk/base/lib/osBindings/ActionResult.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. +import type { ActionResultV0 } from "./ActionResultV0" +import type { ActionResultV1 } from "./ActionResultV1" + +export type ActionResult = + | ({ version: "0" } & ActionResultV0) + | ({ version: "1" } & ActionResultV1) diff --git a/sdk/base/lib/osBindings/ActionResultMember.ts b/sdk/base/lib/osBindings/ActionResultMember.ts new file mode 100644 index 000000000..cdc23ecaa --- /dev/null +++ b/sdk/base/lib/osBindings/ActionResultMember.ts @@ -0,0 +1,15 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type ActionResultMember = { + name: string + description: string | null +} & ( + | { + type: "single" + value: string + copyable: boolean + qr: boolean + masked: boolean + } + | { type: "group"; value: Array } +) diff --git a/sdk/base/lib/osBindings/ActionResultV0.ts b/sdk/base/lib/osBindings/ActionResultV0.ts new file mode 100644 index 000000000..7c6b43d45 --- /dev/null +++ b/sdk/base/lib/osBindings/ActionResultV0.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. + +export type ActionResultV0 = { + message: string + value: string | null + copyable: boolean + qr: boolean +} diff --git a/sdk/base/lib/osBindings/ActionResultV1.ts b/sdk/base/lib/osBindings/ActionResultV1.ts new file mode 100644 index 000000000..eece18477 --- /dev/null +++ b/sdk/base/lib/osBindings/ActionResultV1.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 { ActionResultValue } from "./ActionResultValue" + +export type ActionResultV1 = { + title: string + message: string | null + result: ActionResultValue | null +} diff --git a/sdk/base/lib/osBindings/ActionResultValue.ts b/sdk/base/lib/osBindings/ActionResultValue.ts new file mode 100644 index 000000000..d1cb6c8c3 --- /dev/null +++ b/sdk/base/lib/osBindings/ActionResultValue.ts @@ -0,0 +1,12 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { ActionResultMember } from "./ActionResultMember" + +export type ActionResultValue = + | { + type: "single" + value: string + copyable: boolean + qr: boolean + masked: boolean + } + | { type: "group"; value: Array } diff --git a/sdk/base/lib/osBindings/ActionSeverity.ts b/sdk/base/lib/osBindings/ActionSeverity.ts new file mode 100644 index 000000000..ad339f951 --- /dev/null +++ b/sdk/base/lib/osBindings/ActionSeverity.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 ActionSeverity = "critical" | "important" diff --git a/sdk/base/lib/osBindings/ActionVisibility.ts b/sdk/base/lib/osBindings/ActionVisibility.ts new file mode 100644 index 000000000..ab1e6e1b9 --- /dev/null +++ b/sdk/base/lib/osBindings/ActionVisibility.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 ActionVisibility = "hidden" | { disabled: string } | "enabled" diff --git a/sdk/lib/osBindings/AddAdminParams.ts b/sdk/base/lib/osBindings/AddAdminParams.ts similarity index 100% rename from sdk/lib/osBindings/AddAdminParams.ts rename to sdk/base/lib/osBindings/AddAdminParams.ts diff --git a/sdk/lib/osBindings/AddAssetParams.ts b/sdk/base/lib/osBindings/AddAssetParams.ts similarity index 100% rename from sdk/lib/osBindings/AddAssetParams.ts rename to sdk/base/lib/osBindings/AddAssetParams.ts diff --git a/sdk/base/lib/osBindings/AddCategoryParams.ts b/sdk/base/lib/osBindings/AddCategoryParams.ts new file mode 100644 index 000000000..799f2d4d2 --- /dev/null +++ b/sdk/base/lib/osBindings/AddCategoryParams.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. + +export type AddCategoryParams = { + id: string + name: string + short: string + long: string +} diff --git a/sdk/lib/osBindings/AddPackageParams.ts b/sdk/base/lib/osBindings/AddPackageParams.ts similarity index 100% rename from sdk/lib/osBindings/AddPackageParams.ts rename to sdk/base/lib/osBindings/AddPackageParams.ts diff --git a/sdk/lib/osBindings/AddSslOptions.ts b/sdk/base/lib/osBindings/AddSslOptions.ts similarity index 100% rename from sdk/lib/osBindings/AddSslOptions.ts rename to sdk/base/lib/osBindings/AddSslOptions.ts diff --git a/sdk/lib/osBindings/AddVersionParams.ts b/sdk/base/lib/osBindings/AddVersionParams.ts similarity index 100% rename from sdk/lib/osBindings/AddVersionParams.ts rename to sdk/base/lib/osBindings/AddVersionParams.ts diff --git a/sdk/lib/osBindings/AddressInfo.ts b/sdk/base/lib/osBindings/AddressInfo.ts similarity index 100% rename from sdk/lib/osBindings/AddressInfo.ts rename to sdk/base/lib/osBindings/AddressInfo.ts diff --git a/sdk/lib/osBindings/Alerts.ts b/sdk/base/lib/osBindings/Alerts.ts similarity index 100% rename from sdk/lib/osBindings/Alerts.ts rename to sdk/base/lib/osBindings/Alerts.ts diff --git a/sdk/lib/osBindings/Algorithm.ts b/sdk/base/lib/osBindings/Algorithm.ts similarity index 100% rename from sdk/lib/osBindings/Algorithm.ts rename to sdk/base/lib/osBindings/Algorithm.ts diff --git a/sdk/lib/osBindings/AllPackageData.ts b/sdk/base/lib/osBindings/AllPackageData.ts similarity index 100% rename from sdk/lib/osBindings/AllPackageData.ts rename to sdk/base/lib/osBindings/AllPackageData.ts diff --git a/sdk/base/lib/osBindings/AllowedStatuses.ts b/sdk/base/lib/osBindings/AllowedStatuses.ts new file mode 100644 index 000000000..ed5851495 --- /dev/null +++ b/sdk/base/lib/osBindings/AllowedStatuses.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 AllowedStatuses = "only-running" | "only-stopped" | "any" diff --git a/sdk/lib/osBindings/AlpnInfo.ts b/sdk/base/lib/osBindings/AlpnInfo.ts similarity index 100% rename from sdk/lib/osBindings/AlpnInfo.ts rename to sdk/base/lib/osBindings/AlpnInfo.ts diff --git a/sdk/lib/osBindings/AnySignature.ts b/sdk/base/lib/osBindings/AnySignature.ts similarity index 100% rename from sdk/lib/osBindings/AnySignature.ts rename to sdk/base/lib/osBindings/AnySignature.ts diff --git a/sdk/lib/osBindings/AnySigningKey.ts b/sdk/base/lib/osBindings/AnySigningKey.ts similarity index 100% rename from sdk/lib/osBindings/AnySigningKey.ts rename to sdk/base/lib/osBindings/AnySigningKey.ts diff --git a/sdk/lib/osBindings/AnyVerifyingKey.ts b/sdk/base/lib/osBindings/AnyVerifyingKey.ts similarity index 100% rename from sdk/lib/osBindings/AnyVerifyingKey.ts rename to sdk/base/lib/osBindings/AnyVerifyingKey.ts diff --git a/sdk/lib/osBindings/ApiState.ts b/sdk/base/lib/osBindings/ApiState.ts similarity index 100% rename from sdk/lib/osBindings/ApiState.ts rename to sdk/base/lib/osBindings/ApiState.ts diff --git a/sdk/lib/osBindings/AttachParams.ts b/sdk/base/lib/osBindings/AttachParams.ts similarity index 100% rename from sdk/lib/osBindings/AttachParams.ts rename to sdk/base/lib/osBindings/AttachParams.ts diff --git a/sdk/lib/osBindings/BackupProgress.ts b/sdk/base/lib/osBindings/BackupProgress.ts similarity index 100% rename from sdk/lib/osBindings/BackupProgress.ts rename to sdk/base/lib/osBindings/BackupProgress.ts diff --git a/sdk/lib/osBindings/BackupTargetFS.ts b/sdk/base/lib/osBindings/BackupTargetFS.ts similarity index 100% rename from sdk/lib/osBindings/BackupTargetFS.ts rename to sdk/base/lib/osBindings/BackupTargetFS.ts diff --git a/sdk/lib/osBindings/Base64.ts b/sdk/base/lib/osBindings/Base64.ts similarity index 100% rename from sdk/lib/osBindings/Base64.ts rename to sdk/base/lib/osBindings/Base64.ts diff --git a/sdk/base/lib/osBindings/BindId.ts b/sdk/base/lib/osBindings/BindId.ts new file mode 100644 index 000000000..778d95346 --- /dev/null +++ b/sdk/base/lib/osBindings/BindId.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 { HostId } from "./HostId" + +export type BindId = { id: HostId; internalPort: number } diff --git a/sdk/lib/osBindings/BindInfo.ts b/sdk/base/lib/osBindings/BindInfo.ts similarity index 71% rename from sdk/lib/osBindings/BindInfo.ts rename to sdk/base/lib/osBindings/BindInfo.ts index 221b1c37c..85fc38e94 100644 --- a/sdk/lib/osBindings/BindInfo.ts +++ b/sdk/base/lib/osBindings/BindInfo.ts @@ -2,4 +2,4 @@ import type { BindOptions } from "./BindOptions" import type { LanInfo } from "./LanInfo" -export type BindInfo = { options: BindOptions; lan: LanInfo } +export type BindInfo = { enabled: boolean; options: BindOptions; lan: LanInfo } diff --git a/sdk/lib/osBindings/BindOptions.ts b/sdk/base/lib/osBindings/BindOptions.ts similarity index 100% rename from sdk/lib/osBindings/BindOptions.ts rename to sdk/base/lib/osBindings/BindOptions.ts diff --git a/sdk/lib/osBindings/BindParams.ts b/sdk/base/lib/osBindings/BindParams.ts similarity index 100% rename from sdk/lib/osBindings/BindParams.ts rename to sdk/base/lib/osBindings/BindParams.ts diff --git a/sdk/lib/osBindings/Blake3Commitment.ts b/sdk/base/lib/osBindings/Blake3Commitment.ts similarity index 100% rename from sdk/lib/osBindings/Blake3Commitment.ts rename to sdk/base/lib/osBindings/Blake3Commitment.ts diff --git a/sdk/lib/osBindings/BlockDev.ts b/sdk/base/lib/osBindings/BlockDev.ts similarity index 100% rename from sdk/lib/osBindings/BlockDev.ts rename to sdk/base/lib/osBindings/BlockDev.ts diff --git a/sdk/lib/osBindings/SetConfigured.ts b/sdk/base/lib/osBindings/BuildArg.ts similarity index 67% rename from sdk/lib/osBindings/SetConfigured.ts rename to sdk/base/lib/osBindings/BuildArg.ts index e1478422a..1157828f5 100644 --- a/sdk/lib/osBindings/SetConfigured.ts +++ b/sdk/base/lib/osBindings/BuildArg.ts @@ -1,3 +1,3 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -export type SetConfigured = { configured: boolean } +export type BuildArg = string | { env: string } diff --git a/sdk/lib/osBindings/CallbackId.ts b/sdk/base/lib/osBindings/CallbackId.ts similarity index 100% rename from sdk/lib/osBindings/CallbackId.ts rename to sdk/base/lib/osBindings/CallbackId.ts diff --git a/sdk/lib/osBindings/Category.ts b/sdk/base/lib/osBindings/Category.ts similarity index 100% rename from sdk/lib/osBindings/Category.ts rename to sdk/base/lib/osBindings/Category.ts diff --git a/sdk/lib/osBindings/CheckDependenciesParam.ts b/sdk/base/lib/osBindings/CheckDependenciesParam.ts similarity index 100% rename from sdk/lib/osBindings/CheckDependenciesParam.ts rename to sdk/base/lib/osBindings/CheckDependenciesParam.ts diff --git a/sdk/lib/osBindings/CheckDependenciesResult.ts b/sdk/base/lib/osBindings/CheckDependenciesResult.ts similarity index 62% rename from sdk/lib/osBindings/CheckDependenciesResult.ts rename to sdk/base/lib/osBindings/CheckDependenciesResult.ts index a435ff87f..3fa34b600 100644 --- a/sdk/lib/osBindings/CheckDependenciesResult.ts +++ b/sdk/base/lib/osBindings/CheckDependenciesResult.ts @@ -1,14 +1,17 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { ActionRequestEntry } from "./ActionRequestEntry" import type { HealthCheckId } from "./HealthCheckId" import type { NamedHealthCheckResult } from "./NamedHealthCheckResult" import type { PackageId } from "./PackageId" +import type { ReplayId } from "./ReplayId" +import type { Version } from "./Version" export type CheckDependenciesResult = { packageId: PackageId title: string | null - installedVersion: string | null - satisfies: string[] + installedVersion: Version | null + satisfies: Array isRunning: boolean - configSatisfied: boolean + requestedActions: { [key: ReplayId]: ActionRequestEntry } healthChecks: { [key: HealthCheckId]: NamedHealthCheckResult } } diff --git a/sdk/lib/osBindings/Cifs.ts b/sdk/base/lib/osBindings/Cifs.ts similarity index 100% rename from sdk/lib/osBindings/Cifs.ts rename to sdk/base/lib/osBindings/Cifs.ts diff --git a/sdk/base/lib/osBindings/ClearActionRequestsParams.ts b/sdk/base/lib/osBindings/ClearActionRequestsParams.ts new file mode 100644 index 000000000..856a13de4 --- /dev/null +++ b/sdk/base/lib/osBindings/ClearActionRequestsParams.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. + +export type ClearActionRequestsParams = + | { only: string[] } + | { except: string[] } diff --git a/sdk/base/lib/osBindings/ClearActionsParams.ts b/sdk/base/lib/osBindings/ClearActionsParams.ts new file mode 100644 index 000000000..68cff676a --- /dev/null +++ b/sdk/base/lib/osBindings/ClearActionsParams.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 { ActionId } from "./ActionId" + +export type ClearActionsParams = { except: Array } diff --git a/sdk/base/lib/osBindings/ClearBindingsParams.ts b/sdk/base/lib/osBindings/ClearBindingsParams.ts new file mode 100644 index 000000000..41f1d5741 --- /dev/null +++ b/sdk/base/lib/osBindings/ClearBindingsParams.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 { BindId } from "./BindId" + +export type ClearBindingsParams = { except: Array } diff --git a/sdk/base/lib/osBindings/ClearCallbacksParams.ts b/sdk/base/lib/osBindings/ClearCallbacksParams.ts new file mode 100644 index 000000000..095a27f5e --- /dev/null +++ b/sdk/base/lib/osBindings/ClearCallbacksParams.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 ClearCallbacksParams = { only: number[] } | { except: number[] } diff --git a/sdk/base/lib/osBindings/ClearServiceInterfacesParams.ts b/sdk/base/lib/osBindings/ClearServiceInterfacesParams.ts new file mode 100644 index 000000000..02c177978 --- /dev/null +++ b/sdk/base/lib/osBindings/ClearServiceInterfacesParams.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 { ServiceInterfaceId } from "./ServiceInterfaceId" + +export type ClearServiceInterfacesParams = { except: Array } diff --git a/sdk/base/lib/osBindings/CliSetIconParams.ts b/sdk/base/lib/osBindings/CliSetIconParams.ts new file mode 100644 index 000000000..4e47362b6 --- /dev/null +++ b/sdk/base/lib/osBindings/CliSetIconParams.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 CliSetIconParams = { icon: string } diff --git a/sdk/lib/osBindings/ContactInfo.ts b/sdk/base/lib/osBindings/ContactInfo.ts similarity index 100% rename from sdk/lib/osBindings/ContactInfo.ts rename to sdk/base/lib/osBindings/ContactInfo.ts diff --git a/sdk/lib/osBindings/CreateSubcontainerFsParams.ts b/sdk/base/lib/osBindings/CreateSubcontainerFsParams.ts similarity index 63% rename from sdk/lib/osBindings/CreateSubcontainerFsParams.ts rename to sdk/base/lib/osBindings/CreateSubcontainerFsParams.ts index 729ad4240..32d301e4a 100644 --- a/sdk/lib/osBindings/CreateSubcontainerFsParams.ts +++ b/sdk/base/lib/osBindings/CreateSubcontainerFsParams.ts @@ -1,4 +1,7 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { ImageId } from "./ImageId" -export type CreateSubcontainerFsParams = { imageId: ImageId } +export type CreateSubcontainerFsParams = { + imageId: ImageId + name: string | null +} diff --git a/sdk/lib/osBindings/CurrentDependencies.ts b/sdk/base/lib/osBindings/CurrentDependencies.ts similarity index 100% rename from sdk/lib/osBindings/CurrentDependencies.ts rename to sdk/base/lib/osBindings/CurrentDependencies.ts diff --git a/sdk/lib/osBindings/CurrentDependencyInfo.ts b/sdk/base/lib/osBindings/CurrentDependencyInfo.ts similarity index 92% rename from sdk/lib/osBindings/CurrentDependencyInfo.ts rename to sdk/base/lib/osBindings/CurrentDependencyInfo.ts index 2096a0113..e56e2be7a 100644 --- a/sdk/lib/osBindings/CurrentDependencyInfo.ts +++ b/sdk/base/lib/osBindings/CurrentDependencyInfo.ts @@ -5,5 +5,4 @@ export type CurrentDependencyInfo = { title: string | null icon: DataUrl | null versionRange: string - configSatisfied: boolean } & ({ kind: "exists" } | { kind: "running"; healthChecks: string[] }) diff --git a/sdk/lib/osBindings/DataUrl.ts b/sdk/base/lib/osBindings/DataUrl.ts similarity index 100% rename from sdk/lib/osBindings/DataUrl.ts rename to sdk/base/lib/osBindings/DataUrl.ts diff --git a/sdk/lib/osBindings/DepInfo.ts b/sdk/base/lib/osBindings/DepInfo.ts similarity index 100% rename from sdk/lib/osBindings/DepInfo.ts rename to sdk/base/lib/osBindings/DepInfo.ts diff --git a/sdk/lib/osBindings/Dependencies.ts b/sdk/base/lib/osBindings/Dependencies.ts similarity index 100% rename from sdk/lib/osBindings/Dependencies.ts rename to sdk/base/lib/osBindings/Dependencies.ts diff --git a/sdk/lib/osBindings/DependencyKind.ts b/sdk/base/lib/osBindings/DependencyKind.ts similarity index 100% rename from sdk/lib/osBindings/DependencyKind.ts rename to sdk/base/lib/osBindings/DependencyKind.ts diff --git a/sdk/lib/osBindings/DependencyMetadata.ts b/sdk/base/lib/osBindings/DependencyMetadata.ts similarity index 100% rename from sdk/lib/osBindings/DependencyMetadata.ts rename to sdk/base/lib/osBindings/DependencyMetadata.ts diff --git a/sdk/lib/osBindings/DependencyRequirement.ts b/sdk/base/lib/osBindings/DependencyRequirement.ts similarity index 100% rename from sdk/lib/osBindings/DependencyRequirement.ts rename to sdk/base/lib/osBindings/DependencyRequirement.ts diff --git a/sdk/lib/osBindings/Description.ts b/sdk/base/lib/osBindings/Description.ts similarity index 100% rename from sdk/lib/osBindings/Description.ts rename to sdk/base/lib/osBindings/Description.ts diff --git a/sdk/lib/osBindings/DestroySubcontainerFsParams.ts b/sdk/base/lib/osBindings/DestroySubcontainerFsParams.ts similarity index 100% rename from sdk/lib/osBindings/DestroySubcontainerFsParams.ts rename to sdk/base/lib/osBindings/DestroySubcontainerFsParams.ts diff --git a/sdk/base/lib/osBindings/DeviceFilter.ts b/sdk/base/lib/osBindings/DeviceFilter.ts new file mode 100644 index 000000000..6e6f5810c --- /dev/null +++ b/sdk/base/lib/osBindings/DeviceFilter.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 DeviceFilter = { + class: "processor" | "display" + pattern: string + patternDescription: string +} diff --git a/sdk/lib/osBindings/Duration.ts b/sdk/base/lib/osBindings/Duration.ts similarity index 100% rename from sdk/lib/osBindings/Duration.ts rename to sdk/base/lib/osBindings/Duration.ts diff --git a/sdk/lib/osBindings/EchoParams.ts b/sdk/base/lib/osBindings/EchoParams.ts similarity index 100% rename from sdk/lib/osBindings/EchoParams.ts rename to sdk/base/lib/osBindings/EchoParams.ts diff --git a/sdk/base/lib/osBindings/EditSignerParams.ts b/sdk/base/lib/osBindings/EditSignerParams.ts new file mode 100644 index 000000000..9532709a6 --- /dev/null +++ b/sdk/base/lib/osBindings/EditSignerParams.ts @@ -0,0 +1,13 @@ +// 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 { ContactInfo } from "./ContactInfo" +import type { Guid } from "./Guid" + +export type EditSignerParams = { + id: Guid + setName: string | null + addContact: Array + addKey: Array + removeContact: Array + removeKey: Array +} diff --git a/sdk/lib/osBindings/EncryptedWire.ts b/sdk/base/lib/osBindings/EncryptedWire.ts similarity index 100% rename from sdk/lib/osBindings/EncryptedWire.ts rename to sdk/base/lib/osBindings/EncryptedWire.ts diff --git a/sdk/lib/osBindings/ExportActionParams.ts b/sdk/base/lib/osBindings/ExportActionParams.ts similarity index 58% rename from sdk/lib/osBindings/ExportActionParams.ts rename to sdk/base/lib/osBindings/ExportActionParams.ts index 8bcfbc349..d4aa33102 100644 --- a/sdk/lib/osBindings/ExportActionParams.ts +++ b/sdk/base/lib/osBindings/ExportActionParams.ts @@ -1,10 +1,5 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { ActionId } from "./ActionId" import type { ActionMetadata } from "./ActionMetadata" -import type { PackageId } from "./PackageId" -export type ExportActionParams = { - packageId?: PackageId - id: ActionId - metadata: ActionMetadata -} +export type ExportActionParams = { id: ActionId; metadata: ActionMetadata } diff --git a/sdk/lib/osBindings/ExportServiceInterfaceParams.ts b/sdk/base/lib/osBindings/ExportServiceInterfaceParams.ts similarity index 100% rename from sdk/lib/osBindings/ExportServiceInterfaceParams.ts rename to sdk/base/lib/osBindings/ExportServiceInterfaceParams.ts diff --git a/sdk/lib/osBindings/ExposeForDependentsParams.ts b/sdk/base/lib/osBindings/ExposeForDependentsParams.ts similarity index 100% rename from sdk/lib/osBindings/ExposeForDependentsParams.ts rename to sdk/base/lib/osBindings/ExposeForDependentsParams.ts diff --git a/sdk/lib/osBindings/FullIndex.ts b/sdk/base/lib/osBindings/FullIndex.ts similarity index 100% rename from sdk/lib/osBindings/FullIndex.ts rename to sdk/base/lib/osBindings/FullIndex.ts diff --git a/sdk/lib/osBindings/FullProgress.ts b/sdk/base/lib/osBindings/FullProgress.ts similarity index 100% rename from sdk/lib/osBindings/FullProgress.ts rename to sdk/base/lib/osBindings/FullProgress.ts diff --git a/sdk/base/lib/osBindings/GetActionInputParams.ts b/sdk/base/lib/osBindings/GetActionInputParams.ts new file mode 100644 index 000000000..568ceb907 --- /dev/null +++ b/sdk/base/lib/osBindings/GetActionInputParams.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 { ActionId } from "./ActionId" +import type { PackageId } from "./PackageId" + +export type GetActionInputParams = { packageId?: PackageId; actionId: ActionId } diff --git a/sdk/lib/osBindings/GetHostInfoParams.ts b/sdk/base/lib/osBindings/GetHostInfoParams.ts similarity index 100% rename from sdk/lib/osBindings/GetHostInfoParams.ts rename to sdk/base/lib/osBindings/GetHostInfoParams.ts diff --git a/sdk/lib/osBindings/GetOsAssetParams.ts b/sdk/base/lib/osBindings/GetOsAssetParams.ts similarity index 100% rename from sdk/lib/osBindings/GetOsAssetParams.ts rename to sdk/base/lib/osBindings/GetOsAssetParams.ts diff --git a/sdk/lib/osBindings/GetOsVersionParams.ts b/sdk/base/lib/osBindings/GetOsVersionParams.ts similarity index 100% rename from sdk/lib/osBindings/GetOsVersionParams.ts rename to sdk/base/lib/osBindings/GetOsVersionParams.ts diff --git a/sdk/lib/osBindings/GetPackageParams.ts b/sdk/base/lib/osBindings/GetPackageParams.ts similarity index 100% rename from sdk/lib/osBindings/GetPackageParams.ts rename to sdk/base/lib/osBindings/GetPackageParams.ts diff --git a/sdk/lib/osBindings/GetPackageResponse.ts b/sdk/base/lib/osBindings/GetPackageResponse.ts similarity index 100% rename from sdk/lib/osBindings/GetPackageResponse.ts rename to sdk/base/lib/osBindings/GetPackageResponse.ts diff --git a/sdk/lib/osBindings/GetPackageResponseFull.ts b/sdk/base/lib/osBindings/GetPackageResponseFull.ts similarity index 100% rename from sdk/lib/osBindings/GetPackageResponseFull.ts rename to sdk/base/lib/osBindings/GetPackageResponseFull.ts diff --git a/sdk/lib/osBindings/GetPrimaryUrlParams.ts b/sdk/base/lib/osBindings/GetPrimaryUrlParams.ts similarity index 100% rename from sdk/lib/osBindings/GetPrimaryUrlParams.ts rename to sdk/base/lib/osBindings/GetPrimaryUrlParams.ts diff --git a/sdk/lib/osBindings/GetServiceInterfaceParams.ts b/sdk/base/lib/osBindings/GetServiceInterfaceParams.ts similarity index 100% rename from sdk/lib/osBindings/GetServiceInterfaceParams.ts rename to sdk/base/lib/osBindings/GetServiceInterfaceParams.ts diff --git a/sdk/lib/osBindings/GetServicePortForwardParams.ts b/sdk/base/lib/osBindings/GetServicePortForwardParams.ts similarity index 100% rename from sdk/lib/osBindings/GetServicePortForwardParams.ts rename to sdk/base/lib/osBindings/GetServicePortForwardParams.ts diff --git a/sdk/lib/osBindings/GetSslCertificateParams.ts b/sdk/base/lib/osBindings/GetSslCertificateParams.ts similarity index 100% rename from sdk/lib/osBindings/GetSslCertificateParams.ts rename to sdk/base/lib/osBindings/GetSslCertificateParams.ts diff --git a/sdk/lib/osBindings/GetSslKeyParams.ts b/sdk/base/lib/osBindings/GetSslKeyParams.ts similarity index 100% rename from sdk/lib/osBindings/GetSslKeyParams.ts rename to sdk/base/lib/osBindings/GetSslKeyParams.ts diff --git a/sdk/base/lib/osBindings/GetStatusParams.ts b/sdk/base/lib/osBindings/GetStatusParams.ts new file mode 100644 index 000000000..a0fbe3bfc --- /dev/null +++ b/sdk/base/lib/osBindings/GetStatusParams.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 { CallbackId } from "./CallbackId" +import type { PackageId } from "./PackageId" + +export type GetStatusParams = { packageId?: PackageId; callback?: CallbackId } diff --git a/sdk/lib/osBindings/GetStoreParams.ts b/sdk/base/lib/osBindings/GetStoreParams.ts similarity index 100% rename from sdk/lib/osBindings/GetStoreParams.ts rename to sdk/base/lib/osBindings/GetStoreParams.ts diff --git a/sdk/lib/osBindings/GetSystemSmtpParams.ts b/sdk/base/lib/osBindings/GetSystemSmtpParams.ts similarity index 100% rename from sdk/lib/osBindings/GetSystemSmtpParams.ts rename to sdk/base/lib/osBindings/GetSystemSmtpParams.ts diff --git a/sdk/lib/osBindings/Governor.ts b/sdk/base/lib/osBindings/Governor.ts similarity index 100% rename from sdk/lib/osBindings/Governor.ts rename to sdk/base/lib/osBindings/Governor.ts diff --git a/sdk/lib/osBindings/Guid.ts b/sdk/base/lib/osBindings/Guid.ts similarity index 100% rename from sdk/lib/osBindings/Guid.ts rename to sdk/base/lib/osBindings/Guid.ts diff --git a/sdk/lib/osBindings/HardwareRequirements.ts b/sdk/base/lib/osBindings/HardwareRequirements.ts similarity index 70% rename from sdk/lib/osBindings/HardwareRequirements.ts rename to sdk/base/lib/osBindings/HardwareRequirements.ts index e17568eec..d420f846b 100644 --- a/sdk/lib/osBindings/HardwareRequirements.ts +++ b/sdk/base/lib/osBindings/HardwareRequirements.ts @@ -1,7 +1,8 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { DeviceFilter } from "./DeviceFilter" export type HardwareRequirements = { - device: { display?: string; processor?: string } + device: Array ram: number | null arch: string[] | null } diff --git a/sdk/lib/osBindings/HealthCheckId.ts b/sdk/base/lib/osBindings/HealthCheckId.ts similarity index 100% rename from sdk/lib/osBindings/HealthCheckId.ts rename to sdk/base/lib/osBindings/HealthCheckId.ts diff --git a/sdk/lib/osBindings/Host.ts b/sdk/base/lib/osBindings/Host.ts similarity index 100% rename from sdk/lib/osBindings/Host.ts rename to sdk/base/lib/osBindings/Host.ts diff --git a/sdk/lib/osBindings/HostAddress.ts b/sdk/base/lib/osBindings/HostAddress.ts similarity index 100% rename from sdk/lib/osBindings/HostAddress.ts rename to sdk/base/lib/osBindings/HostAddress.ts diff --git a/sdk/lib/osBindings/HostId.ts b/sdk/base/lib/osBindings/HostId.ts similarity index 100% rename from sdk/lib/osBindings/HostId.ts rename to sdk/base/lib/osBindings/HostId.ts diff --git a/sdk/lib/osBindings/HostKind.ts b/sdk/base/lib/osBindings/HostKind.ts similarity index 100% rename from sdk/lib/osBindings/HostKind.ts rename to sdk/base/lib/osBindings/HostKind.ts diff --git a/sdk/lib/osBindings/HostnameInfo.ts b/sdk/base/lib/osBindings/HostnameInfo.ts similarity index 100% rename from sdk/lib/osBindings/HostnameInfo.ts rename to sdk/base/lib/osBindings/HostnameInfo.ts diff --git a/sdk/lib/osBindings/Hosts.ts b/sdk/base/lib/osBindings/Hosts.ts similarity index 100% rename from sdk/lib/osBindings/Hosts.ts rename to sdk/base/lib/osBindings/Hosts.ts diff --git a/sdk/lib/osBindings/ImageConfig.ts b/sdk/base/lib/osBindings/ImageConfig.ts similarity index 100% rename from sdk/lib/osBindings/ImageConfig.ts rename to sdk/base/lib/osBindings/ImageConfig.ts diff --git a/sdk/lib/osBindings/ImageId.ts b/sdk/base/lib/osBindings/ImageId.ts similarity index 100% rename from sdk/lib/osBindings/ImageId.ts rename to sdk/base/lib/osBindings/ImageId.ts diff --git a/sdk/lib/osBindings/ImageMetadata.ts b/sdk/base/lib/osBindings/ImageMetadata.ts similarity index 100% rename from sdk/lib/osBindings/ImageMetadata.ts rename to sdk/base/lib/osBindings/ImageMetadata.ts diff --git a/sdk/base/lib/osBindings/ImageSource.ts b/sdk/base/lib/osBindings/ImageSource.ts new file mode 100644 index 000000000..d8f876aef --- /dev/null +++ b/sdk/base/lib/osBindings/ImageSource.ts @@ -0,0 +1,13 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { BuildArg } from "./BuildArg" + +export type ImageSource = + | "packed" + | { + dockerBuild: { + workdir?: string + dockerfile?: string + buildArgs?: { [key: string]: BuildArg } + } + } + | { dockerTag: string } diff --git a/sdk/lib/osBindings/InitProgressRes.ts b/sdk/base/lib/osBindings/InitProgressRes.ts similarity index 100% rename from sdk/lib/osBindings/InitProgressRes.ts rename to sdk/base/lib/osBindings/InitProgressRes.ts diff --git a/sdk/lib/osBindings/InstallParams.ts b/sdk/base/lib/osBindings/InstallParams.ts similarity index 100% rename from sdk/lib/osBindings/InstallParams.ts rename to sdk/base/lib/osBindings/InstallParams.ts diff --git a/sdk/lib/osBindings/InstalledState.ts b/sdk/base/lib/osBindings/InstalledState.ts similarity index 100% rename from sdk/lib/osBindings/InstalledState.ts rename to sdk/base/lib/osBindings/InstalledState.ts diff --git a/sdk/lib/osBindings/InstalledVersionParams.ts b/sdk/base/lib/osBindings/InstalledVersionParams.ts similarity index 100% rename from sdk/lib/osBindings/InstalledVersionParams.ts rename to sdk/base/lib/osBindings/InstalledVersionParams.ts diff --git a/sdk/lib/osBindings/InstallingInfo.ts b/sdk/base/lib/osBindings/InstallingInfo.ts similarity index 100% rename from sdk/lib/osBindings/InstallingInfo.ts rename to sdk/base/lib/osBindings/InstallingInfo.ts diff --git a/sdk/lib/osBindings/InstallingState.ts b/sdk/base/lib/osBindings/InstallingState.ts similarity index 100% rename from sdk/lib/osBindings/InstallingState.ts rename to sdk/base/lib/osBindings/InstallingState.ts diff --git a/sdk/lib/osBindings/IpHostname.ts b/sdk/base/lib/osBindings/IpHostname.ts similarity index 100% rename from sdk/lib/osBindings/IpHostname.ts rename to sdk/base/lib/osBindings/IpHostname.ts diff --git a/sdk/lib/osBindings/IpInfo.ts b/sdk/base/lib/osBindings/IpInfo.ts similarity index 100% rename from sdk/lib/osBindings/IpInfo.ts rename to sdk/base/lib/osBindings/IpInfo.ts diff --git a/sdk/lib/osBindings/LanInfo.ts b/sdk/base/lib/osBindings/LanInfo.ts similarity index 100% rename from sdk/lib/osBindings/LanInfo.ts rename to sdk/base/lib/osBindings/LanInfo.ts diff --git a/sdk/lib/osBindings/GetConfiguredParams.ts b/sdk/base/lib/osBindings/ListPackageSignersParams.ts similarity index 72% rename from sdk/lib/osBindings/GetConfiguredParams.ts rename to sdk/base/lib/osBindings/ListPackageSignersParams.ts index 66fb6e320..73cd6a745 100644 --- a/sdk/lib/osBindings/GetConfiguredParams.ts +++ b/sdk/base/lib/osBindings/ListPackageSignersParams.ts @@ -1,4 +1,4 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { PackageId } from "./PackageId" -export type GetConfiguredParams = { packageId?: PackageId } +export type ListPackageSignersParams = { id: PackageId } diff --git a/sdk/lib/osBindings/ListServiceInterfacesParams.ts b/sdk/base/lib/osBindings/ListServiceInterfacesParams.ts similarity index 100% rename from sdk/lib/osBindings/ListServiceInterfacesParams.ts rename to sdk/base/lib/osBindings/ListServiceInterfacesParams.ts diff --git a/sdk/lib/osBindings/ListVersionSignersParams.ts b/sdk/base/lib/osBindings/ListVersionSignersParams.ts similarity index 100% rename from sdk/lib/osBindings/ListVersionSignersParams.ts rename to sdk/base/lib/osBindings/ListVersionSignersParams.ts diff --git a/sdk/lib/osBindings/LoginParams.ts b/sdk/base/lib/osBindings/LoginParams.ts similarity index 100% rename from sdk/lib/osBindings/LoginParams.ts rename to sdk/base/lib/osBindings/LoginParams.ts diff --git a/sdk/base/lib/osBindings/LshwDevice.ts b/sdk/base/lib/osBindings/LshwDevice.ts new file mode 100644 index 000000000..f2c624be7 --- /dev/null +++ b/sdk/base/lib/osBindings/LshwDevice.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. +import type { LshwDisplay } from "./LshwDisplay" +import type { LshwProcessor } from "./LshwProcessor" + +export type LshwDevice = + | ({ class: "processor" } & LshwProcessor) + | ({ class: "display" } & LshwDisplay) diff --git a/sdk/base/lib/osBindings/LshwDisplay.ts b/sdk/base/lib/osBindings/LshwDisplay.ts new file mode 100644 index 000000000..25d14b12f --- /dev/null +++ b/sdk/base/lib/osBindings/LshwDisplay.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 LshwDisplay = { product: string } diff --git a/sdk/base/lib/osBindings/LshwProcessor.ts b/sdk/base/lib/osBindings/LshwProcessor.ts new file mode 100644 index 000000000..17a47d477 --- /dev/null +++ b/sdk/base/lib/osBindings/LshwProcessor.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 LshwProcessor = { product: string } diff --git a/sdk/lib/osBindings/MainStatus.ts b/sdk/base/lib/osBindings/MainStatus.ts similarity index 61% rename from sdk/lib/osBindings/MainStatus.ts rename to sdk/base/lib/osBindings/MainStatus.ts index 1f6b3babe..64e081ab9 100644 --- a/sdk/lib/osBindings/MainStatus.ts +++ b/sdk/base/lib/osBindings/MainStatus.ts @@ -4,17 +4,23 @@ import type { NamedHealthCheckResult } from "./NamedHealthCheckResult" import type { StartStop } from "./StartStop" export type MainStatus = - | { status: "stopped" } - | { status: "restarting" } - | { status: "restoring" } - | { status: "stopping" } | { - status: "starting" + main: "error" + onRebuild: StartStop + message: string + debug: string | null + } + | { main: "stopped" } + | { main: "restarting" } + | { main: "restoring" } + | { main: "stopping" } + | { + main: "starting" health: { [key: HealthCheckId]: NamedHealthCheckResult } } | { - status: "running" + main: "running" started: string health: { [key: HealthCheckId]: NamedHealthCheckResult } } - | { status: "backingUp"; onComplete: StartStop } + | { main: "backingUp"; onComplete: StartStop } diff --git a/sdk/lib/osBindings/Manifest.ts b/sdk/base/lib/osBindings/Manifest.ts similarity index 98% rename from sdk/lib/osBindings/Manifest.ts rename to sdk/base/lib/osBindings/Manifest.ts index d40223236..8007b565b 100644 --- a/sdk/lib/osBindings/Manifest.ts +++ b/sdk/base/lib/osBindings/Manifest.ts @@ -32,5 +32,4 @@ export type Manifest = { hardwareRequirements: HardwareRequirements gitHash: string | null osVersion: string - hasConfig: boolean } diff --git a/sdk/lib/osBindings/MaybeUtf8String.ts b/sdk/base/lib/osBindings/MaybeUtf8String.ts similarity index 100% rename from sdk/lib/osBindings/MaybeUtf8String.ts rename to sdk/base/lib/osBindings/MaybeUtf8String.ts diff --git a/sdk/lib/osBindings/MerkleArchiveCommitment.ts b/sdk/base/lib/osBindings/MerkleArchiveCommitment.ts similarity index 100% rename from sdk/lib/osBindings/MerkleArchiveCommitment.ts rename to sdk/base/lib/osBindings/MerkleArchiveCommitment.ts diff --git a/sdk/lib/osBindings/MountParams.ts b/sdk/base/lib/osBindings/MountParams.ts similarity index 100% rename from sdk/lib/osBindings/MountParams.ts rename to sdk/base/lib/osBindings/MountParams.ts diff --git a/sdk/lib/osBindings/MountTarget.ts b/sdk/base/lib/osBindings/MountTarget.ts similarity index 100% rename from sdk/lib/osBindings/MountTarget.ts rename to sdk/base/lib/osBindings/MountTarget.ts diff --git a/sdk/lib/osBindings/NamedHealthCheckResult.ts b/sdk/base/lib/osBindings/NamedHealthCheckResult.ts similarity index 100% rename from sdk/lib/osBindings/NamedHealthCheckResult.ts rename to sdk/base/lib/osBindings/NamedHealthCheckResult.ts diff --git a/sdk/lib/osBindings/NamedProgress.ts b/sdk/base/lib/osBindings/NamedProgress.ts similarity index 100% rename from sdk/lib/osBindings/NamedProgress.ts rename to sdk/base/lib/osBindings/NamedProgress.ts diff --git a/sdk/lib/osBindings/OnionHostname.ts b/sdk/base/lib/osBindings/OnionHostname.ts similarity index 100% rename from sdk/lib/osBindings/OnionHostname.ts rename to sdk/base/lib/osBindings/OnionHostname.ts diff --git a/sdk/lib/osBindings/OsIndex.ts b/sdk/base/lib/osBindings/OsIndex.ts similarity index 100% rename from sdk/lib/osBindings/OsIndex.ts rename to sdk/base/lib/osBindings/OsIndex.ts diff --git a/sdk/lib/osBindings/OsVersionInfo.ts b/sdk/base/lib/osBindings/OsVersionInfo.ts similarity index 100% rename from sdk/lib/osBindings/OsVersionInfo.ts rename to sdk/base/lib/osBindings/OsVersionInfo.ts diff --git a/sdk/lib/osBindings/OsVersionInfoMap.ts b/sdk/base/lib/osBindings/OsVersionInfoMap.ts similarity index 100% rename from sdk/lib/osBindings/OsVersionInfoMap.ts rename to sdk/base/lib/osBindings/OsVersionInfoMap.ts diff --git a/sdk/lib/osBindings/PackageDataEntry.ts b/sdk/base/lib/osBindings/PackageDataEntry.ts similarity index 83% rename from sdk/lib/osBindings/PackageDataEntry.ts rename to sdk/base/lib/osBindings/PackageDataEntry.ts index 41bd98bba..86df7b767 100644 --- a/sdk/lib/osBindings/PackageDataEntry.ts +++ b/sdk/base/lib/osBindings/PackageDataEntry.ts @@ -1,25 +1,27 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { ActionId } from "./ActionId" import type { ActionMetadata } from "./ActionMetadata" +import type { ActionRequestEntry } from "./ActionRequestEntry" import type { CurrentDependencies } from "./CurrentDependencies" import type { DataUrl } from "./DataUrl" import type { Hosts } from "./Hosts" +import type { MainStatus } from "./MainStatus" import type { PackageState } from "./PackageState" import type { ServiceInterface } from "./ServiceInterface" import type { ServiceInterfaceId } from "./ServiceInterfaceId" -import type { Status } from "./Status" import type { Version } from "./Version" export type PackageDataEntry = { stateInfo: PackageState dataVersion: Version | null - status: Status + status: MainStatus registry: string | null developerKey: string icon: DataUrl lastBackup: string | null currentDependencies: CurrentDependencies actions: { [key: ActionId]: ActionMetadata } + requestedActions: { [key: string]: ActionRequestEntry } serviceInterfaces: { [key: ServiceInterfaceId]: ServiceInterface } hosts: Hosts storeExposedDependents: string[] diff --git a/sdk/lib/osBindings/PackageDetailLevel.ts b/sdk/base/lib/osBindings/PackageDetailLevel.ts similarity index 100% rename from sdk/lib/osBindings/PackageDetailLevel.ts rename to sdk/base/lib/osBindings/PackageDetailLevel.ts diff --git a/sdk/lib/osBindings/PackageId.ts b/sdk/base/lib/osBindings/PackageId.ts similarity index 100% rename from sdk/lib/osBindings/PackageId.ts rename to sdk/base/lib/osBindings/PackageId.ts diff --git a/sdk/lib/osBindings/PackageIndex.ts b/sdk/base/lib/osBindings/PackageIndex.ts similarity index 100% rename from sdk/lib/osBindings/PackageIndex.ts rename to sdk/base/lib/osBindings/PackageIndex.ts diff --git a/sdk/lib/osBindings/PackageInfo.ts b/sdk/base/lib/osBindings/PackageInfo.ts similarity index 100% rename from sdk/lib/osBindings/PackageInfo.ts rename to sdk/base/lib/osBindings/PackageInfo.ts diff --git a/sdk/lib/osBindings/PackageInfoShort.ts b/sdk/base/lib/osBindings/PackageInfoShort.ts similarity index 100% rename from sdk/lib/osBindings/PackageInfoShort.ts rename to sdk/base/lib/osBindings/PackageInfoShort.ts diff --git a/sdk/base/lib/osBindings/PackageSignerParams.ts b/sdk/base/lib/osBindings/PackageSignerParams.ts new file mode 100644 index 000000000..b131e3e23 --- /dev/null +++ b/sdk/base/lib/osBindings/PackageSignerParams.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 { Guid } from "./Guid" +import type { PackageId } from "./PackageId" + +export type PackageSignerParams = { id: PackageId; signer: Guid } diff --git a/sdk/lib/osBindings/PackageState.ts b/sdk/base/lib/osBindings/PackageState.ts similarity index 100% rename from sdk/lib/osBindings/PackageState.ts rename to sdk/base/lib/osBindings/PackageState.ts diff --git a/sdk/lib/osBindings/PackageVersionInfo.ts b/sdk/base/lib/osBindings/PackageVersionInfo.ts similarity index 100% rename from sdk/lib/osBindings/PackageVersionInfo.ts rename to sdk/base/lib/osBindings/PackageVersionInfo.ts diff --git a/sdk/lib/osBindings/PasswordType.ts b/sdk/base/lib/osBindings/PasswordType.ts similarity index 100% rename from sdk/lib/osBindings/PasswordType.ts rename to sdk/base/lib/osBindings/PasswordType.ts diff --git a/sdk/lib/osBindings/PathOrUrl.ts b/sdk/base/lib/osBindings/PathOrUrl.ts similarity index 100% rename from sdk/lib/osBindings/PathOrUrl.ts rename to sdk/base/lib/osBindings/PathOrUrl.ts diff --git a/sdk/lib/osBindings/ProcedureId.ts b/sdk/base/lib/osBindings/ProcedureId.ts similarity index 100% rename from sdk/lib/osBindings/ProcedureId.ts rename to sdk/base/lib/osBindings/ProcedureId.ts diff --git a/sdk/lib/osBindings/Progress.ts b/sdk/base/lib/osBindings/Progress.ts similarity index 100% rename from sdk/lib/osBindings/Progress.ts rename to sdk/base/lib/osBindings/Progress.ts diff --git a/sdk/lib/osBindings/Public.ts b/sdk/base/lib/osBindings/Public.ts similarity index 100% rename from sdk/lib/osBindings/Public.ts rename to sdk/base/lib/osBindings/Public.ts diff --git a/sdk/lib/osBindings/RecoverySource.ts b/sdk/base/lib/osBindings/RecoverySource.ts similarity index 100% rename from sdk/lib/osBindings/RecoverySource.ts rename to sdk/base/lib/osBindings/RecoverySource.ts diff --git a/sdk/lib/osBindings/RegistryAsset.ts b/sdk/base/lib/osBindings/RegistryAsset.ts similarity index 100% rename from sdk/lib/osBindings/RegistryAsset.ts rename to sdk/base/lib/osBindings/RegistryAsset.ts diff --git a/sdk/lib/osBindings/RegistryInfo.ts b/sdk/base/lib/osBindings/RegistryInfo.ts similarity index 100% rename from sdk/lib/osBindings/RegistryInfo.ts rename to sdk/base/lib/osBindings/RegistryInfo.ts diff --git a/sdk/base/lib/osBindings/RemoveCategoryParams.ts b/sdk/base/lib/osBindings/RemoveCategoryParams.ts new file mode 100644 index 000000000..4f468fee7 --- /dev/null +++ b/sdk/base/lib/osBindings/RemoveCategoryParams.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 RemoveCategoryParams = { id: string } diff --git a/sdk/lib/osBindings/RemoveVersionParams.ts b/sdk/base/lib/osBindings/RemoveVersionParams.ts similarity index 100% rename from sdk/lib/osBindings/RemoveVersionParams.ts rename to sdk/base/lib/osBindings/RemoveVersionParams.ts diff --git a/sdk/base/lib/osBindings/ReplayId.ts b/sdk/base/lib/osBindings/ReplayId.ts new file mode 100644 index 000000000..048ef183a --- /dev/null +++ b/sdk/base/lib/osBindings/ReplayId.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 ReplayId = string diff --git a/sdk/base/lib/osBindings/RequestActionParams.ts b/sdk/base/lib/osBindings/RequestActionParams.ts new file mode 100644 index 000000000..ccc8d0e61 --- /dev/null +++ b/sdk/base/lib/osBindings/RequestActionParams.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 { ActionId } from "./ActionId" +import type { ActionRequestInput } from "./ActionRequestInput" +import type { ActionRequestTrigger } from "./ActionRequestTrigger" +import type { ActionSeverity } from "./ActionSeverity" +import type { PackageId } from "./PackageId" +import type { ReplayId } from "./ReplayId" + +export type RequestActionParams = { + replayId: ReplayId + packageId: PackageId + actionId: ActionId + severity: ActionSeverity + reason?: string + when?: ActionRequestTrigger + input?: ActionRequestInput +} diff --git a/sdk/lib/osBindings/RequestCommitment.ts b/sdk/base/lib/osBindings/RequestCommitment.ts similarity index 100% rename from sdk/lib/osBindings/RequestCommitment.ts rename to sdk/base/lib/osBindings/RequestCommitment.ts diff --git a/sdk/lib/osBindings/ExecuteAction.ts b/sdk/base/lib/osBindings/RunActionParams.ts similarity index 88% rename from sdk/lib/osBindings/ExecuteAction.ts rename to sdk/base/lib/osBindings/RunActionParams.ts index 6e3c44f79..33864d1e6 100644 --- a/sdk/lib/osBindings/ExecuteAction.ts +++ b/sdk/base/lib/osBindings/RunActionParams.ts @@ -2,7 +2,7 @@ import type { ActionId } from "./ActionId" import type { PackageId } from "./PackageId" -export type ExecuteAction = { +export type RunActionParams = { packageId?: PackageId actionId: ActionId input: any diff --git a/sdk/lib/osBindings/Security.ts b/sdk/base/lib/osBindings/Security.ts similarity index 100% rename from sdk/lib/osBindings/Security.ts rename to sdk/base/lib/osBindings/Security.ts diff --git a/sdk/lib/osBindings/ServerInfo.ts b/sdk/base/lib/osBindings/ServerInfo.ts similarity index 78% rename from sdk/lib/osBindings/ServerInfo.ts rename to sdk/base/lib/osBindings/ServerInfo.ts index 76840cfc4..89d7fc1b0 100644 --- a/sdk/lib/osBindings/ServerInfo.ts +++ b/sdk/base/lib/osBindings/ServerInfo.ts @@ -1,6 +1,8 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { AcmeSettings } from "./AcmeSettings" import type { Governor } from "./Governor" import type { IpInfo } from "./IpInfo" +import type { LshwDevice } from "./LshwDevice" import type { ServerStatus } from "./ServerStatus" import type { SmtpValue } from "./SmtpValue" import type { WifiInfo } from "./WifiInfo" @@ -11,8 +13,9 @@ export type ServerInfo = { id: string hostname: string version: string + packageVersionCompat: string + postInitMigrationTodos: string[] lastBackup: string | null - eosVersionCompat: string lanAddress: string onionAddress: string /** @@ -20,6 +23,7 @@ export type ServerInfo = { */ torAddress: string ipInfo: { [key: string]: IpInfo } + acme: AcmeSettings | null statusInfo: ServerStatus wifi: WifiInfo unreadNotificationCount: number @@ -30,4 +34,6 @@ export type ServerInfo = { zram: boolean governor: Governor | null smtp: SmtpValue | null + ram: number + devices: Array } diff --git a/sdk/lib/osBindings/ServerSpecs.ts b/sdk/base/lib/osBindings/ServerSpecs.ts similarity index 100% rename from sdk/lib/osBindings/ServerSpecs.ts rename to sdk/base/lib/osBindings/ServerSpecs.ts diff --git a/sdk/lib/osBindings/ServerStatus.ts b/sdk/base/lib/osBindings/ServerStatus.ts similarity index 100% rename from sdk/lib/osBindings/ServerStatus.ts rename to sdk/base/lib/osBindings/ServerStatus.ts diff --git a/sdk/lib/osBindings/ServiceInterface.ts b/sdk/base/lib/osBindings/ServiceInterface.ts similarity index 100% rename from sdk/lib/osBindings/ServiceInterface.ts rename to sdk/base/lib/osBindings/ServiceInterface.ts diff --git a/sdk/lib/osBindings/ServiceInterfaceId.ts b/sdk/base/lib/osBindings/ServiceInterfaceId.ts similarity index 100% rename from sdk/lib/osBindings/ServiceInterfaceId.ts rename to sdk/base/lib/osBindings/ServiceInterfaceId.ts diff --git a/sdk/lib/osBindings/ServiceInterfaceType.ts b/sdk/base/lib/osBindings/ServiceInterfaceType.ts similarity index 100% rename from sdk/lib/osBindings/ServiceInterfaceType.ts rename to sdk/base/lib/osBindings/ServiceInterfaceType.ts diff --git a/sdk/lib/osBindings/Session.ts b/sdk/base/lib/osBindings/Session.ts similarity index 100% rename from sdk/lib/osBindings/Session.ts rename to sdk/base/lib/osBindings/Session.ts diff --git a/sdk/lib/osBindings/SessionList.ts b/sdk/base/lib/osBindings/SessionList.ts similarity index 67% rename from sdk/lib/osBindings/SessionList.ts rename to sdk/base/lib/osBindings/SessionList.ts index a85a42dee..af36aaa8a 100644 --- a/sdk/lib/osBindings/SessionList.ts +++ b/sdk/base/lib/osBindings/SessionList.ts @@ -1,4 +1,4 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { Sessions } from "./Sessions" -export type SessionList = { current: string; sessions: Sessions } +export type SessionList = { current: string | null; sessions: Sessions } diff --git a/sdk/lib/osBindings/Sessions.ts b/sdk/base/lib/osBindings/Sessions.ts similarity index 100% rename from sdk/lib/osBindings/Sessions.ts rename to sdk/base/lib/osBindings/Sessions.ts diff --git a/sdk/lib/osBindings/SetDataVersionParams.ts b/sdk/base/lib/osBindings/SetDataVersionParams.ts similarity index 100% rename from sdk/lib/osBindings/SetDataVersionParams.ts rename to sdk/base/lib/osBindings/SetDataVersionParams.ts diff --git a/sdk/lib/osBindings/SetDependenciesParams.ts b/sdk/base/lib/osBindings/SetDependenciesParams.ts similarity index 82% rename from sdk/lib/osBindings/SetDependenciesParams.ts rename to sdk/base/lib/osBindings/SetDependenciesParams.ts index bbc9b325f..7b34b50c9 100644 --- a/sdk/lib/osBindings/SetDependenciesParams.ts +++ b/sdk/base/lib/osBindings/SetDependenciesParams.ts @@ -1,8 +1,6 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { DependencyRequirement } from "./DependencyRequirement" -import type { Guid } from "./Guid" export type SetDependenciesParams = { - procedureId: Guid dependencies: Array } diff --git a/sdk/lib/osBindings/SetHealth.ts b/sdk/base/lib/osBindings/SetHealth.ts similarity index 100% rename from sdk/lib/osBindings/SetHealth.ts rename to sdk/base/lib/osBindings/SetHealth.ts diff --git a/sdk/base/lib/osBindings/SetIconParams.ts b/sdk/base/lib/osBindings/SetIconParams.ts new file mode 100644 index 000000000..f10eaa50b --- /dev/null +++ b/sdk/base/lib/osBindings/SetIconParams.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 { DataUrl } from "./DataUrl" + +export type SetIconParams = { icon: DataUrl } diff --git a/sdk/lib/osBindings/SetMainStatus.ts b/sdk/base/lib/osBindings/SetMainStatus.ts similarity index 100% rename from sdk/lib/osBindings/SetMainStatus.ts rename to sdk/base/lib/osBindings/SetMainStatus.ts diff --git a/sdk/lib/osBindings/SetMainStatusStatus.ts b/sdk/base/lib/osBindings/SetMainStatusStatus.ts similarity index 100% rename from sdk/lib/osBindings/SetMainStatusStatus.ts rename to sdk/base/lib/osBindings/SetMainStatusStatus.ts diff --git a/sdk/base/lib/osBindings/SetNameParams.ts b/sdk/base/lib/osBindings/SetNameParams.ts new file mode 100644 index 000000000..df49d7be5 --- /dev/null +++ b/sdk/base/lib/osBindings/SetNameParams.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 SetNameParams = { name: string } diff --git a/sdk/lib/osBindings/SetStoreParams.ts b/sdk/base/lib/osBindings/SetStoreParams.ts similarity index 100% rename from sdk/lib/osBindings/SetStoreParams.ts rename to sdk/base/lib/osBindings/SetStoreParams.ts diff --git a/sdk/lib/osBindings/SetupExecuteParams.ts b/sdk/base/lib/osBindings/SetupExecuteParams.ts similarity index 100% rename from sdk/lib/osBindings/SetupExecuteParams.ts rename to sdk/base/lib/osBindings/SetupExecuteParams.ts diff --git a/sdk/lib/osBindings/SetupProgress.ts b/sdk/base/lib/osBindings/SetupProgress.ts similarity index 100% rename from sdk/lib/osBindings/SetupProgress.ts rename to sdk/base/lib/osBindings/SetupProgress.ts diff --git a/sdk/lib/osBindings/SetupResult.ts b/sdk/base/lib/osBindings/SetupResult.ts similarity index 91% rename from sdk/lib/osBindings/SetupResult.ts rename to sdk/base/lib/osBindings/SetupResult.ts index 464aeb4b7..d81c7f039 100644 --- a/sdk/lib/osBindings/SetupResult.ts +++ b/sdk/base/lib/osBindings/SetupResult.ts @@ -2,6 +2,7 @@ export type SetupResult = { torAddress: string + hostname: string lanAddress: string rootCa: string } diff --git a/sdk/lib/osBindings/SetupStatusRes.ts b/sdk/base/lib/osBindings/SetupStatusRes.ts similarity index 100% rename from sdk/lib/osBindings/SetupStatusRes.ts rename to sdk/base/lib/osBindings/SetupStatusRes.ts diff --git a/sdk/lib/osBindings/SignAssetParams.ts b/sdk/base/lib/osBindings/SignAssetParams.ts similarity index 100% rename from sdk/lib/osBindings/SignAssetParams.ts rename to sdk/base/lib/osBindings/SignAssetParams.ts diff --git a/sdk/lib/osBindings/SignerInfo.ts b/sdk/base/lib/osBindings/SignerInfo.ts similarity index 100% rename from sdk/lib/osBindings/SignerInfo.ts rename to sdk/base/lib/osBindings/SignerInfo.ts diff --git a/sdk/lib/osBindings/SmtpValue.ts b/sdk/base/lib/osBindings/SmtpValue.ts similarity index 100% rename from sdk/lib/osBindings/SmtpValue.ts rename to sdk/base/lib/osBindings/SmtpValue.ts diff --git a/sdk/lib/osBindings/StartStop.ts b/sdk/base/lib/osBindings/StartStop.ts similarity index 100% rename from sdk/lib/osBindings/StartStop.ts rename to sdk/base/lib/osBindings/StartStop.ts diff --git a/sdk/lib/osBindings/UpdatingState.ts b/sdk/base/lib/osBindings/UpdatingState.ts similarity index 100% rename from sdk/lib/osBindings/UpdatingState.ts rename to sdk/base/lib/osBindings/UpdatingState.ts diff --git a/sdk/lib/osBindings/VerifyCifsParams.ts b/sdk/base/lib/osBindings/VerifyCifsParams.ts similarity index 100% rename from sdk/lib/osBindings/VerifyCifsParams.ts rename to sdk/base/lib/osBindings/VerifyCifsParams.ts diff --git a/sdk/lib/osBindings/Version.ts b/sdk/base/lib/osBindings/Version.ts similarity index 100% rename from sdk/lib/osBindings/Version.ts rename to sdk/base/lib/osBindings/Version.ts diff --git a/sdk/lib/osBindings/VersionSignerParams.ts b/sdk/base/lib/osBindings/VersionSignerParams.ts similarity index 100% rename from sdk/lib/osBindings/VersionSignerParams.ts rename to sdk/base/lib/osBindings/VersionSignerParams.ts diff --git a/sdk/lib/osBindings/VolumeId.ts b/sdk/base/lib/osBindings/VolumeId.ts similarity index 100% rename from sdk/lib/osBindings/VolumeId.ts rename to sdk/base/lib/osBindings/VolumeId.ts diff --git a/sdk/lib/osBindings/WifiInfo.ts b/sdk/base/lib/osBindings/WifiInfo.ts similarity index 100% rename from sdk/lib/osBindings/WifiInfo.ts rename to sdk/base/lib/osBindings/WifiInfo.ts diff --git a/sdk/lib/osBindings/index.ts b/sdk/base/lib/osBindings/index.ts similarity index 78% rename from sdk/lib/osBindings/index.ts rename to sdk/base/lib/osBindings/index.ts index 9492fe796..f76f595c9 100644 --- a/sdk/lib/osBindings/index.ts +++ b/sdk/base/lib/osBindings/index.ts @@ -1,8 +1,23 @@ export { AcceptSigners } from "./AcceptSigners" +export { AcmeSettings } from "./AcmeSettings" export { ActionId } from "./ActionId" +export { ActionInput } from "./ActionInput" export { ActionMetadata } from "./ActionMetadata" +export { ActionRequestCondition } from "./ActionRequestCondition" +export { ActionRequestEntry } from "./ActionRequestEntry" +export { ActionRequestInput } from "./ActionRequestInput" +export { ActionRequestTrigger } from "./ActionRequestTrigger" +export { ActionRequest } from "./ActionRequest" +export { ActionResultMember } from "./ActionResultMember" +export { ActionResult } from "./ActionResult" +export { ActionResultV0 } from "./ActionResultV0" +export { ActionResultV1 } from "./ActionResultV1" +export { ActionResultValue } from "./ActionResultValue" +export { ActionSeverity } from "./ActionSeverity" +export { ActionVisibility } from "./ActionVisibility" export { AddAdminParams } from "./AddAdminParams" export { AddAssetParams } from "./AddAssetParams" +export { AddCategoryParams } from "./AddCategoryParams" export { AddPackageParams } from "./AddPackageParams" export { AddressInfo } from "./AddressInfo" export { AddSslOptions } from "./AddSslOptions" @@ -20,16 +35,24 @@ export { AttachParams } from "./AttachParams" export { BackupProgress } from "./BackupProgress" export { BackupTargetFS } from "./BackupTargetFS" export { Base64 } from "./Base64" +export { BindId } from "./BindId" export { BindInfo } from "./BindInfo" export { BindOptions } from "./BindOptions" export { BindParams } from "./BindParams" export { Blake3Commitment } from "./Blake3Commitment" export { BlockDev } from "./BlockDev" +export { BuildArg } from "./BuildArg" export { CallbackId } from "./CallbackId" export { Category } from "./Category" export { CheckDependenciesParam } from "./CheckDependenciesParam" export { CheckDependenciesResult } from "./CheckDependenciesResult" export { Cifs } from "./Cifs" +export { ClearActionRequestsParams } from "./ClearActionRequestsParams" +export { ClearActionsParams } from "./ClearActionsParams" +export { ClearBindingsParams } from "./ClearBindingsParams" +export { ClearCallbacksParams } from "./ClearCallbacksParams" +export { ClearServiceInterfacesParams } from "./ClearServiceInterfacesParams" +export { CliSetIconParams } from "./CliSetIconParams" export { ContactInfo } from "./ContactInfo" export { CreateSubcontainerFsParams } from "./CreateSubcontainerFsParams" export { CurrentDependencies } from "./CurrentDependencies" @@ -42,16 +65,17 @@ export { DependencyRequirement } from "./DependencyRequirement" export { DepInfo } from "./DepInfo" export { Description } from "./Description" export { DestroySubcontainerFsParams } from "./DestroySubcontainerFsParams" +export { DeviceFilter } from "./DeviceFilter" export { Duration } from "./Duration" export { EchoParams } from "./EchoParams" +export { EditSignerParams } from "./EditSignerParams" export { EncryptedWire } from "./EncryptedWire" -export { ExecuteAction } from "./ExecuteAction" export { ExportActionParams } from "./ExportActionParams" export { ExportServiceInterfaceParams } from "./ExportServiceInterfaceParams" export { ExposeForDependentsParams } from "./ExposeForDependentsParams" export { FullIndex } from "./FullIndex" export { FullProgress } from "./FullProgress" -export { GetConfiguredParams } from "./GetConfiguredParams" +export { GetActionInputParams } from "./GetActionInputParams" export { GetHostInfoParams } from "./GetHostInfoParams" export { GetOsAssetParams } from "./GetOsAssetParams" export { GetOsVersionParams } from "./GetOsVersionParams" @@ -63,6 +87,7 @@ export { GetServiceInterfaceParams } from "./GetServiceInterfaceParams" export { GetServicePortForwardParams } from "./GetServicePortForwardParams" export { GetSslCertificateParams } from "./GetSslCertificateParams" export { GetSslKeyParams } from "./GetSslKeyParams" +export { GetStatusParams } from "./GetStatusParams" export { GetStoreParams } from "./GetStoreParams" export { GetSystemSmtpParams } from "./GetSystemSmtpParams" export { Governor } from "./Governor" @@ -88,9 +113,13 @@ export { InstallParams } from "./InstallParams" export { IpHostname } from "./IpHostname" export { IpInfo } from "./IpInfo" export { LanInfo } from "./LanInfo" +export { ListPackageSignersParams } from "./ListPackageSignersParams" export { ListServiceInterfacesParams } from "./ListServiceInterfacesParams" export { ListVersionSignersParams } from "./ListVersionSignersParams" export { LoginParams } from "./LoginParams" +export { LshwDevice } from "./LshwDevice" +export { LshwDisplay } from "./LshwDisplay" +export { LshwProcessor } from "./LshwProcessor" export { MainStatus } from "./MainStatus" export { Manifest } from "./Manifest" export { MaybeUtf8String } from "./MaybeUtf8String" @@ -109,6 +138,7 @@ export { PackageId } from "./PackageId" export { PackageIndex } from "./PackageIndex" export { PackageInfoShort } from "./PackageInfoShort" export { PackageInfo } from "./PackageInfo" +export { PackageSignerParams } from "./PackageSignerParams" export { PackageState } from "./PackageState" export { PackageVersionInfo } from "./PackageVersionInfo" export { PasswordType } from "./PasswordType" @@ -119,8 +149,12 @@ export { Public } from "./Public" export { RecoverySource } from "./RecoverySource" export { RegistryAsset } from "./RegistryAsset" export { RegistryInfo } from "./RegistryInfo" +export { RemoveCategoryParams } from "./RemoveCategoryParams" export { RemoveVersionParams } from "./RemoveVersionParams" +export { ReplayId } from "./ReplayId" +export { RequestActionParams } from "./RequestActionParams" export { RequestCommitment } from "./RequestCommitment" +export { RunActionParams } from "./RunActionParams" export { Security } from "./Security" export { ServerInfo } from "./ServerInfo" export { ServerSpecs } from "./ServerSpecs" @@ -131,12 +165,13 @@ export { ServiceInterfaceType } from "./ServiceInterfaceType" export { SessionList } from "./SessionList" export { Sessions } from "./Sessions" export { Session } from "./Session" -export { SetConfigured } from "./SetConfigured" export { SetDataVersionParams } from "./SetDataVersionParams" export { SetDependenciesParams } from "./SetDependenciesParams" export { SetHealth } from "./SetHealth" +export { SetIconParams } from "./SetIconParams" export { SetMainStatusStatus } from "./SetMainStatusStatus" export { SetMainStatus } from "./SetMainStatus" +export { SetNameParams } from "./SetNameParams" export { SetStoreParams } from "./SetStoreParams" export { SetupExecuteParams } from "./SetupExecuteParams" export { SetupProgress } from "./SetupProgress" @@ -146,7 +181,6 @@ export { SignAssetParams } from "./SignAssetParams" export { SignerInfo } from "./SignerInfo" export { SmtpValue } from "./SmtpValue" export { StartStop } from "./StartStop" -export { Status } from "./Status" export { UpdatingState } from "./UpdatingState" export { VerifyCifsParams } from "./VerifyCifsParams" export { VersionSignerParams } from "./VersionSignerParams" diff --git a/sdk/lib/s9pk/index.ts b/sdk/base/lib/s9pk/index.ts similarity index 90% rename from sdk/lib/s9pk/index.ts rename to sdk/base/lib/s9pk/index.ts index eba8ed3f8..84a1ec644 100644 --- a/sdk/lib/s9pk/index.ts +++ b/sdk/base/lib/s9pk/index.ts @@ -1,6 +1,6 @@ import { DataUrl, Manifest, MerkleArchiveCommitment } from "../osBindings" import { ArrayBufferReader, MerkleArchive } from "./merkleArchive" -import mime from "mime" +import mime from "mime-types" const magicAndVersion = new Uint8Array([59, 59, 2]) @@ -52,13 +52,14 @@ export class S9pk { async icon(): Promise { const iconName = Object.keys(this.archive.contents.contents).find( (name) => - name.startsWith("icon.") && mime.getType(name)?.startsWith("image/"), + name.startsWith("icon.") && + (mime.contentType(name) || null)?.startsWith("image/"), ) if (!iconName) { throw new Error("no icon found in archive") } return ( - `data:${mime.getType(iconName)};base64,` + + `data:${mime.contentType(iconName)};base64,` + Buffer.from( await this.archive.contents.getPath([iconName])!.verifiedFileContents(), ).toString("base64") diff --git a/sdk/lib/s9pk/merkleArchive/directoryContents.ts b/sdk/base/lib/s9pk/merkleArchive/directoryContents.ts similarity index 100% rename from sdk/lib/s9pk/merkleArchive/directoryContents.ts rename to sdk/base/lib/s9pk/merkleArchive/directoryContents.ts diff --git a/sdk/lib/s9pk/merkleArchive/fileContents.ts b/sdk/base/lib/s9pk/merkleArchive/fileContents.ts similarity index 100% rename from sdk/lib/s9pk/merkleArchive/fileContents.ts rename to sdk/base/lib/s9pk/merkleArchive/fileContents.ts diff --git a/sdk/lib/s9pk/merkleArchive/index.ts b/sdk/base/lib/s9pk/merkleArchive/index.ts similarity index 100% rename from sdk/lib/s9pk/merkleArchive/index.ts rename to sdk/base/lib/s9pk/merkleArchive/index.ts diff --git a/sdk/lib/s9pk/merkleArchive/varint.ts b/sdk/base/lib/s9pk/merkleArchive/varint.ts similarity index 96% rename from sdk/lib/s9pk/merkleArchive/varint.ts rename to sdk/base/lib/s9pk/merkleArchive/varint.ts index 016505307..a6a425289 100644 --- a/sdk/lib/s9pk/merkleArchive/varint.ts +++ b/sdk/base/lib/s9pk/merkleArchive/varint.ts @@ -1,4 +1,4 @@ -import { asError } from "../../util/asError" +import { asError } from "../../util" const msb = 0x80 const dropMsb = 0x7f diff --git a/sdk/lib/test/exverList.test.ts b/sdk/base/lib/test/exverList.test.ts similarity index 100% rename from sdk/lib/test/exverList.test.ts rename to sdk/base/lib/test/exverList.test.ts diff --git a/sdk/lib/test/graph.test.ts b/sdk/base/lib/test/graph.test.ts similarity index 99% rename from sdk/lib/test/graph.test.ts rename to sdk/base/lib/test/graph.test.ts index 7f02adc2e..a738123d6 100644 --- a/sdk/lib/test/graph.test.ts +++ b/sdk/base/lib/test/graph.test.ts @@ -1,4 +1,4 @@ -import { Graph } from "../util/graph" +import { Graph } from "../util" describe("graph", () => { { diff --git a/sdk/lib/test/configTypes.test.ts b/sdk/base/lib/test/inputSpecTypes.test.ts similarity index 64% rename from sdk/lib/test/configTypes.test.ts rename to sdk/base/lib/test/inputSpecTypes.test.ts index 6d0b9a3d8..6767faf20 100644 --- a/sdk/lib/test/configTypes.test.ts +++ b/sdk/base/lib/test/inputSpecTypes.test.ts @@ -1,15 +1,18 @@ -import { ListValueSpecOf, isValueSpecListOf } from "../config/configTypes" -import { Config } from "../config/builder/config" -import { List } from "../config/builder/list" -import { Value } from "../config/builder/value" +import { + ListValueSpecOf, + isValueSpecListOf, +} from "../actions/input/inputSpecTypes" +import { InputSpec } from "../actions/input/builder/inputSpec" +import { List } from "../actions/input/builder/list" +import { Value } from "../actions/input/builder/value" -describe("Config Types", () => { +describe("InputSpec Types", () => { test("isValueSpecListOf", async () => { const options = [List.obj, List.text] for (const option of options) { const test = (option as any)( {} as any, - { spec: Config.of({}) } as any, + { spec: InputSpec.of({}) } as any, ) as any const someList = await Value.list(test).build({} as any) if (isValueSpecListOf(someList, "text")) { diff --git a/sdk/lib/test/startosTypeValidation.test.ts b/sdk/base/lib/test/startosTypeValidation.test.ts similarity index 79% rename from sdk/lib/test/startosTypeValidation.test.ts rename to sdk/base/lib/test/startosTypeValidation.test.ts index bcbc4b6ec..509da0894 100644 --- a/sdk/lib/test/startosTypeValidation.test.ts +++ b/sdk/base/lib/test/startosTypeValidation.test.ts @@ -1,18 +1,22 @@ import { Effects } from "../types" import { CheckDependenciesParam, - ExecuteAction, - GetConfiguredParams, - GetStoreParams, + ClearActionRequestsParams, + ClearActionsParams, + ClearBindingsParams, + ClearCallbacksParams, + ClearServiceInterfacesParams, + GetActionInputParams, + GetStatusParams, + RequestActionParams, + RunActionParams, SetDataVersionParams, SetMainStatus, - SetStoreParams, } from ".././osBindings" import { CreateSubcontainerFsParams } from ".././osBindings" import { DestroySubcontainerFsParams } from ".././osBindings" import { BindParams } from ".././osBindings" import { GetHostInfoParams } from ".././osBindings" -import { SetConfigured } from ".././osBindings" import { SetHealth } from ".././osBindings" import { ExposeForDependentsParams } from ".././osBindings" import { GetSslCertificateParams } from ".././osBindings" @@ -41,21 +45,27 @@ type EffectsTypeChecker = { describe("startosTypeValidation ", () => { test(`checking the params match`, () => { - const testInput: any = {} typeEquality({ - executeAction: {} as ExecuteAction, + constRetry: {}, + clearCallbacks: {} as ClearCallbacksParams, + action: { + clear: {} as ClearActionsParams, + export: {} as ExportActionParams, + getInput: {} as GetActionInputParams, + run: {} as RunActionParams, + request: {} as RequestActionParams, + clearRequests: {} as ClearActionRequestsParams, + }, subcontainer: { createFs: {} as CreateSubcontainerFsParams, destroyFs: {} as DestroySubcontainerFsParams, }, - clearBindings: undefined, + clearBindings: {} as ClearBindingsParams, getInstalledPackages: undefined, bind: {} as BindParams, getHostInfo: {} as WithCallback, - getConfigured: {} as GetConfiguredParams, restart: undefined, shutdown: undefined, - setConfigured: {} as SetConfigured, setDataVersion: {} as SetDataVersionParams, getDataVersion: undefined, setHealth: {} as SetHealth, @@ -71,19 +81,15 @@ describe("startosTypeValidation ", () => { getSystemSmtp: {} as WithCallback, getContainerIp: undefined, getServicePortForward: {} as GetServicePortForwardParams, - clearServiceInterfaces: undefined, + clearServiceInterfaces: {} as ClearServiceInterfacesParams, exportServiceInterface: {} as ExportServiceInterfaceParams, getPrimaryUrl: {} as WithCallback, listServiceInterfaces: {} as WithCallback, - exportAction: {} as ExportActionParams, - clearActions: undefined, mount: {} as MountParams, checkDependencies: {} as CheckDependenciesParam, getDependencies: undefined, + getStatus: {} as WithCallback, setMainStatus: {} as SetMainStatus, }) - typeEquality[0]>( - testInput as ExecuteAction, - ) }) }) diff --git a/sdk/lib/test/util.deepMerge.test.ts b/sdk/base/lib/test/util.deepMerge.test.ts similarity index 70% rename from sdk/lib/test/util.deepMerge.test.ts rename to sdk/base/lib/test/util.deepMerge.test.ts index 25a4a7d22..74ff92c26 100644 --- a/sdk/lib/test/util.deepMerge.test.ts +++ b/sdk/base/lib/test/util.deepMerge.test.ts @@ -1,5 +1,5 @@ -import { deepEqual } from "../util/deepEqual" -import { deepMerge } from "../util/deepMerge" +import { deepEqual } from "../util" +import { deepMerge } from "../util" describe("deepMerge", () => { test("deepMerge({}, {a: 1}, {b: 2}) should return {a: 1, b: 2}", () => { @@ -20,7 +20,11 @@ describe("deepMerge", () => { }), ).toBeTruthy() }) - test("deepMerge([1,2,3], [2,3,4]) should equal [2,3,4]", () => { - expect(deepMerge([1, 2, 3], [2, 3, 4])).toEqual([2, 3, 4]) + test("Test that merging lists has Set semantics", () => { + const merge = deepMerge(["a", "b"], ["b", "c"]) + expect(merge).toHaveLength(3) + expect(merge).toContain("a") + expect(merge).toContain("b") + expect(merge).toContain("c") }) }) diff --git a/sdk/lib/test/util.getNetworkInterface.test.ts b/sdk/base/lib/test/util.getNetworkInterface.test.ts similarity index 100% rename from sdk/lib/test/util.getNetworkInterface.test.ts rename to sdk/base/lib/test/util.getNetworkInterface.test.ts diff --git a/sdk/base/lib/types.ts b/sdk/base/lib/types.ts new file mode 100644 index 000000000..36d4bd293 --- /dev/null +++ b/sdk/base/lib/types.ts @@ -0,0 +1,236 @@ +export * as inputSpecTypes from "./actions/input/inputSpecTypes" + +import { + DependencyRequirement, + NamedHealthCheckResult, + Manifest, + ServiceInterface, + ActionId, +} from "./osBindings" +import { Affine, StringObject, ToKebab } from "./util" +import { Action, Actions } from "./actions/setupActions" +import { Effects } from "./Effects" +export { Effects } +export * from "./osBindings" +export { SDKManifest } from "./types/ManifestTypes" +export { + RequiredDependenciesOf as RequiredDependencies, + OptionalDependenciesOf as OptionalDependencies, + CurrentDependenciesResult, +} from "./dependencies/setupDependencies" + +export type ExposedStorePaths = string[] & Affine<"ExposedStorePaths"> +declare const HealthProof: unique symbol +export type HealthReceipt = { + [HealthProof]: never +} + +export type DaemonBuildable = { + build(): Promise<{ + term(): Promise + }> +} + +export type ServiceInterfaceType = "ui" | "p2p" | "api" +export type Signals = NodeJS.Signals +export const SIGTERM: Signals = "SIGTERM" +export const SIGKILL: Signals = "SIGKILL" +export const NO_TIMEOUT = -1 + +export type PathMaker = (options: { volume: string; path: string }) => string +export type MaybePromise = Promise | A +export namespace ExpectedExports { + version: 1 + + /** For backing up service data though the startOS UI */ + export type createBackup = (options: { effects: Effects }) => Promise + /** For restoring service data that was previously backed up using the startOS UI create backup flow. Backup restores are also triggered via the startOS UI, or doing a system restore flow during setup. */ + export type restoreBackup = (options: { + effects: Effects + }) => Promise + + /** + * This is the entrypoint for the main container. Used to start up something like the service that the + * package represents, like running a bitcoind in a bitcoind-wrapper. + */ + export type main = (options: { + effects: Effects + started(onTerm: () => PromiseLike): PromiseLike + }) => Promise + + /** + * After a shutdown, if we wanted to do any operations to clean up things, like + * set the action as unavailable or something. + */ + export type afterShutdown = (options: { + effects: Effects + }) => Promise + + /** + * Every time a service launches (both on startup, and on install) this function is called before packageInit + * Can be used to register callbacks + */ + export type containerInit = (options: { + effects: Effects + }) => Promise + + /** + * Every time a package completes an install, this function is called before the main. + * Can be used to do migration like things. + */ + export type packageInit = (options: { effects: Effects }) => Promise + /** This will be ran during any time a package is uninstalled, for example during a update + * this will be called. + */ + export type packageUninit = (options: { + effects: Effects + nextVersion: null | string + }) => Promise + + export type manifest = Manifest + + export type actions = Actions< + any, + Record> + > +} +export type ABI = { + createBackup: ExpectedExports.createBackup + restoreBackup: ExpectedExports.restoreBackup + main: ExpectedExports.main + afterShutdown: ExpectedExports.afterShutdown + containerInit: ExpectedExports.containerInit + packageInit: ExpectedExports.packageInit + packageUninit: ExpectedExports.packageUninit + manifest: ExpectedExports.manifest + actions: ExpectedExports.actions +} +export type TimeMs = number +export type VersionString = string + +declare const DaemonProof: unique symbol +export type DaemonReceipt = { + [DaemonProof]: never +} +export type Daemon = { + wait(): Promise + term(): Promise + [DaemonProof]: never +} + +export type HealthStatus = NamedHealthCheckResult["result"] +export type SmtpValue = { + server: string + port: number + from: string + login: string + password: string | null | undefined +} + +export type CommandType = string | [string, ...string[]] + +export type DaemonReturned = { + wait(): Promise + term(options?: { signal?: Signals; timeout?: number }): Promise +} + +export declare const hostName: unique symbol +// asdflkjadsf.onion | 1.2.3.4 +export type Hostname = string & { [hostName]: never } + +export type HostnameInfoIp = { + kind: "ip" + networkInterfaceId: string + public: boolean + hostname: + | { + kind: "ipv4" | "ipv6" | "local" + value: string + port: number | null + sslPort: number | null + } + | { + kind: "domain" + domain: string + subdomain: string | null + port: number | null + sslPort: number | null + } +} + +export type HostnameInfoOnion = { + kind: "onion" + hostname: { value: string; port: number | null; sslPort: number | null } +} + +export type HostnameInfo = HostnameInfoIp | HostnameInfoOnion + +export type ServiceInterfaceId = string + +export { ServiceInterface } +export type ExposeServicePaths = { + /** The path to the value in the Store. [JsonPath](https://jsonpath.com/) */ + paths: ExposedStorePaths +} + +export type EffectMethod = { + [K in keyof T]-?: K extends string + ? T[K] extends Function + ? ToKebab + : T[K] extends StringObject + ? `${ToKebab}.${EffectMethod}` + : never + : never +}[keyof T] + +export type SyncOptions = { + /** delete files that exist in the target directory, but not in the source directory */ + delete: boolean + /** do not sync files with paths that match these patterns */ + exclude: string[] +} + +/** + * This is the metadata that is returned from the metadata call. + */ +export type Metadata = { + fileType: string + isDir: boolean + isFile: boolean + isSymlink: boolean + len: number + modified?: Date + accessed?: Date + created?: Date + readonly: boolean + uid: number + gid: number + mode: number +} + +export type SetResult = { + dependsOn: DependsOn + signal: Signals +} + +export type PackageId = string +export type Message = string +export type DependencyKind = "running" | "exists" + +export type DependsOn = { + [packageId: string]: string[] | readonly string[] +} + +export type KnownError = + | { error: string } + | { + errorCode: [number, string] | readonly [number, string] + } + +export type Dependencies = Array + +export type DeepPartial = T extends unknown[] + ? T + : T extends {} + ? { [P in keyof T]?: DeepPartial } + : T diff --git a/sdk/base/lib/types/ManifestTypes.ts b/sdk/base/lib/types/ManifestTypes.ts new file mode 100644 index 000000000..17defebcd --- /dev/null +++ b/sdk/base/lib/types/ManifestTypes.ts @@ -0,0 +1,168 @@ +import { T } from ".." +import { ImageId, ImageSource } from "../types" + +export type SDKManifest = { + /** + * The package identifier used by StartOS. This must be unique amongst all other known packages. + * @example nextcloud + * */ + readonly id: string + /** + * The human readable name of your service + * @example Nextcloud + * */ + readonly title: string + /** + * The name of the software license for this project. The license itself should be included in the root of the project directory. + * @example MIT + */ + readonly license: string + /** + * URL of the StartOS package repository + * @example `https://github.com/Start9Labs/nextcloud-startos` + */ + readonly wrapperRepo: string + /** + * URL of the upstream service repository + * @example `https://github.com/nextcloud/docker` + */ + readonly upstreamRepo: string + /** + * URL where users can get help using the upstream service + * @example `https://github.com/nextcloud/docker/issues` + */ + readonly supportSite: string + /** + * URL where users can learn more about the upstream service + * @example `https://nextcloud.com` + */ + readonly marketingSite: string + /** + * (optional) URL where users can donate to the upstream project + * @example `https://nextcloud.com/contribute/` + */ + readonly donationUrl: string | null + readonly description: { + /** Short description to display on the marketplace list page. Max length 80 chars. */ + readonly short: string + /** Long description to display on the marketplace details page for this service. Max length 500 chars. */ + readonly long: string + } + /** + * @description A mapping of OS images needed to run the container processes. Each image ID is a unique key. + * @example + * Using dockerTag... + * + * ``` + images: { + main: { + source: { + dockerTag: 'start9/hello-world', + }, + }, + }, + * ``` + * @example + * Using dockerBuild... + * + * ``` + images: { + main: { + source: { + dockerBuild: { + dockerFile: '../Dockerfile', + workdir: '.', + }, + }, + }, + }, + * ``` + */ + readonly images: Record + /** + * @description A list of readonly asset directories that will mount to the container. Each item here must + * correspond to a directory in the /assets directory of this project. + * + * Most projects will not make use of this. + * @example [] + */ + readonly assets: string[] + /** + * @description A list of data volumes that will mount to the container. Must contain at least one volume. + * @example ['main'] + */ + readonly volumes: string[] + + readonly alerts?: { + /** An warning alert requiring user confirmation before proceeding with initial installation of this service. */ + readonly install?: string | null + /** An warning alert requiring user confirmation before updating this service. */ + readonly update?: string | null + /** An warning alert requiring user confirmation before uninstalling this service. */ + readonly uninstall?: string | null + /** An warning alert requiring user confirmation before restoring this service from backup. */ + readonly restore?: string | null + /** An warning alert requiring user confirmation before starting this service. */ + readonly start?: string | null + /** An warning alert requiring user confirmation before stopping this service. */ + readonly stop?: string | null + } + /** + * @description A mapping of service dependencies to be displayed to users when viewing the Marketplace + * @property {string} description - An explanation of why this service is a dependency. + * @property {boolean} optional - Whether or not this dependency is required or contingent on user configuration. + * @property {string} s9pk - A path or url to an s9pk of the dependency to extract metadata at build time + * @example + * ``` + dependencies: { + 'hello-world': { + description: 'A moon needs a world', + optional: false, + s9pk: '', + }, + }, + * ``` + */ + readonly dependencies: Record + /** + * @description (optional) A set of hardware requirements for this service. If the user's machine + * does not meet these requirements, they will not be able to install this service. + * @property {object[]} devices - TODO Aiden confirm type on the left. List of required devices (displays or processors). + * @property {number} ram - Minimum RAM requirement (in megabytes MB) + * @property {string[]} arch - List of supported arches + * @example + * ``` + TODO Aiden verify below and provide examples for devices + hardwareRequirements: { + devices: [ + { class: 'display', value: '' }, + { class: 'processor', value: '' }, + ], + ram: 8192, + arch: ['x86-64'], + }, + * ``` + */ + readonly hardwareRequirements?: { + readonly device?: T.DeviceFilter[] + readonly ram?: number | null + readonly arch?: string[] | null + } +} + +// this is hacky but idk a more elegant way +type ArchOptions = { + 0: ["x86_64", "aarch64"] + 1: ["aarch64", "x86_64"] + 2: ["x86_64"] + 3: ["aarch64"] +} +export type SDKImageInputSpec = { + [A in keyof ArchOptions]: { + source: Exclude + arch?: ArchOptions[A] + emulateMissingAs?: ArchOptions[A][number] | null + } +}[keyof ArchOptions] + +export type ManifestDependency = T.Manifest["dependencies"][string] diff --git a/sdk/lib/util/GetSystemSmtp.ts b/sdk/base/lib/util/GetSystemSmtp.ts similarity index 90% rename from sdk/lib/util/GetSystemSmtp.ts rename to sdk/base/lib/util/GetSystemSmtp.ts index 498a2d8b2..cd87a9db6 100644 --- a/sdk/lib/util/GetSystemSmtp.ts +++ b/sdk/base/lib/util/GetSystemSmtp.ts @@ -1,4 +1,4 @@ -import { Effects } from "../types" +import { Effects } from "../Effects" export class GetSystemSmtp { constructor(readonly effects: Effects) {} @@ -8,7 +8,7 @@ export class GetSystemSmtp { */ const() { return this.effects.getSystemSmtp({ - callback: this.effects.restart, + callback: () => this.effects.constRetry(), }) } /** diff --git a/sdk/lib/util/Hostname.ts b/sdk/base/lib/util/Hostname.ts similarity index 100% rename from sdk/lib/util/Hostname.ts rename to sdk/base/lib/util/Hostname.ts diff --git a/sdk/lib/store/PathBuilder.ts b/sdk/base/lib/util/PathBuilder.ts similarity index 100% rename from sdk/lib/store/PathBuilder.ts rename to sdk/base/lib/util/PathBuilder.ts diff --git a/sdk/base/lib/util/asError.ts b/sdk/base/lib/util/asError.ts new file mode 100644 index 000000000..c3454e0e4 --- /dev/null +++ b/sdk/base/lib/util/asError.ts @@ -0,0 +1,9 @@ +export const asError = (e: unknown) => { + if (e instanceof Error) { + return new Error(e as any) + } + if (typeof e === "string") { + return new Error(`${e}`) + } + return new Error(`${JSON.stringify(e)}`) +} diff --git a/sdk/lib/util/deepEqual.ts b/sdk/base/lib/util/deepEqual.ts similarity index 100% rename from sdk/lib/util/deepEqual.ts rename to sdk/base/lib/util/deepEqual.ts diff --git a/sdk/base/lib/util/deepMerge.ts b/sdk/base/lib/util/deepMerge.ts new file mode 100644 index 000000000..72392a887 --- /dev/null +++ b/sdk/base/lib/util/deepMerge.ts @@ -0,0 +1,86 @@ +export function partialDiff( + prev: T, + next: T, +): { diff: Partial } | undefined { + if (prev === next) { + return + } else if (Array.isArray(prev) && Array.isArray(next)) { + const res = { diff: [] as any[] } + for (let newItem of next) { + let anyEq = false + for (let oldItem of prev) { + if (!partialDiff(oldItem, newItem)) { + anyEq = true + break + } + } + if (!anyEq) { + res.diff.push(newItem) + } + } + if (res.diff.length) { + return res as any + } else { + return + } + } else if (typeof prev === "object" && typeof next === "object") { + if (prev === null) { + return { diff: next } + } + if (next === null) return + const res = { diff: {} as Record } + for (let key in next) { + const diff = partialDiff(prev[key], next[key]) + if (diff) { + res.diff[key] = diff.diff + } + } + if (Object.keys(res.diff).length) { + return res + } else { + return + } + } else { + return { diff: next } + } +} + +export function deepMerge(...args: unknown[]): unknown { + const lastItem = (args as any)[args.length - 1] + if (typeof lastItem !== "object" || !lastItem) return lastItem + if (Array.isArray(lastItem)) + return deepMergeList( + ...(args.filter((x) => Array.isArray(x)) as unknown[][]), + ) + return deepMergeObject( + ...(args.filter( + (x) => typeof x === "object" && x && !Array.isArray(x), + ) as object[]), + ) +} + +function deepMergeList(...args: unknown[][]): unknown[] { + const res: unknown[] = [] + for (let arg of args) { + for (let item of arg) { + if (!res.some((x) => !partialDiff(x, item))) { + res.push(item) + } + } + } + return res +} + +function deepMergeObject(...args: object[]): object { + const lastItem = (args as any)[args.length - 1] + if (args.length === 0) return lastItem as any + if (args.length === 1) args.unshift({}) + const allKeys = new Set(args.flatMap((x) => Object.keys(x))) + for (const key of allKeys) { + const filteredValues = args.flatMap((x) => + key in x ? [(x as any)[key]] : [], + ) + ;(args as any)[0][key] = deepMerge(...filteredValues) + } + return args[0] as any +} diff --git a/sdk/lib/util/getDefaultString.ts b/sdk/base/lib/util/getDefaultString.ts similarity index 79% rename from sdk/lib/util/getDefaultString.ts rename to sdk/base/lib/util/getDefaultString.ts index fa35b4e66..2bbf8d279 100644 --- a/sdk/lib/util/getDefaultString.ts +++ b/sdk/base/lib/util/getDefaultString.ts @@ -1,4 +1,4 @@ -import { DefaultString } from "../config/configTypes" +import { DefaultString } from "../actions/input/inputSpecTypes" import { getRandomString } from "./getRandomString" export function getDefaultString(defaultSpec: DefaultString): string { diff --git a/sdk/lib/util/getRandomCharInSet.ts b/sdk/base/lib/util/getRandomCharInSet.ts similarity index 100% rename from sdk/lib/util/getRandomCharInSet.ts rename to sdk/base/lib/util/getRandomCharInSet.ts diff --git a/sdk/lib/util/getRandomString.ts b/sdk/base/lib/util/getRandomString.ts similarity index 79% rename from sdk/lib/util/getRandomString.ts rename to sdk/base/lib/util/getRandomString.ts index ea0989bcd..7b52041d8 100644 --- a/sdk/lib/util/getRandomString.ts +++ b/sdk/base/lib/util/getRandomString.ts @@ -1,4 +1,4 @@ -import { RandomString } from "../config/configTypes" +import { RandomString } from "../actions/input/inputSpecTypes" import { getRandomCharInSet } from "./getRandomCharInSet" export function getRandomString(generator: RandomString): string { diff --git a/sdk/lib/util/getServiceInterface.ts b/sdk/base/lib/util/getServiceInterface.ts similarity index 98% rename from sdk/lib/util/getServiceInterface.ts rename to sdk/base/lib/util/getServiceInterface.ts index fd0fef779..cbbb345cb 100644 --- a/sdk/lib/util/getServiceInterface.ts +++ b/sdk/base/lib/util/getServiceInterface.ts @@ -1,8 +1,7 @@ -import { ServiceInterfaceType } from "../StartSdk" +import { ServiceInterfaceType } from "../types" import { knownProtocols } from "../interfaces/Host" import { AddressInfo, - Effects, Host, HostAddress, Hostname, @@ -11,6 +10,7 @@ import { HostnameInfoOnion, IpInfo, } from "../types" +import { Effects } from "../Effects" export type UrlString = string export type HostId = string @@ -232,7 +232,7 @@ export class GetServiceInterface { */ async const() { const { id, packageId } = this.opts - const callback = this.effects.restart + const callback = () => this.effects.constRetry() const interfaceFilled = await makeInterfaceFilled({ effects: this.effects, id, diff --git a/sdk/lib/util/getServiceInterfaces.ts b/sdk/base/lib/util/getServiceInterfaces.ts similarity index 96% rename from sdk/lib/util/getServiceInterfaces.ts rename to sdk/base/lib/util/getServiceInterfaces.ts index 9f0e242b8..1d83684d6 100644 --- a/sdk/lib/util/getServiceInterfaces.ts +++ b/sdk/base/lib/util/getServiceInterfaces.ts @@ -1,4 +1,4 @@ -import { Effects } from "../types" +import { Effects } from "../Effects" import { ServiceInterfaceFilled, filledAddress, @@ -63,7 +63,7 @@ export class GetServiceInterfaces { */ async const() { const { packageId } = this.opts - const callback = this.effects.restart + const callback = () => this.effects.constRetry() const interfaceFilled: ServiceInterfaceFilled[] = await makeManyInterfaceFilled({ effects: this.effects, diff --git a/sdk/lib/util/graph.ts b/sdk/base/lib/util/graph.ts similarity index 89% rename from sdk/lib/util/graph.ts rename to sdk/base/lib/util/graph.ts index 5ad71a04d..682ccf63e 100644 --- a/sdk/lib/util/graph.ts +++ b/sdk/base/lib/util/graph.ts @@ -1,17 +1,17 @@ import { boolean } from "ts-matches" -export type Vertex = { +export type Vertex = { metadata: VMetadata edges: Array> } -export type Edge = { +export type Edge = { metadata: EMetadata from: Vertex to: Vertex } -export class Graph { +export class Graph { private readonly vertices: Array> = [] constructor() {} addVertex( @@ -46,7 +46,7 @@ export class Graph { } findVertex( predicate: (vertex: Vertex) => boolean, - ): Generator, void> { + ): Generator, null> { const veritces = this.vertices function* gen() { for (let vertex of veritces) { @@ -54,6 +54,7 @@ export class Graph { yield vertex } } + return null } return gen() } @@ -75,13 +76,13 @@ export class Graph { from: | Vertex | ((vertex: Vertex) => boolean), - ): Generator, void> { + ): Generator, null> { const visited: Array> = [] function* rec( vertex: Vertex, - ): Generator, void> { + ): Generator, null> { if (visited.includes(vertex)) { - return + return null } visited.push(vertex) yield vertex @@ -99,6 +100,7 @@ export class Graph { } } } + return null } if (from instanceof Function) { @@ -115,6 +117,7 @@ export class Graph { } } } + return null })() } else { return rec(from) @@ -124,13 +127,13 @@ export class Graph { to: | Vertex | ((vertex: Vertex) => boolean), - ): Generator, void> { + ): Generator, null> { const visited: Array> = [] function* rec( vertex: Vertex, - ): Generator, void> { + ): Generator, null> { if (visited.includes(vertex)) { - return + return null } visited.push(vertex) yield vertex @@ -148,6 +151,7 @@ export class Graph { } } } + return null } if (to instanceof Function) { @@ -164,6 +168,7 @@ export class Graph { } } } + return null })() } else { return rec(to) @@ -176,7 +181,7 @@ export class Graph { to: | Vertex | ((vertex: Vertex) => boolean), - ): Array> | void { + ): Array> | null { const isDone = to instanceof Function ? to @@ -186,12 +191,12 @@ export class Graph { function* check( vertex: Vertex, path: Array>, - ): Generator> | undefined> { + ): Generator> | null> { if (isDone(vertex)) { return path } if (visited.includes(vertex)) { - return + return null } visited.push(vertex) yield @@ -213,6 +218,7 @@ export class Graph { } } } + return null } if (from instanceof Function) { @@ -240,5 +246,6 @@ export class Graph { } } } + return null } } diff --git a/sdk/lib/util/inMs.test.ts b/sdk/base/lib/util/inMs.test.ts similarity index 100% rename from sdk/lib/util/inMs.test.ts rename to sdk/base/lib/util/inMs.test.ts diff --git a/sdk/lib/util/inMs.ts b/sdk/base/lib/util/inMs.ts similarity index 95% rename from sdk/lib/util/inMs.ts rename to sdk/base/lib/util/inMs.ts index 547fb8bea..548eb14bf 100644 --- a/sdk/lib/util/inMs.ts +++ b/sdk/base/lib/util/inMs.ts @@ -1,5 +1,3 @@ -import { DEFAULT_SIGTERM_TIMEOUT } from "../mainFn" - const matchTimeRegex = /^\s*(\d+)?(\.\d+)?\s*(ms|s|m|h|d)/ const unitMultiplier = (unit?: string) => { diff --git a/sdk/base/lib/util/index.ts b/sdk/base/lib/util/index.ts new file mode 100644 index 000000000..4c9e803bb --- /dev/null +++ b/sdk/base/lib/util/index.ts @@ -0,0 +1,22 @@ +/// Currently being used +export { addressHostToUrl } from "./getServiceInterface" +export { getDefaultString } from "./getDefaultString" + +/// Not being used, but known to be browser compatible +export { GetServiceInterface, getServiceInterface } from "./getServiceInterface" +export { getServiceInterfaces } from "./getServiceInterfaces" +export { once } from "./once" +export { asError } from "./asError" +export * as Patterns from "./patterns" +export * from "./typeHelpers" +export { GetSystemSmtp } from "./GetSystemSmtp" +export { Graph, Vertex } from "./graph" +export { inMs } from "./inMs" +export { splitCommand } from "./splitCommand" +export { nullIfEmpty } from "./nullIfEmpty" +export { deepMerge, partialDiff } from "./deepMerge" +export { deepEqual } from "./deepEqual" +export { hostnameInfoToAddress } from "./Hostname" +export { PathBuilder, extractJsonPath, StorePath } from "./PathBuilder" +export * as regexes from "./regexes" +export { stringFromStdErrOut } from "./stringFromStdErrOut" diff --git a/sdk/base/lib/util/nullIfEmpty.ts b/sdk/base/lib/util/nullIfEmpty.ts new file mode 100644 index 000000000..b24907b7d --- /dev/null +++ b/sdk/base/lib/util/nullIfEmpty.ts @@ -0,0 +1,10 @@ +/** + * A useful tool when doing a getInputSpec. + * Look into the inputSpec {@link FileHelper} for an example of the use. + * @param s + * @returns + */ +export function nullIfEmpty>(s: null | A) { + if (s === null) return null + return Object.keys(s).length === 0 ? null : s +} diff --git a/sdk/lib/util/once.ts b/sdk/base/lib/util/once.ts similarity index 100% rename from sdk/lib/util/once.ts rename to sdk/base/lib/util/once.ts diff --git a/sdk/lib/util/patterns.ts b/sdk/base/lib/util/patterns.ts similarity index 96% rename from sdk/lib/util/patterns.ts rename to sdk/base/lib/util/patterns.ts index ac281b081..2c9c7010d 100644 --- a/sdk/lib/util/patterns.ts +++ b/sdk/base/lib/util/patterns.ts @@ -1,4 +1,4 @@ -import { Pattern } from "../config/configTypes" +import { Pattern } from "../actions/input/inputSpecTypes" import * as regexes from "./regexes" export const ipv6: Pattern = { diff --git a/sdk/lib/util/regexes.ts b/sdk/base/lib/util/regexes.ts similarity index 100% rename from sdk/lib/util/regexes.ts rename to sdk/base/lib/util/regexes.ts diff --git a/sdk/lib/util/splitCommand.ts b/sdk/base/lib/util/splitCommand.ts similarity index 100% rename from sdk/lib/util/splitCommand.ts rename to sdk/base/lib/util/splitCommand.ts diff --git a/sdk/lib/util/stringFromStdErrOut.ts b/sdk/base/lib/util/stringFromStdErrOut.ts similarity index 100% rename from sdk/lib/util/stringFromStdErrOut.ts rename to sdk/base/lib/util/stringFromStdErrOut.ts diff --git a/sdk/lib/util/typeHelpers.ts b/sdk/base/lib/util/typeHelpers.ts similarity index 100% rename from sdk/lib/util/typeHelpers.ts rename to sdk/base/lib/util/typeHelpers.ts diff --git a/sdk/package-lock.json b/sdk/base/package-lock.json similarity index 53% rename from sdk/package-lock.json rename to sdk/base/package-lock.json index fe4fee235..d7b491303 100644 --- a/sdk/package-lock.json +++ b/sdk/base/package-lock.json @@ -1,12 +1,11 @@ { - "name": "@start9labs/start-sdk", + "name": "@start9labs/start-sdk-base", "version": "0.3.6-alpha8", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "@start9labs/start-sdk", - "version": "0.3.6-alpha8", + "name": "@start9labs/start-sdk-base", "license": "MIT", "dependencies": { "@iarna/toml": "^2.2.5", @@ -14,15 +13,14 @@ "@noble/hashes": "^1.4.0", "isomorphic-fetch": "^3.0.0", "lodash.merge": "^4.6.2", - "mime": "^4.0.3", - "ts-matches": "^5.5.1", + "mime-types": "^2.1.35", + "ts-matches": "^6.1.0", "yaml": "^2.2.2" }, "devDependencies": { - "@iarna/toml": "^2.2.5", "@types/jest": "^29.4.0", "@types/lodash.merge": "^4.6.2", - "copyfiles": "^2.4.1", + "@types/mime-types": "^2.1.4", "jest": "^29.4.3", "peggy": "^3.0.2", "prettier": "^3.2.5", @@ -30,14 +28,14 @@ "ts-node": "^10.9.1", "ts-pegjs": "^4.2.1", "tsx": "^4.7.1", - "typescript": "^5.0.4", - "yaml": "^2.2.2" + "typescript": "^5.0.4" } }, "node_modules/@ampproject/remapping": { "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", "dev": true, - "license": "Apache-2.0", "dependencies": { "@jridgewell/gen-mapping": "^0.1.0", "@jridgewell/trace-mapping": "^0.3.9" @@ -48,8 +46,9 @@ }, "node_modules/@babel/code-frame": { "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", "dev": true, - "license": "MIT", "dependencies": { "@babel/highlight": "^7.18.6" }, @@ -59,16 +58,18 @@ }, "node_modules/@babel/compat-data": { "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.0.tgz", + "integrity": "sha512-gMuZsmsgxk/ENC3O/fRw5QY8A9/uxQbbCEypnLIiYYc/qVJtEV7ouxC3EllIIwNzMqAQee5tanFabWsUOutS7g==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { "version": "7.21.3", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.3.tgz", + "integrity": "sha512-qIJONzoa/qiHghnm0l1n4i/6IIziDpzqc36FBs4pzMhDUraHqponwJLiAKm1hGLP3OSB/TVNz6rMwVGpwxxySw==", "dev": true, - "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.18.6", @@ -96,13 +97,15 @@ }, "node_modules/@babel/core/node_modules/convert-source-map": { "version": "1.9.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true }, "node_modules/@babel/generator": { "version": "7.21.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.3.tgz", + "integrity": "sha512-QS3iR1GYC/YGUnW7IdggFeN5c1poPUurnGttOV/bZgPGV+izC/D8HnD6DLwod0fsatNyVn1G3EVWMYIF0nHbeA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/types": "^7.21.3", "@jridgewell/gen-mapping": "^0.3.2", @@ -115,8 +118,9 @@ }, "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", "dev": true, - "license": "MIT", "dependencies": { "@jridgewell/set-array": "^1.0.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -128,8 +132,9 @@ }, "node_modules/@babel/helper-compilation-targets": { "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz", + "integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==", "dev": true, - "license": "MIT", "dependencies": { "@babel/compat-data": "^7.20.5", "@babel/helper-validator-option": "^7.18.6", @@ -146,16 +151,18 @@ }, "node_modules/@babel/helper-environment-visitor": { "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", + "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-function-name": { "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz", + "integrity": "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/template": "^7.20.7", "@babel/types": "^7.21.0" @@ -166,8 +173,9 @@ }, "node_modules/@babel/helper-hoist-variables": { "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", + "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", "dev": true, - "license": "MIT", "dependencies": { "@babel/types": "^7.18.6" }, @@ -177,8 +185,9 @@ }, "node_modules/@babel/helper-module-imports": { "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", + "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/types": "^7.18.6" }, @@ -188,8 +197,9 @@ }, "node_modules/@babel/helper-module-transforms": { "version": "7.21.2", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz", + "integrity": "sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-module-imports": "^7.18.6", @@ -206,16 +216,18 @@ }, "node_modules/@babel/helper-plugin-utils": { "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", + "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-simple-access": { "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz", + "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/types": "^7.20.2" }, @@ -225,8 +237,9 @@ }, "node_modules/@babel/helper-split-export-declaration": { "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", + "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/types": "^7.18.6" }, @@ -236,32 +249,36 @@ }, "node_modules/@babel/helper-string-parser": { "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", + "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz", + "integrity": "sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.21.0.tgz", + "integrity": "sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/template": "^7.20.7", "@babel/traverse": "^7.21.0", @@ -273,8 +290,9 @@ }, "node_modules/@babel/highlight": { "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.18.6", "chalk": "^2.0.0", @@ -286,8 +304,9 @@ }, "node_modules/@babel/highlight/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": { "color-convert": "^1.9.0" }, @@ -297,8 +316,9 @@ }, "node_modules/@babel/highlight/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": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -310,37 +330,42 @@ }, "node_modules/@babel/highlight/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": { "color-name": "1.1.3" } }, "node_modules/@babel/highlight/node_modules/color-name": { "version": "1.1.3", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true }, "node_modules/@babel/highlight/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": { "node": ">=0.8.0" } }, "node_modules/@babel/highlight/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": { "node": ">=4" } }, "node_modules/@babel/highlight/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": { "has-flag": "^3.0.0" }, @@ -350,8 +375,9 @@ }, "node_modules/@babel/parser": { "version": "7.21.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.3.tgz", + "integrity": "sha512-lobG0d7aOfQRXh8AyklEAgZGvA4FShxo6xQbUrrT/cNBPUdIDojlokwJsQyCC/eKia7ifqM0yP+2DRZ4WKw2RQ==", "dev": true, - "license": "MIT", "bin": { "parser": "bin/babel-parser.js" }, @@ -361,8 +387,9 @@ }, "node_modules/@babel/plugin-syntax-async-generators": { "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -372,8 +399,9 @@ }, "node_modules/@babel/plugin-syntax-bigint": { "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -383,8 +411,9 @@ }, "node_modules/@babel/plugin-syntax-class-properties": { "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.12.13" }, @@ -394,8 +423,9 @@ }, "node_modules/@babel/plugin-syntax-import-meta": { "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -405,8 +435,9 @@ }, "node_modules/@babel/plugin-syntax-json-strings": { "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -416,8 +447,9 @@ }, "node_modules/@babel/plugin-syntax-jsx": { "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz", + "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.6" }, @@ -430,8 +462,9 @@ }, "node_modules/@babel/plugin-syntax-logical-assignment-operators": { "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -441,8 +474,9 @@ }, "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -452,8 +486,9 @@ }, "node_modules/@babel/plugin-syntax-numeric-separator": { "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -463,8 +498,9 @@ }, "node_modules/@babel/plugin-syntax-object-rest-spread": { "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -474,8 +510,9 @@ }, "node_modules/@babel/plugin-syntax-optional-catch-binding": { "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -485,8 +522,9 @@ }, "node_modules/@babel/plugin-syntax-optional-chaining": { "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -496,8 +534,9 @@ }, "node_modules/@babel/plugin-syntax-top-level-await": { "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -510,8 +549,9 @@ }, "node_modules/@babel/plugin-syntax-typescript": { "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.20.0.tgz", + "integrity": "sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.19.0" }, @@ -524,8 +564,9 @@ }, "node_modules/@babel/template": { "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", + "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/code-frame": "^7.18.6", "@babel/parser": "^7.20.7", @@ -537,8 +578,9 @@ }, "node_modules/@babel/traverse": { "version": "7.21.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.3.tgz", + "integrity": "sha512-XLyopNeaTancVitYZe2MlUEvgKb6YVVPXzofHgqHijCImG33b/uTurMS488ht/Hbsb2XK3U2BnSTxKVNGV3nGQ==", "dev": true, - "license": "MIT", "dependencies": { "@babel/code-frame": "^7.18.6", "@babel/generator": "^7.21.3", @@ -557,8 +599,9 @@ }, "node_modules/@babel/types": { "version": "7.21.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.3.tgz", + "integrity": "sha512-sBGdETxC+/M4o/zKC0sl6sjWv62WFR/uzxrJ6uYyMLZOUlPnwzw0tKgVHOXxaAd5l2g8pEDM5RZ495GPQI77kg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", @@ -570,13 +613,15 @@ }, "node_modules/@bcoe/v8-coverage": { "version": "0.2.3", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true }, "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": { "@jridgewell/trace-mapping": "0.3.9" }, @@ -586,22 +631,40 @@ }, "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": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz", + "integrity": "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/@iarna/toml": { "version": "2.2.5", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.5.tgz", + "integrity": "sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==" }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", "dev": true, - "license": "ISC", "dependencies": { "camelcase": "^5.3.1", "find-up": "^4.1.0", @@ -615,16 +678,18 @@ }, "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": { "node": ">=8" } }, "node_modules/@jest/console": { "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.5.0.tgz", + "integrity": "sha512-NEpkObxPwyw/XxZVLPmAGKE89IQRp4puc6IQRPru6JKd1M3fW9v1xM1AnzIJE65hbCkzQAdnL8P47e9hzhiYLQ==", "dev": true, - "license": "MIT", "dependencies": { "@jest/types": "^29.5.0", "@types/node": "*", @@ -639,8 +704,9 @@ }, "node_modules/@jest/core": { "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.5.0.tgz", + "integrity": "sha512-28UzQc7ulUrOQw1IsN/kv1QES3q2kkbl/wGslyhAclqZ/8cMdB5M68BffkIdSJgKBUt50d3hbwJ92XESlE7LiQ==", "dev": true, - "license": "MIT", "dependencies": { "@jest/console": "^29.5.0", "@jest/reporters": "^29.5.0", @@ -685,8 +751,9 @@ }, "node_modules/@jest/environment": { "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.5.0.tgz", + "integrity": "sha512-5FXw2+wD29YU1d4I2htpRX7jYnAyTRjP2CsXQdo9SAM8g3ifxWPSV0HnClSn71xwctr0U3oZIIH+dtbfmnbXVQ==", "dev": true, - "license": "MIT", "dependencies": { "@jest/fake-timers": "^29.5.0", "@jest/types": "^29.5.0", @@ -699,8 +766,9 @@ }, "node_modules/@jest/expect": { "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.5.0.tgz", + "integrity": "sha512-PueDR2HGihN3ciUNGr4uelropW7rqUfTiOn+8u0leg/42UhblPxHkfoh0Ruu3I9Y1962P3u2DY4+h7GVTSVU6g==", "dev": true, - "license": "MIT", "dependencies": { "expect": "^29.5.0", "jest-snapshot": "^29.5.0" @@ -711,8 +779,9 @@ }, "node_modules/@jest/expect-utils": { "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.5.0.tgz", + "integrity": "sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg==", "dev": true, - "license": "MIT", "dependencies": { "jest-get-type": "^29.4.3" }, @@ -722,8 +791,9 @@ }, "node_modules/@jest/fake-timers": { "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.5.0.tgz", + "integrity": "sha512-9ARvuAAQcBwDAqOnglWq2zwNIRUDtk/SCkp/ToGEhFv5r86K21l+VEs0qNTaXtyiY0lEePl3kylijSYJQqdbDg==", "dev": true, - "license": "MIT", "dependencies": { "@jest/types": "^29.5.0", "@sinonjs/fake-timers": "^10.0.2", @@ -738,8 +808,9 @@ }, "node_modules/@jest/globals": { "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.5.0.tgz", + "integrity": "sha512-S02y0qMWGihdzNbUiqSAiKSpSozSuHX5UYc7QbnHP+D9Lyw8DgGGCinrN9uSuHPeKgSSzvPom2q1nAtBvUsvPQ==", "dev": true, - "license": "MIT", "dependencies": { "@jest/environment": "^29.5.0", "@jest/expect": "^29.5.0", @@ -752,8 +823,9 @@ }, "node_modules/@jest/reporters": { "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.5.0.tgz", + "integrity": "sha512-D05STXqj/M8bP9hQNSICtPqz97u7ffGzZu+9XLucXhkOFBqKcXe04JLZOgIekOxdb73MAoBUFnqvf7MCpKk5OA==", "dev": true, - "license": "MIT", "dependencies": { "@bcoe/v8-coverage": "^0.2.3", "@jest/console": "^29.5.0", @@ -794,8 +866,9 @@ }, "node_modules/@jest/schemas": { "version": "29.4.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.3.tgz", + "integrity": "sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg==", "dev": true, - "license": "MIT", "dependencies": { "@sinclair/typebox": "^0.25.16" }, @@ -805,8 +878,9 @@ }, "node_modules/@jest/source-map": { "version": "29.4.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.4.3.tgz", + "integrity": "sha512-qyt/mb6rLyd9j1jUts4EQncvS6Yy3PM9HghnNv86QBlV+zdL2inCdK1tuVlL+J+lpiw2BI67qXOrX3UurBqQ1w==", "dev": true, - "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "^0.3.15", "callsites": "^3.0.0", @@ -818,8 +892,9 @@ }, "node_modules/@jest/test-result": { "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.5.0.tgz", + "integrity": "sha512-fGl4rfitnbfLsrfx1uUpDEESS7zM8JdgZgOCQuxQvL1Sn/I6ijeAVQWGfXI9zb1i9Mzo495cIpVZhA0yr60PkQ==", "dev": true, - "license": "MIT", "dependencies": { "@jest/console": "^29.5.0", "@jest/types": "^29.5.0", @@ -832,8 +907,9 @@ }, "node_modules/@jest/test-sequencer": { "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.5.0.tgz", + "integrity": "sha512-yPafQEcKjkSfDXyvtgiV4pevSeyuA6MQr6ZIdVkWJly9vkqjnFfcfhRQqpD5whjoU8EORki752xQmjaqoFjzMQ==", "dev": true, - "license": "MIT", "dependencies": { "@jest/test-result": "^29.5.0", "graceful-fs": "^4.2.9", @@ -846,8 +922,9 @@ }, "node_modules/@jest/transform": { "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.5.0.tgz", + "integrity": "sha512-8vbeZWqLJOvHaDfeMuoHITGKSz5qWc9u04lnWrQE3VyuSw604PzQM824ZeX9XSjUCeDiE3GuxZe5UKa8J61NQw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/core": "^7.11.6", "@jest/types": "^29.5.0", @@ -871,8 +948,9 @@ }, "node_modules/@jest/types": { "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", + "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", "dev": true, - "license": "MIT", "dependencies": { "@jest/schemas": "^29.4.3", "@types/istanbul-lib-coverage": "^2.0.0", @@ -887,8 +965,9 @@ }, "node_modules/@jridgewell/gen-mapping": { "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", "dev": true, - "license": "MIT", "dependencies": { "@jridgewell/set-array": "^1.0.0", "@jridgewell/sourcemap-codec": "^1.4.10" @@ -899,38 +978,42 @@ }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/set-array": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.14", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", "dev": true, - "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "3.1.0", "@jridgewell/sourcemap-codec": "1.4.14" } }, "node_modules/@noble/curves": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.2.tgz", - "integrity": "sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.0.tgz", + "integrity": "sha512-p+4cb332SFCrReJkCYe8Xzm0OWi4Jji5jVdIZRL/PmacmDkFNw6MrrV+gGpiPxLHbV+zKFRywUWbaseT+tZRXg==", "dependencies": { "@noble/hashes": "1.4.0" }, @@ -986,21 +1069,24 @@ }, "node_modules/@sinclair/typebox": { "version": "0.25.24", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz", + "integrity": "sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==", + "dev": true }, "node_modules/@sinonjs/commons": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { "type-detect": "4.0.8" } }, "node_modules/@sinonjs/fake-timers": { "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.0.2.tgz", + "integrity": "sha512-SwUDyjWnah1AaNl7kxsa7cfLhlTYoiyhDAIgyh+El30YvXs/o7OLXpYH88Zdhyx9JExKrmHDJ+10bwIcY80Jmw==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { "@sinonjs/commons": "^2.0.0" } @@ -1041,45 +1127,35 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@ts-morph/common/node_modules/mkdirp": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-2.1.6.tgz", - "integrity": "sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A==", - "dev": true, - "bin": { - "mkdirp": "dist/cjs/src/bin.js" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@tsconfig/node10": { "version": "1.0.9", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true }, "node_modules/@tsconfig/node12": { "version": "1.0.11", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true }, "node_modules/@tsconfig/node14": { "version": "1.0.3", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true }, "node_modules/@tsconfig/node16": { "version": "1.0.3", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", + "dev": true }, "node_modules/@types/babel__core": { "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.0.tgz", + "integrity": "sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ==", "dev": true, - "license": "MIT", "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", @@ -1090,16 +1166,18 @@ }, "node_modules/@types/babel__generator": { "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", + "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/types": "^7.0.0" } }, "node_modules/@types/babel__template": { "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", "dev": true, - "license": "MIT", "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" @@ -1107,54 +1185,60 @@ }, "node_modules/@types/babel__traverse": { "version": "7.18.3", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.3.tgz", + "integrity": "sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w==", "dev": true, - "license": "MIT", "dependencies": { "@babel/types": "^7.3.0" } }, "node_modules/@types/graceful-fs": { "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", + "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*" } }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "dev": true }, "node_modules/@types/istanbul-lib-report": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", "dev": true, - "license": "MIT", "dependencies": { "@types/istanbul-lib-coverage": "*" } }, "node_modules/@types/istanbul-reports": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", "dev": true, - "license": "MIT", "dependencies": { "@types/istanbul-lib-report": "*" } }, "node_modules/@types/jest": { "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.0.tgz", + "integrity": "sha512-3Emr5VOl/aoBwnWcH/EFQvlSAmjV+XtV9GGu5mwdYew5vhQh0IUZx/60x0TzHDu09Bi7HMx10t/namdJw5QIcg==", "dev": true, - "license": "MIT", "dependencies": { "expect": "^29.0.0", "pretty-format": "^29.0.0" } }, "node_modules/@types/lodash": { - "version": "4.17.7", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.7.tgz", - "integrity": "sha512-8wTvZawATi/lsmNu10/j2hk1KEP0IvjubqPE3cu1Xz7xfXXt5oCq3SNUz4fMIP4XGF9Ky+Ue2tBA3hcS7LSBlA==", + "version": "4.17.5", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.5.tgz", + "integrity": "sha512-MBIOHVZqVqgfro1euRDWX7OO0fBVUUMrN6Pwm8LQsz8cWhEpihlvR70ENj3f40j58TNxZaWv2ndSkInykNBBJw==", "dev": true }, "node_modules/@types/lodash.merge": { @@ -1166,38 +1250,51 @@ "@types/lodash": "*" } }, - "node_modules/@types/node": { - "version": "18.15.10", + "node_modules/@types/mime-types": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@types/mime-types/-/mime-types-2.1.4.tgz", + "integrity": "sha512-lfU4b34HOri+kAY5UheuFMWPDOI+OPceBSHZKp69gEyTL/mmJ4cnU6Y/rlme3UL3GyOn6Y42hyIEw0/q8sWx5w==", "dev": true, "license": "MIT" }, + "node_modules/@types/node": { + "version": "18.15.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.10.tgz", + "integrity": "sha512-9avDaQJczATcXgfmMAW3MIWArOO7A+m90vuCFLr8AotWf8igO/mRoYukrk2cqZVtv38tHs33retzHEilM7FpeQ==", + "dev": true + }, "node_modules/@types/prettier": { "version": "2.7.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.2.tgz", + "integrity": "sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==", + "dev": true }, "node_modules/@types/stack-utils": { "version": "2.0.1", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "dev": true }, "node_modules/@types/yargs": { "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", "dev": true, - "license": "MIT", "dependencies": { "@types/yargs-parser": "*" } }, "node_modules/@types/yargs-parser": { "version": "21.0.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", + "dev": true }, "node_modules/acorn": { "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", "dev": true, - "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -1207,16 +1304,18 @@ }, "node_modules/acorn-walk": { "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.4.0" } }, "node_modules/ansi-escapes": { "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", "dev": true, - "license": "MIT", "dependencies": { "type-fest": "^0.21.3" }, @@ -1229,16 +1328,18 @@ }, "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==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } }, "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": { "color-convert": "^2.0.1" }, @@ -1251,8 +1352,9 @@ }, "node_modules/anymatch": { "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, - "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -1263,21 +1365,24 @@ }, "node_modules/arg": { "version": "4.1.3", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true }, "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": { "sprintf-js": "~1.0.2" } }, "node_modules/babel-jest": { "version": "29.5.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.5.0.tgz", + "integrity": "sha512-mA4eCDh5mSo2EcA9xQjVTpmbbNk32Zb3Q3QFQsNhaK56Q+yoXowzFodLux30HRgyOho5rsQ6B0P9QpMkvvnJ0Q==", "dev": true, - "license": "MIT", "dependencies": { "@jest/transform": "^29.5.0", "@types/babel__core": "^7.1.14", @@ -1296,8 +1401,9 @@ }, "node_modules/babel-plugin-istanbul": { "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@istanbuljs/load-nyc-config": "^1.0.0", @@ -1311,8 +1417,9 @@ }, "node_modules/babel-plugin-jest-hoist": { "version": "29.5.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.5.0.tgz", + "integrity": "sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w==", "dev": true, - "license": "MIT", "dependencies": { "@babel/template": "^7.3.3", "@babel/types": "^7.3.3", @@ -1325,8 +1432,9 @@ }, "node_modules/babel-preset-current-node-syntax": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", "dev": true, - "license": "MIT", "dependencies": { "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-bigint": "^7.8.3", @@ -1347,8 +1455,9 @@ }, "node_modules/babel-preset-jest": { "version": "29.5.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.5.0.tgz", + "integrity": "sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg==", "dev": true, - "license": "MIT", "dependencies": { "babel-plugin-jest-hoist": "^29.5.0", "babel-preset-current-node-syntax": "^1.0.0" @@ -1362,13 +1471,15 @@ }, "node_modules/balanced-match": { "version": "1.0.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true }, "node_modules/brace-expansion": { "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, - "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1376,8 +1487,9 @@ }, "node_modules/braces": { "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "dev": true, - "license": "MIT", "dependencies": { "fill-range": "^7.0.1" }, @@ -1387,6 +1499,8 @@ }, "node_modules/browserslist": { "version": "4.21.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", + "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", "dev": true, "funding": [ { @@ -1398,7 +1512,6 @@ "url": "https://tidelift.com/funding/github/npm/browserslist" } ], - "license": "MIT", "dependencies": { "caniuse-lite": "^1.0.30001449", "electron-to-chromium": "^1.4.284", @@ -1414,8 +1527,9 @@ }, "node_modules/bs-logger": { "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", "dev": true, - "license": "MIT", "dependencies": { "fast-json-stable-stringify": "2.x" }, @@ -1425,35 +1539,41 @@ }, "node_modules/bser": { "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", "dev": true, - "license": "Apache-2.0", "dependencies": { "node-int64": "^0.4.0" } }, "node_modules/buffer-from": { "version": "1.1.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true }, "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": { "node": ">=6" } }, "node_modules/camelcase": { "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/caniuse-lite": { "version": "1.0.30001470", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001470.tgz", + "integrity": "sha512-065uNwY6QtHCBOExzbV6m236DDhYCCtPmQUCoQtwkVqzud8v5QPidoMr6CoMkC2nfp6nksjttqWQRRh75LqUmA==", "dev": true, "funding": [ { @@ -1464,13 +1584,13 @@ "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/caniuse-lite" } - ], - "license": "CC-BY-4.0" + ] }, "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": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -1484,14 +1604,17 @@ }, "node_modules/char-regex": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", "dev": true, - "license": "MIT", "engines": { "node": ">=10" } }, "node_modules/ci-info": { "version": "3.8.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", + "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", "dev": true, "funding": [ { @@ -1499,20 +1622,21 @@ "url": "https://github.com/sponsors/sibiraj-s" } ], - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/cjs-module-lexer": { "version": "1.2.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", + "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", + "dev": true }, "node_modules/cliui": { "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, - "license": "ISC", "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", @@ -1522,10 +1646,40 @@ "node": ">=12" } }, + "node_modules/cliui/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==", + "dev": true + }, + "node_modules/cliui/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==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/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==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/co": { "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", "dev": true, - "license": "MIT", "engines": { "iojs": ">= 1.0.0", "node": ">= 0.12.0" @@ -1539,13 +1693,15 @@ }, "node_modules/collect-v8-coverage": { "version": "1.0.1", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", + "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", + "dev": 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==", "dev": true, - "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -1555,95 +1711,43 @@ }, "node_modules/color-name": { "version": "1.1.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, "node_modules/commander": { "version": "10.0.1", "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", "dev": true, + "license": "MIT", "engines": { "node": ">=14" } }, "node_modules/concat-map": { "version": "0.0.1", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true }, "node_modules/convert-source-map": { "version": "2.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/copyfiles": { - "version": "2.4.1", - "dev": true, - "license": "MIT", - "dependencies": { - "glob": "^7.0.5", - "minimatch": "^3.0.3", - "mkdirp": "^1.0.4", - "noms": "0.0.0", - "through2": "^2.0.1", - "untildify": "^4.0.0", - "yargs": "^16.1.0" - }, - "bin": { - "copyfiles": "copyfiles", - "copyup": "copyfiles" - } - }, - "node_modules/copyfiles/node_modules/cliui": { - "version": "7.0.4", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/copyfiles/node_modules/yargs": { - "version": "16.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/copyfiles/node_modules/yargs-parser": { - "version": "20.2.9", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true }, "node_modules/create-require": { "version": "1.1.1", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true }, "node_modules/cross-spawn": { "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, - "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -1655,8 +1759,9 @@ }, "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": { "ms": "2.1.2" }, @@ -1671,50 +1776,57 @@ }, "node_modules/dedent": { "version": "0.7.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", + "dev": true }, "node_modules/deepmerge": { "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/detect-newline": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", "dev": true, - "license": "MIT", "engines": { "node": ">=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": { "node": ">=0.3.1" } }, "node_modules/diff-sequences": { "version": "29.4.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz", + "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==", "dev": true, - "license": "MIT", "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/electron-to-chromium": { "version": "1.4.341", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.341.tgz", + "integrity": "sha512-R4A8VfUBQY9WmAhuqY5tjHRf5fH2AAf6vqitBOE0y6u2PgHgqHSrhZmu78dIX3fVZtjqlwJNX1i2zwC3VpHtQQ==", + "dev": true }, "node_modules/emittery": { "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" }, @@ -1722,39 +1834,38 @@ "url": "https://github.com/sindresorhus/emittery?sponsor=1" } }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "dev": true, - "license": "MIT" - }, "node_modules/error-ex": { "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "dev": true, - "license": "MIT", "dependencies": { "is-arrayish": "^0.2.1" } }, "node_modules/escalade": { "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/escape-string-regexp": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", "dev": true, - "license": "MIT", "engines": { "node": ">=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": { "esparse": "bin/esparse.js", "esvalidate": "bin/esvalidate.js" @@ -1765,8 +1876,9 @@ }, "node_modules/execa": { "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, - "license": "MIT", "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", @@ -1787,6 +1899,8 @@ }, "node_modules/exit": { "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", "dev": true, "engines": { "node": ">= 0.8.0" @@ -1794,8 +1908,9 @@ }, "node_modules/expect": { "version": "29.5.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.5.0.tgz", + "integrity": "sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg==", "dev": true, - "license": "MIT", "dependencies": { "@jest/expect-utils": "^29.5.0", "jest-get-type": "^29.4.3", @@ -1825,8 +1940,9 @@ }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true }, "node_modules/fastq": { "version": "1.17.1", @@ -1839,16 +1955,18 @@ }, "node_modules/fb-watchman": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", "dev": true, - "license": "Apache-2.0", "dependencies": { "bser": "2.1.1" } }, "node_modules/fill-range": { "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "dev": true, - "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -1858,8 +1976,9 @@ }, "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==", "dev": true, - "license": "MIT", "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -1870,13 +1989,16 @@ }, "node_modules/fs.realpath": { "version": "1.0.0", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true }, "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, - "license": "MIT", + "hasInstallScript": true, "optional": true, "os": [ "darwin" @@ -1887,37 +2009,42 @@ }, "node_modules/function-bind": { "version": "1.1.1", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true }, "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": { "node": ">=6.9.0" } }, "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==", "dev": true, - "license": "ISC", "engines": { "node": "6.* || 8.* || >= 10.*" } }, "node_modules/get-package-type": { "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", "dev": true, - "license": "MIT", "engines": { "node": ">=8.0.0" } }, "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": { "node": ">=10" }, @@ -1927,8 +2054,9 @@ }, "node_modules/get-tsconfig": { "version": "4.7.2", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.2.tgz", + "integrity": "sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A==", "dev": true, - "license": "MIT", "dependencies": { "resolve-pkg-maps": "^1.0.0" }, @@ -1938,8 +2066,9 @@ }, "node_modules/glob": { "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dev": true, - "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -1969,21 +2098,24 @@ }, "node_modules/globals": { "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true, - "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/graceful-fs": { "version": "4.2.11", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true }, "node_modules/has": { "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", "dev": true, - "license": "MIT", "dependencies": { "function-bind": "^1.1.1" }, @@ -1993,29 +2125,33 @@ }, "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": { "node": ">=8" } }, "node_modules/html-escaper": { "version": "2.0.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true }, "node_modules/human-signals": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">=10.17.0" } }, "node_modules/import-local": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", "dev": true, - "license": "MIT", "dependencies": { "pkg-dir": "^4.2.0", "resolve-cwd": "^3.0.0" @@ -2032,16 +2168,18 @@ }, "node_modules/imurmurhash": { "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.8.19" } }, "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==", "dev": true, - "license": "ISC", "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -2049,18 +2187,21 @@ }, "node_modules/inherits": { "version": "2.0.4", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true }, "node_modules/is-arrayish": { "version": "0.2.1", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true }, "node_modules/is-core-module": { "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", "dev": true, - "license": "MIT", "dependencies": { "has": "^1.0.3" }, @@ -2077,18 +2218,11 @@ "node": ">=0.10.0" } }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/is-generator-fn": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } @@ -2107,16 +2241,18 @@ }, "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==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.12.0" } }, "node_modules/is-stream": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" }, @@ -2124,19 +2260,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/isarray": { - "version": "0.0.1", - "dev": true, - "license": "MIT" - }, "node_modules/isexe": { "version": "2.0.0", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true }, "node_modules/isomorphic-fetch": { "version": "3.0.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-3.0.0.tgz", + "integrity": "sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA==", "dependencies": { "node-fetch": "^2.6.1", "whatwg-fetch": "^3.4.1" @@ -2144,7 +2277,8 @@ }, "node_modules/isomorphic-fetch/node_modules/node-fetch": { "version": "2.6.11", - "license": "MIT", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz", + "integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==", "dependencies": { "whatwg-url": "^5.0.0" }, @@ -2162,16 +2296,18 @@ }, "node_modules/istanbul-lib-coverage": { "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", "dev": true, - "license": "BSD-3-Clause", "engines": { "node": ">=8" } }, "node_modules/istanbul-lib-instrument": { "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { "@babel/core": "^7.12.3", "@babel/parser": "^7.14.7", @@ -2185,8 +2321,9 @@ }, "node_modules/istanbul-lib-report": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { "istanbul-lib-coverage": "^3.0.0", "make-dir": "^3.0.0", @@ -2198,8 +2335,9 @@ }, "node_modules/istanbul-lib-source-maps": { "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { "debug": "^4.1.1", "istanbul-lib-coverage": "^3.0.0", @@ -2211,8 +2349,9 @@ }, "node_modules/istanbul-reports": { "version": "3.1.5", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", + "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { "html-escaper": "^2.0.0", "istanbul-lib-report": "^3.0.0" @@ -2223,8 +2362,9 @@ }, "node_modules/jest": { "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.5.0.tgz", + "integrity": "sha512-juMg3he2uru1QoXX078zTa7pO85QyB9xajZc6bU+d9yEGwrKX6+vGmJQ3UdVZsvTEUARIdObzH68QItim6OSSQ==", "dev": true, - "license": "MIT", "dependencies": { "@jest/core": "^29.5.0", "@jest/types": "^29.5.0", @@ -2248,8 +2388,9 @@ }, "node_modules/jest-changed-files": { "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.5.0.tgz", + "integrity": "sha512-IFG34IUMUaNBIxjQXF/iu7g6EcdMrGRRxaUSw92I/2g2YC6vCdTltl4nHvt7Ci5nSJwXIkCu8Ka1DKF+X7Z1Ag==", "dev": true, - "license": "MIT", "dependencies": { "execa": "^5.0.0", "p-limit": "^3.1.0" @@ -2260,8 +2401,9 @@ }, "node_modules/jest-circus": { "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.5.0.tgz", + "integrity": "sha512-gq/ongqeQKAplVxqJmbeUOJJKkW3dDNPY8PjhJ5G0lBRvu0e3EWGxGy5cI4LAGA7gV2UHCtWBI4EMXK8c9nQKA==", "dev": true, - "license": "MIT", "dependencies": { "@jest/environment": "^29.5.0", "@jest/expect": "^29.5.0", @@ -2290,8 +2432,9 @@ }, "node_modules/jest-cli": { "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.5.0.tgz", + "integrity": "sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw==", "dev": true, - "license": "MIT", "dependencies": { "@jest/core": "^29.5.0", "@jest/test-result": "^29.5.0", @@ -2323,8 +2466,9 @@ }, "node_modules/jest-config": { "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.5.0.tgz", + "integrity": "sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/core": "^7.11.6", "@jest/test-sequencer": "^29.5.0", @@ -2367,8 +2511,9 @@ }, "node_modules/jest-diff": { "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.5.0.tgz", + "integrity": "sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw==", "dev": true, - "license": "MIT", "dependencies": { "chalk": "^4.0.0", "diff-sequences": "^29.4.3", @@ -2381,8 +2526,9 @@ }, "node_modules/jest-docblock": { "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.4.3.tgz", + "integrity": "sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg==", "dev": true, - "license": "MIT", "dependencies": { "detect-newline": "^3.0.0" }, @@ -2392,8 +2538,9 @@ }, "node_modules/jest-each": { "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.5.0.tgz", + "integrity": "sha512-HM5kIJ1BTnVt+DQZ2ALp3rzXEl+g726csObrW/jpEGl+CDSSQpOJJX2KE/vEg8cxcMXdyEPu6U4QX5eruQv5hA==", "dev": true, - "license": "MIT", "dependencies": { "@jest/types": "^29.5.0", "chalk": "^4.0.0", @@ -2407,8 +2554,9 @@ }, "node_modules/jest-environment-node": { "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.5.0.tgz", + "integrity": "sha512-ExxuIK/+yQ+6PRGaHkKewYtg6hto2uGCgvKdb2nfJfKXgZ17DfXjvbZ+jA1Qt9A8EQSfPnt5FKIfnOO3u1h9qw==", "dev": true, - "license": "MIT", "dependencies": { "@jest/environment": "^29.5.0", "@jest/fake-timers": "^29.5.0", @@ -2423,16 +2571,18 @@ }, "node_modules/jest-get-type": { "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz", + "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==", "dev": true, - "license": "MIT", "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-haste-map": { "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.5.0.tgz", + "integrity": "sha512-IspOPnnBro8YfVYSw6yDRKh/TiCdRngjxeacCps1cQ9cgVN6+10JUcuJ1EabrgYLOATsIAigxA0rLR9x/YlrSA==", "dev": true, - "license": "MIT", "dependencies": { "@jest/types": "^29.5.0", "@types/graceful-fs": "^4.1.3", @@ -2455,8 +2605,9 @@ }, "node_modules/jest-leak-detector": { "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.5.0.tgz", + "integrity": "sha512-u9YdeeVnghBUtpN5mVxjID7KbkKE1QU4f6uUwuxiY0vYRi9BUCLKlPEZfDGR67ofdFmDz9oPAy2G92Ujrntmow==", "dev": true, - "license": "MIT", "dependencies": { "jest-get-type": "^29.4.3", "pretty-format": "^29.5.0" @@ -2467,8 +2618,9 @@ }, "node_modules/jest-matcher-utils": { "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.5.0.tgz", + "integrity": "sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw==", "dev": true, - "license": "MIT", "dependencies": { "chalk": "^4.0.0", "jest-diff": "^29.5.0", @@ -2481,8 +2633,9 @@ }, "node_modules/jest-message-util": { "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.5.0.tgz", + "integrity": "sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/code-frame": "^7.12.13", "@jest/types": "^29.5.0", @@ -2500,8 +2653,9 @@ }, "node_modules/jest-mock": { "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.5.0.tgz", + "integrity": "sha512-GqOzvdWDE4fAV2bWQLQCkujxYWL7RxjCnj71b5VhDAGOevB3qj3Ovg26A5NI84ZpODxyzaozXLOh2NCgkbvyaw==", "dev": true, - "license": "MIT", "dependencies": { "@jest/types": "^29.5.0", "@types/node": "*", @@ -2513,8 +2667,9 @@ }, "node_modules/jest-pnp-resolver": { "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" }, @@ -2529,16 +2684,18 @@ }, "node_modules/jest-regex-util": { "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.4.3.tgz", + "integrity": "sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg==", "dev": true, - "license": "MIT", "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-resolve": { "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.5.0.tgz", + "integrity": "sha512-1TzxJ37FQq7J10jPtQjcc+MkCkE3GBpBecsSUWJ0qZNJpmg6m0D9/7II03yJulm3H/fvVjgqLh/k2eYg+ui52w==", "dev": true, - "license": "MIT", "dependencies": { "chalk": "^4.0.0", "graceful-fs": "^4.2.9", @@ -2556,8 +2713,9 @@ }, "node_modules/jest-resolve-dependencies": { "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.5.0.tgz", + "integrity": "sha512-sjV3GFr0hDJMBpYeUuGduP+YeCRbd7S/ck6IvL3kQ9cpySYKqcqhdLLC2rFwrcL7tz5vYibomBrsFYWkIGGjOg==", "dev": true, - "license": "MIT", "dependencies": { "jest-regex-util": "^29.4.3", "jest-snapshot": "^29.5.0" @@ -2568,8 +2726,9 @@ }, "node_modules/jest-runner": { "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.5.0.tgz", + "integrity": "sha512-m7b6ypERhFghJsslMLhydaXBiLf7+jXy8FwGRHO3BGV1mcQpPbwiqiKUR2zU2NJuNeMenJmlFZCsIqzJCTeGLQ==", "dev": true, - "license": "MIT", "dependencies": { "@jest/console": "^29.5.0", "@jest/environment": "^29.5.0", @@ -2599,8 +2758,9 @@ }, "node_modules/jest-runtime": { "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.5.0.tgz", + "integrity": "sha512-1Hr6Hh7bAgXQP+pln3homOiEZtCDZFqwmle7Ew2j8OlbkIu6uE3Y/etJQG8MLQs3Zy90xrp2C0BRrtPHG4zryw==", "dev": true, - "license": "MIT", "dependencies": { "@jest/environment": "^29.5.0", "@jest/fake-timers": "^29.5.0", @@ -2631,8 +2791,9 @@ }, "node_modules/jest-snapshot": { "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.5.0.tgz", + "integrity": "sha512-x7Wolra5V0tt3wRs3/ts3S6ciSQVypgGQlJpz2rsdQYoUKxMxPNaoHMGJN6qAuPJqS+2iQ1ZUn5kl7HCyls84g==", "dev": true, - "license": "MIT", "dependencies": { "@babel/core": "^7.11.6", "@babel/generator": "^7.7.2", @@ -2664,8 +2825,9 @@ }, "node_modules/jest-snapshot/node_modules/lru-cache": { "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, - "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -2675,8 +2837,9 @@ }, "node_modules/jest-snapshot/node_modules/semver": { "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "dev": true, - "license": "ISC", "dependencies": { "lru-cache": "^6.0.0" }, @@ -2689,13 +2852,15 @@ }, "node_modules/jest-snapshot/node_modules/yallist": { "version": "4.0.0", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true }, "node_modules/jest-util": { "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", "dev": true, - "license": "MIT", "dependencies": { "@jest/types": "^29.5.0", "@types/node": "*", @@ -2710,8 +2875,9 @@ }, "node_modules/jest-validate": { "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.5.0.tgz", + "integrity": "sha512-pC26etNIi+y3HV8A+tUGr/lph9B18GnzSRAkPaaZJIE1eFdiYm6/CewuiJQ8/RlfHd1u/8Ioi8/sJ+CmbA+zAQ==", "dev": true, - "license": "MIT", "dependencies": { "@jest/types": "^29.5.0", "camelcase": "^6.2.0", @@ -2726,8 +2892,9 @@ }, "node_modules/jest-validate/node_modules/camelcase": { "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true, - "license": "MIT", "engines": { "node": ">=10" }, @@ -2737,8 +2904,9 @@ }, "node_modules/jest-watcher": { "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.5.0.tgz", + "integrity": "sha512-KmTojKcapuqYrKDpRwfqcQ3zjMlwu27SYext9pt4GlF5FUgB+7XE1mcCnSm6a4uUpFyQIkb6ZhzZvHl+jiBCiA==", "dev": true, - "license": "MIT", "dependencies": { "@jest/test-result": "^29.5.0", "@jest/types": "^29.5.0", @@ -2755,8 +2923,9 @@ }, "node_modules/jest-worker": { "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.5.0.tgz", + "integrity": "sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*", "jest-util": "^29.5.0", @@ -2769,8 +2938,9 @@ }, "node_modules/jest-worker/node_modules/supports-color": { "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, - "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -2783,13 +2953,15 @@ }, "node_modules/js-tokens": { "version": "4.0.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true }, "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": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -2800,8 +2972,9 @@ }, "node_modules/jsesc": { "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "dev": true, - "license": "MIT", "bin": { "jsesc": "bin/jsesc" }, @@ -2811,13 +2984,15 @@ }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", - "dev": true, - "license": "MIT" + "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 }, "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": { "json5": "lib/cli.js" }, @@ -2827,29 +3002,33 @@ }, "node_modules/kleur": { "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/leven": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/lines-and-columns": { "version": "1.2.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true }, "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==", "dev": true, - "license": "MIT", "dependencies": { "p-locate": "^4.1.0" }, @@ -2859,8 +3038,9 @@ }, "node_modules/lodash.memoize": { "version": "4.1.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true }, "node_modules/lodash.merge": { "version": "4.6.2", @@ -2869,16 +3049,18 @@ }, "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": { "yallist": "^3.0.2" } }, "node_modules/make-dir": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", "dev": true, - "license": "MIT", "dependencies": { "semver": "^6.0.0" }, @@ -2891,21 +3073,24 @@ }, "node_modules/make-error": { "version": "1.3.6", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true }, "node_modules/makeerror": { "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { "tmpl": "1.0.5" } }, "node_modules/merge-stream": { "version": "2.0.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true }, "node_modules/merge2": { "version": "1.4.1", @@ -2918,8 +3103,9 @@ }, "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": { "braces": "^3.0.2", "picomatch": "^2.3.1" @@ -2928,32 +3114,41 @@ "node": ">=8.6" } }, - "node_modules/mime": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/mime/-/mime-4.0.4.tgz", - "integrity": "sha512-v8yqInVjhXyqP6+Kw4fV3ZzeMRqEW6FotRsKXjRS5VMTNIuXsdRoAvklpoRgSqXm6o9VNH4/C0mgedko9DdLsQ==", - "funding": [ - "https://github.com/sponsors/broofa" - ], - "bin": { - "mime": "bin/cli.js" + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" }, "engines": { - "node": ">=16" + "node": ">= 0.6" } }, "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": { "node": ">=6" } }, "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": { "brace-expansion": "^1.1.7" }, @@ -2962,57 +3157,58 @@ } }, "node_modules/mkdirp": { - "version": "1.0.4", + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-2.1.6.tgz", + "integrity": "sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A==", "dev": true, - "license": "MIT", "bin": { - "mkdirp": "bin/cmd.js" + "mkdirp": "dist/cjs/src/bin.js" }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/ms": { "version": "2.1.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true }, "node_modules/natural-compare": { "version": "1.4.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true }, "node_modules/node-int64": { "version": "0.4.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true }, "node_modules/node-releases": { "version": "2.0.10", - "dev": true, - "license": "MIT" - }, - "node_modules/noms": { - "version": "0.0.0", - "dev": true, - "license": "ISC", - "dependencies": { - "inherits": "^2.0.1", - "readable-stream": "~1.0.31" - } + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", + "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==", + "dev": true }, "node_modules/normalize-path": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/npm-run-path": { "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, - "license": "MIT", "dependencies": { "path-key": "^3.0.0" }, @@ -3022,16 +3218,18 @@ }, "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==", "dev": true, - "license": "ISC", "dependencies": { "wrappy": "1" } }, "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": { "mimic-fn": "^2.1.0" }, @@ -3044,8 +3242,9 @@ }, "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": { "yocto-queue": "^0.1.0" }, @@ -3058,8 +3257,9 @@ }, "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==", "dev": true, - "license": "MIT", "dependencies": { "p-limit": "^2.2.0" }, @@ -3069,8 +3269,9 @@ }, "node_modules/p-locate/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==", "dev": true, - "license": "MIT", "dependencies": { "p-try": "^2.0.0" }, @@ -3083,16 +3284,18 @@ }, "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==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } }, "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": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -3114,38 +3317,43 @@ }, "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==", "dev": true, - "license": "MIT", "engines": { "node": ">=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": { "node": ">=0.10.0" } }, "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==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/path-parse": { "version": "1.0.7", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true }, "node_modules/peggy": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/peggy/-/peggy-3.0.2.tgz", "integrity": "sha512-n7chtCbEoGYRwZZ0i/O3t1cPr6o+d9Xx4Zwy2LYfzv0vjchMBU0tO+qYYyvZloBPcgRgzYvALzGWHe609JjEpg==", "dev": true, + "license": "MIT", "dependencies": { "commander": "^10.0.0", "source-map-generator": "0.8.0" @@ -3159,13 +3367,15 @@ }, "node_modules/picocolors": { "version": "1.0.0", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true }, "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": { "node": ">=8.6" }, @@ -3175,16 +3385,18 @@ }, "node_modules/pirates": { "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", "dev": true, - "license": "MIT", "engines": { "node": ">= 6" } }, "node_modules/pkg-dir": { "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", "dev": true, - "license": "MIT", "dependencies": { "find-up": "^4.0.0" }, @@ -3194,8 +3406,9 @@ }, "node_modules/prettier": { "version": "3.2.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", + "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", "dev": true, - "license": "MIT", "bin": { "prettier": "bin/prettier.cjs" }, @@ -3208,8 +3421,9 @@ }, "node_modules/pretty-format": { "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", "dev": true, - "license": "MIT", "dependencies": { "@jest/schemas": "^29.4.3", "ansi-styles": "^5.0.0", @@ -3221,8 +3435,9 @@ }, "node_modules/pretty-format/node_modules/ansi-styles": { "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, - "license": "MIT", "engines": { "node": ">=10" }, @@ -3230,15 +3445,11 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "dev": true, - "license": "MIT" - }, "node_modules/prompts": { "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", "dev": true, - "license": "MIT", "dependencies": { "kleur": "^3.0.3", "sisteransi": "^1.0.5" @@ -3249,6 +3460,8 @@ }, "node_modules/pure-rand": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.1.tgz", + "integrity": "sha512-t+x1zEHDjBwkDGY5v5ApnZ/utcd4XYDiJsaQQoptTXgUXX95sDg1elCdJghzicm7n2mbCBJ3uYWr6M22SO19rg==", "dev": true, "funding": [ { @@ -3259,8 +3472,7 @@ "type": "opencollective", "url": "https://opencollective.com/fast-check" } - ], - "license": "MIT" + ] }, "node_modules/queue-microtask": { "version": "1.2.3", @@ -3284,32 +3496,24 @@ }, "node_modules/react-is": { "version": "18.2.0", - "dev": true, - "license": "MIT" - }, - "node_modules/readable-stream": { - "version": "1.0.34", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true }, "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==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/resolve": { "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", "dev": true, - "license": "MIT", "dependencies": { "is-core-module": "^2.9.0", "path-parse": "^1.0.7", @@ -3324,8 +3528,9 @@ }, "node_modules/resolve-cwd": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", "dev": true, - "license": "MIT", "dependencies": { "resolve-from": "^5.0.0" }, @@ -3335,24 +3540,27 @@ }, "node_modules/resolve-from": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/resolve-pkg-maps": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", "dev": true, - "license": "MIT", "funding": { "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" } }, "node_modules/resolve.exports": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", + "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", "dev": true, - "license": "MIT", "engines": { "node": ">=10" } @@ -3390,23 +3598,20 @@ "queue-microtask": "^1.2.2" } }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "dev": true, - "license": "MIT" - }, "node_modules/semver": { "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true, - "license": "ISC", "bin": { "semver": "bin/semver.js" } }, "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==", "dev": true, - "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" }, @@ -3416,34 +3621,39 @@ }, "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==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/signal-exit": { "version": "3.0.7", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true }, "node_modules/sisteransi": { "version": "1.0.5", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true }, "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": { "node": ">=8" } }, "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": { "node": ">=0.10.0" } @@ -3459,8 +3669,9 @@ }, "node_modules/source-map-support": { "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", "dev": true, - "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -3468,13 +3679,15 @@ }, "node_modules/sprintf-js": { "version": "1.0.3", - "dev": true, - "license": "BSD-3-Clause" + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true }, "node_modules/stack-utils": { "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", "dev": true, - "license": "MIT", "dependencies": { "escape-string-regexp": "^2.0.0" }, @@ -3482,15 +3695,11 @@ "node": ">=10" } }, - "node_modules/string_decoder": { - "version": "0.10.31", - "dev": true, - "license": "MIT" - }, "node_modules/string-length": { "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", "dev": true, - "license": "MIT", "dependencies": { "char-regex": "^1.0.2", "strip-ansi": "^6.0.0" @@ -3499,23 +3708,11 @@ "node": ">=10" } }, - "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" - } - }, "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==", "dev": true, - "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -3525,24 +3722,27 @@ }, "node_modules/strip-bom": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/strip-final-newline": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/strip-json-comments": { "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" }, @@ -3552,8 +3752,9 @@ }, "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": { "has-flag": "^4.0.0" }, @@ -3563,8 +3764,9 @@ }, "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==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -3574,8 +3776,9 @@ }, "node_modules/test-exclude": { "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", "dev": true, - "license": "ISC", "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", @@ -3585,59 +3788,26 @@ "node": ">=8" } }, - "node_modules/through2": { - "version": "2.0.5", - "dev": true, - "license": "MIT", - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, - "node_modules/through2/node_modules/isarray": { - "version": "1.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/through2/node_modules/readable-stream": { - "version": "2.3.8", - "dev": true, - "license": "MIT", - "dependencies": { - "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/through2/node_modules/string_decoder": { - "version": "1.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/tmpl": { "version": "1.0.5", - "dev": true, - "license": "BSD-3-Clause" + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true }, "node_modules/to-fast-properties": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", "dev": true, - "license": "MIT", "engines": { "node": ">=4" } }, "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==", "dev": true, - "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -3647,12 +3817,14 @@ }, "node_modules/tr46": { "version": "0.0.3", - "license": "MIT" + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, "node_modules/ts-jest": { "version": "29.0.5", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.5.tgz", + "integrity": "sha512-PL3UciSgIpQ7f6XjVOmbi96vmDHUqAyqDr8YxzopDqX3kfgYtX1cuNeBjP+L9sFXi6nzsGGA6R3fP3DDDJyrxA==", "dev": true, - "license": "MIT", "dependencies": { "bs-logger": "0.x", "fast-json-stable-stringify": "2.x", @@ -3693,8 +3865,9 @@ }, "node_modules/ts-jest/node_modules/lru-cache": { "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, - "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -3704,8 +3877,9 @@ }, "node_modules/ts-jest/node_modules/semver": { "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "dev": true, - "license": "ISC", "dependencies": { "lru-cache": "^6.0.0" }, @@ -3718,13 +3892,15 @@ }, "node_modules/ts-jest/node_modules/yallist": { "version": "4.0.0", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true }, "node_modules/ts-matches": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/ts-matches/-/ts-matches-5.5.1.tgz", - "integrity": "sha512-UFYaKgfqlg9FROK7bdpYqFwG1CJvP4kOJdjXuWoqxo9jCmANoDw1GxkSCpJgoTeIiSTaTH5Qr1klSspb8c+ydg==" + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ts-matches/-/ts-matches-6.1.0.tgz", + "integrity": "sha512-01qvbIpOiKdbzzXDH84JeHunvCwBGFdZw94jS6kOGLSN5ms+1nBZtfe8WSuYMIPb1xPA+qyAiVgznFi2VCQ6UQ==", + "license": "MIT" }, "node_modules/ts-morph": { "version": "18.0.0", @@ -3738,8 +3914,9 @@ }, "node_modules/ts-node": { "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", "dev": true, - "license": "MIT", "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -3811,8 +3988,9 @@ }, "node_modules/tsx": { "version": "4.7.1", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.7.1.tgz", + "integrity": "sha512-8d6VuibXHtlN5E3zFkgY8u4DX7Y3Z27zvvPKVmLon/D4AjuKzarkUBTLDBgj9iTQ0hg5xM7c/mYiRVM+HETf0g==", "dev": true, - "license": "MIT", "dependencies": { "esbuild": "~0.19.10", "get-tsconfig": "^4.7.2" @@ -3827,13 +4005,62 @@ "fsevents": "~2.3.3" } }, - "node_modules/tsx/node_modules/@esbuild/darwin-arm64": { + "node_modules/tsx/node_modules/@esbuild/android-arm": { "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.12.tgz", + "integrity": "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz", + "integrity": "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.12.tgz", + "integrity": "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/darwin-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz", + "integrity": "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -3842,11 +4069,300 @@ "node": ">=12" } }, + "node_modules/tsx/node_modules/@esbuild/darwin-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz", + "integrity": "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/freebsd-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz", + "integrity": "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/freebsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz", + "integrity": "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-arm": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz", + "integrity": "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz", + "integrity": "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-ia32": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz", + "integrity": "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-loong64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz", + "integrity": "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-mips64el": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz", + "integrity": "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-ppc64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz", + "integrity": "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-riscv64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz", + "integrity": "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-s390x": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz", + "integrity": "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz", + "integrity": "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/netbsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz", + "integrity": "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/openbsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz", + "integrity": "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/sunos-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz", + "integrity": "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz", + "integrity": "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-ia32": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz", + "integrity": "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz", + "integrity": "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/tsx/node_modules/esbuild": { "version": "0.19.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz", + "integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==", "dev": true, "hasInstallScript": true, - "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, @@ -3881,16 +4397,18 @@ }, "node_modules/type-detect": { "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", "dev": true, - "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/type-fest": { "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", "dev": true, - "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -3900,8 +4418,9 @@ }, "node_modules/typescript": { "version": "5.0.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", + "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", "dev": true, - "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -3910,16 +4429,10 @@ "node": ">=12.20" } }, - "node_modules/untildify": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/update-browserslist-db": { "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", "dev": true, "funding": [ { @@ -3931,7 +4444,6 @@ "url": "https://tidelift.com/funding/github/npm/browserslist" } ], - "license": "MIT", "dependencies": { "escalade": "^3.1.1", "picocolors": "^1.0.0" @@ -3943,20 +4455,17 @@ "browserslist": ">= 4.21.0" } }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "dev": true, - "license": "MIT" - }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", - "dev": true, - "license": "MIT" + "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 }, "node_modules/v8-to-istanbul": { "version": "9.1.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz", + "integrity": "sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==", "dev": true, - "license": "ISC", "dependencies": { "@jridgewell/trace-mapping": "^0.3.12", "@types/istanbul-lib-coverage": "^2.0.1", @@ -3968,28 +4477,33 @@ }, "node_modules/v8-to-istanbul/node_modules/convert-source-map": { "version": "1.9.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true }, "node_modules/walker": { "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", "dev": true, - "license": "Apache-2.0", "dependencies": { "makeerror": "1.0.12" } }, "node_modules/webidl-conversions": { "version": "3.0.1", - "license": "BSD-2-Clause" + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, "node_modules/whatwg-fetch": { "version": "3.6.2", - "license": "MIT" + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz", + "integrity": "sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==" }, "node_modules/whatwg-url": { "version": "5.0.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" @@ -3997,8 +4511,9 @@ }, "node_modules/which": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, - "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -4011,8 +4526,9 @@ }, "node_modules/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==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -4025,15 +4541,46 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "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==", + "dev": true + }, + "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==", + "dev": true, + "engines": { + "node": ">=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==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/wrappy": { "version": "1.0.2", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true }, "node_modules/write-file-atomic": { "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", "dev": true, - "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4", "signal-exit": "^3.0.7" @@ -4042,39 +4589,34 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/xtend": { - "version": "4.0.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.4" - } - }, "node_modules/y18n": { "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true, - "license": "ISC", "engines": { "node": ">=10" } }, "node_modules/yallist": { "version": "3.1.1", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true }, "node_modules/yaml": { "version": "2.2.2", - "dev": true, - "license": "ISC", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.2.tgz", + "integrity": "sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA==", "engines": { "node": ">= 14" } }, "node_modules/yargs": { "version": "17.7.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", + "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", "dev": true, - "license": "MIT", "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", @@ -4090,24 +4632,56 @@ }, "node_modules/yargs-parser": { "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true, - "license": "ISC", "engines": { "node": ">=12" } }, + "node_modules/yargs/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==", + "dev": true + }, + "node_modules/yargs/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==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/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==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=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": { "node": ">=6" } }, "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": { "node": ">=10" }, diff --git a/sdk/base/package.json b/sdk/base/package.json new file mode 100644 index 000000000..4cc2fc7ca --- /dev/null +++ b/sdk/base/package.json @@ -0,0 +1,52 @@ +{ + "name": "@start9labs/start-sdk-base", + "main": "./index.js", + "types": "./index.d.ts", + "sideEffects": true, + "scripts": { + "peggy": "peggy --allowed-start-rules \"*\" --plugin ./node_modules/ts-pegjs/dist/tspegjs -o lib/exver/exver.ts lib/exver/exver.pegjs", + "test": "jest -c ./jest.config.js --coverage", + "buildOutput": "npx prettier --write \"**/*.ts\"", + "check": "tsc --noEmit", + "tsc": "tsc" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/Start9Labs/start-sdk.git" + }, + "author": "Start9 Labs", + "license": "MIT", + "bugs": { + "url": "https://github.com/Start9Labs/start-sdk/issues" + }, + "homepage": "https://github.com/Start9Labs/start-sdk#readme", + "dependencies": { + "@iarna/toml": "^2.2.5", + "@noble/curves": "^1.4.0", + "@noble/hashes": "^1.4.0", + "isomorphic-fetch": "^3.0.0", + "lodash.merge": "^4.6.2", + "mime-types": "^2.1.35", + "ts-matches": "^6.1.0", + "yaml": "^2.2.2" + }, + "prettier": { + "trailingComma": "all", + "tabWidth": 2, + "semi": false, + "singleQuote": false + }, + "devDependencies": { + "@types/jest": "^29.4.0", + "@types/lodash.merge": "^4.6.2", + "@types/mime-types": "^2.1.4", + "jest": "^29.4.3", + "peggy": "^3.0.2", + "prettier": "^3.2.5", + "ts-jest": "^29.0.5", + "ts-node": "^10.9.1", + "ts-pegjs": "^4.2.1", + "tsx": "^4.7.1", + "typescript": "^5.0.4" + } +} diff --git a/sdk/tsconfig-base.json b/sdk/base/tsconfig.json similarity index 78% rename from sdk/tsconfig-base.json rename to sdk/base/tsconfig.json index cc14a817c..cd73f3164 100644 --- a/sdk/tsconfig-base.json +++ b/sdk/base/tsconfig.json @@ -1,18 +1,18 @@ { "compilerOptions": { - "module": "esnext", "strict": true, - "outDir": "dist", "preserveConstEnums": true, "sourceMap": true, - "target": "es2017", "pretty": true, "declaration": true, "noImplicitAny": true, "esModuleInterop": true, "types": ["node", "jest"], "moduleResolution": "node", - "skipLibCheck": true + "skipLibCheck": true, + "module": "commonjs", + "outDir": "../baseDist", + "target": "es2018" }, "include": ["lib/**/*"], "exclude": ["lib/**/*.spec.ts", "lib/**/*.gen.ts", "list", "node_modules"] diff --git a/sdk/lib/Dependency.ts b/sdk/lib/Dependency.ts deleted file mode 100644 index 067ed653e..000000000 --- a/sdk/lib/Dependency.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { VersionRange } from "./exver" - -export class Dependency { - constructor( - readonly data: - | { - type: "running" - versionRange: VersionRange - registryUrl: string - healthChecks: string[] - } - | { - type: "exists" - versionRange: VersionRange - registryUrl: string - }, - ) {} -} diff --git a/sdk/lib/StartSdk.ts b/sdk/lib/StartSdk.ts deleted file mode 100644 index 658597bc2..000000000 --- a/sdk/lib/StartSdk.ts +++ /dev/null @@ -1,804 +0,0 @@ -import { RequiredDefault, Value } from "./config/builder/value" -import { Config, ExtractConfigType, LazyBuild } from "./config/builder/config" -import { - DefaultString, - ListValueSpecText, - Pattern, - RandomString, - UniqueBy, - ValueSpecDatetime, - ValueSpecText, -} from "./config/configTypes" -import { Variants } from "./config/builder/variants" -import { CreatedAction, createAction } from "./actions/createAction" -import { - ActionMetadata, - Effects, - ActionResult, - BackupOptions, - DeepPartial, - MaybePromise, - ServiceInterfaceId, - PackageId, -} from "./types" -import * as patterns from "./util/patterns" -import { DependencyConfig, Update } from "./dependencies/DependencyConfig" -import { BackupSet, Backups } from "./backup/Backups" -import { smtpConfig } from "./config/configConstants" -import { Daemons } from "./mainFn/Daemons" -import { healthCheck, HealthCheckParams } from "./health/HealthCheck" -import { checkPortListening } from "./health/checkFns/checkPortListening" -import { checkWebUrl, runHealthScript } from "./health/checkFns" -import { List } from "./config/builder/list" -import { Install, InstallFn } from "./inits/setupInstall" -import { setupActions } from "./actions/setupActions" -import { setupDependencyConfig } from "./dependencies/setupDependencyConfig" -import { SetupBackupsParams, setupBackups } from "./backup/setupBackups" -import { setupInit } from "./inits/setupInit" -import { Uninstall, UninstallFn, setupUninstall } from "./inits/setupUninstall" -import { setupMain } from "./mainFn" -import { defaultTrigger } from "./trigger/defaultTrigger" -import { changeOnFirstSuccess, cooldownTrigger } from "./trigger" -import setupConfig, { - DependenciesReceipt, - Read, - Save, -} from "./config/setupConfig" -import { - InterfacesReceipt, - SetInterfaces, - setupInterfaces, -} from "./interfaces/setupInterfaces" -import { successFailure } from "./trigger/successFailure" -import { HealthReceipt } from "./health/HealthReceipt" -import { MultiHost, Scheme } from "./interfaces/Host" -import { ServiceInterfaceBuilder } from "./interfaces/ServiceInterfaceBuilder" -import { GetSystemSmtp } from "./util/GetSystemSmtp" -import nullIfEmpty from "./util/nullIfEmpty" -import { - GetServiceInterface, - getServiceInterface, -} from "./util/getServiceInterface" -import { getServiceInterfaces } from "./util/getServiceInterfaces" -import { getStore } from "./store/getStore" -import { CommandOptions, MountOptions, SubContainer } from "./util/SubContainer" -import { splitCommand } from "./util/splitCommand" -import { Mounts } from "./mainFn/Mounts" -import { Dependency } from "./Dependency" -import * as T from "./types" -import { testTypeVersion, ValidateExVer } from "./exver" -import { ExposedStorePaths } from "./store/setupExposeStore" -import { PathBuilder, extractJsonPath, pathBuilder } from "./store/PathBuilder" -import { - CheckDependencies, - checkDependencies, -} from "./dependencies/dependencies" -import { health } from "." -import { GetSslCertificate } from "./util/GetSslCertificate" -import { VersionGraph } from "./version" - -export const SDKVersion = testTypeVersion("0.3.6") - -// prettier-ignore -type AnyNeverCond = - T extends [] ? Else : - T extends [never, ...Array] ? Then : - T extends [any, ...infer U] ? AnyNeverCond : - never - -export type ServiceInterfaceType = "ui" | "p2p" | "api" -export type MainEffects = Effects & { - _type: "main" - clearCallbacks: () => Promise -} -export type Signals = NodeJS.Signals -export const SIGTERM: Signals = "SIGTERM" -export const SIGKILL: Signals = "SIGKILL" -export const NO_TIMEOUT = -1 - -function removeCallbackTypes(effects: E) { - return (t: T) => { - if ("_type" in effects && effects._type === "main") { - return t as E extends MainEffects ? T : Omit - } else { - if ("const" in t) { - delete t.const - } - if ("watch" in t) { - delete t.watch - } - return t as E extends MainEffects ? T : Omit - } - } -} - -export class StartSdk { - private constructor(readonly manifest: Manifest) {} - static of() { - return new StartSdk(null as never) - } - withManifest(manifest: Manifest) { - return new StartSdk(manifest) - } - withStore>() { - return new StartSdk(this.manifest) - } - - build(isReady: AnyNeverCond<[Manifest, Store], "Build not ready", true>) { - type DependencyType = { - [K in keyof { - [K in keyof Manifest["dependencies"]]: Manifest["dependencies"][K]["optional"] extends false - ? K - : never - }]: Dependency - } & { - [K in keyof { - [K in keyof Manifest["dependencies"]]: Manifest["dependencies"][K]["optional"] extends true - ? K - : never - }]?: Dependency - } - - type NestedEffects = "subcontainer" | "store" - type InterfaceEffects = - | "getServiceInterface" - | "listServiceInterfaces" - | "exportServiceInterface" - | "clearServiceInterfaces" - | "bind" - | "getHostInfo" - | "getPrimaryUrl" - type MainUsedEffects = "setMainStatus" | "setHealth" - type AlreadyExposed = "getSslCertificate" | "getSystemSmtp" - - // prettier-ignore - type StartSdkEffectWrapper = { - [K in keyof Omit]: (effects: Effects, ...args: Parameters) => ReturnType - } - const startSdkEffectWrapper: StartSdkEffectWrapper = { - executeAction: (effects, ...args) => effects.executeAction(...args), - exportAction: (effects, ...args) => effects.exportAction(...args), - clearActions: (effects, ...args) => effects.clearActions(...args), - getConfigured: (effects, ...args) => effects.getConfigured(...args), - setConfigured: (effects, ...args) => effects.setConfigured(...args), - restart: (effects, ...args) => effects.restart(...args), - setDependencies: (effects, ...args) => effects.setDependencies(...args), - checkDependencies: (effects, ...args) => - effects.checkDependencies(...args), - mount: (effects, ...args) => effects.mount(...args), - getInstalledPackages: (effects, ...args) => - effects.getInstalledPackages(...args), - exposeForDependents: (effects, ...args) => - effects.exposeForDependents(...args), - getServicePortForward: (effects, ...args) => - effects.getServicePortForward(...args), - clearBindings: (effects, ...args) => effects.clearBindings(...args), - getContainerIp: (effects, ...args) => effects.getContainerIp(...args), - getSslKey: (effects, ...args) => effects.getSslKey(...args), - setDataVersion: (effects, ...args) => effects.setDataVersion(...args), - getDataVersion: (effects, ...args) => effects.getDataVersion(...args), - shutdown: (effects, ...args) => effects.shutdown(...args), - getDependencies: (effects, ...args) => effects.getDependencies(...args), - } - - return { - ...startSdkEffectWrapper, - - checkDependencies: checkDependencies as < - DependencyId extends keyof Manifest["dependencies"] & - PackageId = keyof Manifest["dependencies"] & PackageId, - >( - effects: Effects, - packageIds?: DependencyId[], - ) => Promise>, - serviceInterface: { - getOwn: (effects: E, id: ServiceInterfaceId) => - removeCallbackTypes(effects)( - getServiceInterface(effects, { - id, - }), - ), - get: ( - effects: E, - opts: { id: ServiceInterfaceId; packageId: PackageId }, - ) => - removeCallbackTypes(effects)(getServiceInterface(effects, opts)), - getAllOwn: (effects: E) => - removeCallbackTypes(effects)(getServiceInterfaces(effects, {})), - getAll: ( - effects: E, - opts: { packageId: PackageId }, - ) => - removeCallbackTypes(effects)(getServiceInterfaces(effects, opts)), - }, - - store: { - get: ( - effects: E, - packageId: string, - path: PathBuilder, - ) => - removeCallbackTypes(effects)( - getStore(effects, path, { - packageId, - }), - ), - getOwn: ( - effects: E, - path: PathBuilder, - ) => - removeCallbackTypes(effects)( - getStore(effects, path), - ), - setOwn: >( - effects: E, - path: Path, - value: Path extends PathBuilder ? Value : never, - ) => - effects.store.set({ - value, - path: extractJsonPath(path), - }), - }, - - host: { - // static: (effects: Effects, id: string) => - // new StaticHost({ id, effects }), - // single: (effects: Effects, id: string) => - // new SingleHost({ id, effects }), - multi: (effects: Effects, id: string) => new MultiHost({ id, effects }), - }, - nullIfEmpty, - runCommand: async ( - effects: Effects, - image: { - id: keyof Manifest["images"] & T.ImageId - sharedRun?: boolean - }, - command: T.CommandType, - options: CommandOptions & { - mounts?: { path: string; options: MountOptions }[] - }, - ): Promise<{ stdout: string | Buffer; stderr: string | Buffer }> => { - return runCommand(effects, image, command, options) - }, - - createAction: < - ConfigType extends - | Record - | Config - | Config, - Type extends Record = ExtractConfigType, - >( - id: string, - metaData: Omit & { - input: Config | Config - }, - fn: (options: { - effects: Effects - input: Type - }) => Promise, - ) => { - const { input, ...rest } = metaData - return createAction( - id, - rest, - fn, - input, - ) - }, - configConstants: { smtpConfig }, - createInterface: ( - effects: Effects, - options: { - name: string - id: string - description: string - hasPrimary: boolean - type: ServiceInterfaceType - username: null | string - path: string - search: Record - schemeOverride: { ssl: Scheme; noSsl: Scheme } | null - masked: boolean - }, - ) => new ServiceInterfaceBuilder({ ...options, effects }), - getSystemSmtp: (effects: E) => - removeCallbackTypes(effects)(new GetSystemSmtp(effects)), - - getSslCerificate: ( - effects: E, - hostnames: string[], - algorithm?: T.Algorithm, - ) => - removeCallbackTypes(effects)( - new GetSslCertificate(effects, hostnames, algorithm), - ), - - createDynamicAction: < - ConfigType extends - | Record - | Config - | Config, - Type extends Record = ExtractConfigType, - >( - id: string, - metaData: (options: { - effects: Effects - }) => MaybePromise>, - fn: (options: { - effects: Effects - input: Type - }) => Promise, - input: Config | Config, - ) => { - return createAction( - id, - metaData, - fn, - input, - ) - }, - HealthCheck: { - of(o: HealthCheckParams) { - return healthCheck(o) - }, - }, - Dependency: { - of(data: Dependency["data"]) { - return new Dependency({ ...data }) - }, - }, - healthCheck: { - checkPortListening, - checkWebUrl, - runHealthScript, - }, - patterns, - setupActions: (...createdActions: CreatedAction[]) => - setupActions(...createdActions), - setupBackups: (...args: SetupBackupsParams) => - setupBackups(this.manifest, ...args), - setupConfig: < - ConfigType extends Config | Config, - Type extends Record = ExtractConfigType, - >( - spec: ConfigType, - write: Save, - read: Read, - ) => setupConfig(spec, write, read), - setupConfigRead: < - ConfigSpec extends - | Config, any> - | Config, never>, - >( - _configSpec: ConfigSpec, - fn: Read, - ) => fn, - setupConfigSave: < - ConfigSpec extends - | Config, any> - | Config, never>, - >( - _configSpec: ConfigSpec, - fn: Save, - ) => fn, - setupDependencyConfig: >( - config: Config | Config, - autoConfigs: { - [K in keyof Manifest["dependencies"]]: DependencyConfig< - Manifest, - Store, - Input, - any - > | null - }, - ) => setupDependencyConfig(config, autoConfigs), - setupDependencies: >( - fn: (options: { - effects: Effects - input: Input | null - }) => Promise, - ) => { - return async (options: { effects: Effects; input: Input }) => { - const dependencyType = await fn(options) - return await options.effects.setDependencies({ - dependencies: Object.entries(dependencyType).map( - ([ - id, - { - data: { versionRange, ...x }, - }, - ]) => ({ - id, - ...x, - ...(x.type === "running" - ? { - kind: "running", - healthChecks: x.healthChecks, - } - : { - kind: "exists", - }), - versionRange: versionRange.toString(), - }), - ), - }) - } - }, - setupInit: ( - versions: VersionGraph, - install: Install, - uninstall: Uninstall, - setInterfaces: SetInterfaces, - setDependencies: (options: { - effects: Effects - input: any - }) => Promise, - exposedStore: ExposedStorePaths, - ) => - setupInit( - versions, - install, - uninstall, - setInterfaces, - setDependencies, - exposedStore, - ), - setupInstall: (fn: InstallFn) => Install.of(fn), - setupInterfaces: < - ConfigInput extends Record, - Output extends InterfacesReceipt, - >( - config: Config, - fn: SetInterfaces, - ) => setupInterfaces(config, fn), - setupMain: ( - fn: (o: { - effects: MainEffects - started(onTerm: () => PromiseLike): PromiseLike - }) => Promise>, - ) => setupMain(fn), - setupProperties: - ( - fn: (options: { effects: Effects }) => Promise, - ): T.ExpectedExports.properties => - (options) => - fn(options).then(nullifyProperties), - setupUninstall: (fn: UninstallFn) => - setupUninstall(fn), - trigger: { - defaultTrigger, - cooldownTrigger, - changeOnFirstSuccess, - successFailure, - }, - Mounts: { - of() { - return Mounts.of() - }, - }, - Backups: { - volumes: ( - ...volumeNames: Array - ) => Backups.volumes(...volumeNames), - addSets: ( - ...options: BackupSet[] - ) => Backups.addSets(...options), - withOptions: (options?: Partial) => - Backups.with_options(options), - }, - Config: { - of: < - Spec extends Record | Value>, - >( - spec: Spec, - ) => Config.of(spec), - }, - Daemons: { - of(config: { - effects: Effects - started: (onTerm: () => PromiseLike) => PromiseLike - healthReceipts: HealthReceipt[] - }) { - return Daemons.of(config) - }, - }, - DependencyConfig: { - of< - LocalConfig extends Record, - RemoteConfig extends Record, - >({ - localConfigSpec, - remoteConfigSpec, - dependencyConfig, - update, - }: { - localConfigSpec: - | Config - | Config - remoteConfigSpec: - | Config - | Config - dependencyConfig: (options: { - effects: Effects - localConfig: LocalConfig - }) => Promise> - update?: Update, RemoteConfig> - }) { - return new DependencyConfig< - Manifest, - Store, - LocalConfig, - RemoteConfig - >(dependencyConfig, update) - }, - }, - List: { - text: List.text, - obj: >( - a: { - name: string - description?: string | null - warning?: string | null - /** Default [] */ - default?: [] - minLength?: number | null - maxLength?: number | null - }, - aSpec: { - spec: Config - displayAs?: null | string - uniqueBy?: null | UniqueBy - }, - ) => List.obj(a, aSpec), - dynamicText: ( - getA: LazyBuild< - Store, - { - name: string - description?: string | null - warning?: string | null - /** Default = [] */ - default?: string[] - minLength?: number | null - maxLength?: number | null - disabled?: false | string - generate?: null | RandomString - spec: { - /** Default = false */ - masked?: boolean - placeholder?: string | null - minLength?: number | null - maxLength?: number | null - patterns: Pattern[] - /** Default = "text" */ - inputmode?: ListValueSpecText["inputmode"] - } - } - >, - ) => List.dynamicText(getA), - }, - StorePath: pathBuilder(), - Value: { - toggle: Value.toggle, - text: Value.text, - textarea: Value.textarea, - number: Value.number, - color: Value.color, - datetime: Value.datetime, - select: Value.select, - multiselect: Value.multiselect, - object: Value.object, - union: Value.union, - list: Value.list, - dynamicToggle: ( - a: LazyBuild< - Store, - { - name: string - description?: string | null - warning?: string | null - default: boolean - disabled?: false | string - } - >, - ) => Value.dynamicToggle(a), - dynamicText: ( - getA: LazyBuild< - Store, - { - name: string - description?: string | null - warning?: string | null - required: RequiredDefault - - /** Default = false */ - masked?: boolean - placeholder?: string | null - minLength?: number | null - maxLength?: number | null - patterns?: Pattern[] - /** Default = 'text' */ - inputmode?: ValueSpecText["inputmode"] - generate?: null | RandomString - } - >, - ) => Value.dynamicText(getA), - dynamicTextarea: ( - getA: LazyBuild< - Store, - { - name: string - description?: string | null - warning?: string | null - required: boolean - minLength?: number | null - maxLength?: number | null - placeholder?: string | null - disabled?: false | string - generate?: null | RandomString - } - >, - ) => Value.dynamicTextarea(getA), - dynamicNumber: ( - getA: LazyBuild< - Store, - { - name: string - description?: string | null - warning?: string | null - required: RequiredDefault - min?: number | null - max?: number | null - /** Default = '1' */ - step?: number | null - integer: boolean - units?: string | null - placeholder?: string | null - disabled?: false | string - } - >, - ) => Value.dynamicNumber(getA), - dynamicColor: ( - getA: LazyBuild< - Store, - { - name: string - description?: string | null - warning?: string | null - required: RequiredDefault - - disabled?: false | string - } - >, - ) => Value.dynamicColor(getA), - dynamicDatetime: ( - getA: LazyBuild< - Store, - { - name: string - description?: string | null - warning?: string | null - required: RequiredDefault - /** Default = 'datetime-local' */ - inputmode?: ValueSpecDatetime["inputmode"] - min?: string | null - max?: string | null - disabled?: false | string - } - >, - ) => Value.dynamicDatetime(getA), - dynamicSelect: ( - getA: LazyBuild< - Store, - { - name: string - description?: string | null - warning?: string | null - required: RequiredDefault - values: Record - disabled?: false | string - } - >, - ) => Value.dynamicSelect(getA), - dynamicMultiselect: ( - getA: LazyBuild< - Store, - { - name: string - description?: string | null - warning?: string | null - default: string[] - values: Record - minLength?: number | null - maxLength?: number | null - disabled?: false | string - } - >, - ) => Value.dynamicMultiselect(getA), - filteredUnion: < - Required extends RequiredDefault, - Type extends Record, - >( - getDisabledFn: LazyBuild, - a: { - name: string - description?: string | null - warning?: string | null - required: Required - }, - aVariants: Variants | Variants, - ) => - Value.filteredUnion( - getDisabledFn, - a, - aVariants, - ), - - dynamicUnion: < - Required extends RequiredDefault, - Type extends Record, - >( - getA: LazyBuild< - Store, - { - disabled: string[] | false | string - name: string - description?: string | null - warning?: string | null - required: Required - } - >, - aVariants: Variants | Variants, - ) => Value.dynamicUnion(getA, aVariants), - }, - Variants: { - of: < - VariantValues extends { - [K in string]: { - name: string - spec: Config - } - }, - >( - a: VariantValues, - ) => Variants.of(a), - }, - } - } -} - -export async function runCommand( - effects: Effects, - image: { id: keyof Manifest["images"] & T.ImageId; sharedRun?: boolean }, - command: string | [string, ...string[]], - options: CommandOptions & { - mounts?: { path: string; options: MountOptions }[] - }, -): Promise<{ stdout: string | Buffer; stderr: string | Buffer }> { - const commands = splitCommand(command) - return SubContainer.with( - effects, - image, - options.mounts || [], - (subcontainer) => subcontainer.exec(commands), - ) -} -function nullifyProperties(value: T.SdkPropertiesReturn): T.PropertiesReturn { - return Object.fromEntries( - Object.entries(value).map(([k, v]) => [k, nullifyProperties_(v)]), - ) -} -function nullifyProperties_(value: T.SdkPropertiesValue): T.PropertiesValue { - if (value.type === "string") { - return { description: null, copyable: null, qr: null, ...value } - } - return { - description: null, - ...value, - value: Object.fromEntries( - Object.entries(value.value).map(([k, v]) => [k, nullifyProperties_(v)]), - ), - } -} diff --git a/sdk/lib/actions/createAction.ts b/sdk/lib/actions/createAction.ts deleted file mode 100644 index 4fa858d56..000000000 --- a/sdk/lib/actions/createAction.ts +++ /dev/null @@ -1,89 +0,0 @@ -import * as T from "../types" -import { Config, ExtractConfigType } from "../config/builder/config" - -import { ActionMetadata, ActionResult, Effects, ExportedAction } from "../types" - -export type MaybeFn = - | Value - | ((options: { effects: Effects }) => Promise | Value) -export class CreatedAction< - Manifest extends T.Manifest, - Store, - ConfigType extends - | Record - | Config - | Config, - Type extends Record = ExtractConfigType, -> { - private constructor( - public readonly id: string, - public readonly myMetadata: MaybeFn< - Manifest, - Store, - Omit - >, - readonly fn: (options: { - effects: Effects - input: Type - }) => Promise, - readonly input: Config, - public validator = input.validator, - ) {} - - static of< - Manifest extends T.Manifest, - Store, - ConfigType extends - | Record - | Config - | Config, - Type extends Record = ExtractConfigType, - >( - id: string, - metadata: MaybeFn>, - fn: (options: { effects: Effects; input: Type }) => Promise, - inputConfig: Config | Config, - ) { - return new CreatedAction( - id, - metadata, - fn, - inputConfig as Config, - ) - } - - exportedAction: ExportedAction = ({ effects, input }) => { - return this.fn({ - effects, - input: this.validator.unsafeCast(input), - }) - } - - run = async ({ effects, input }: { effects: Effects; input?: Type }) => { - return this.fn({ - effects, - input: this.validator.unsafeCast(input), - }) - } - - async metadata(options: { effects: Effects }) { - if (this.myMetadata instanceof Function) - return await this.myMetadata(options) - return this.myMetadata - } - - async ActionMetadata(options: { effects: Effects }): Promise { - return { - ...(await this.metadata(options)), - input: await this.input.build(options), - } - } - - async getConfig({ effects }: { effects: Effects }) { - return this.input.build({ - effects, - }) - } -} - -export const createAction = CreatedAction.of diff --git a/sdk/lib/actions/index.ts b/sdk/lib/actions/index.ts deleted file mode 100644 index 603684b67..000000000 --- a/sdk/lib/actions/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import "./createAction" - -import "./setupActions" diff --git a/sdk/lib/actions/setupActions.ts b/sdk/lib/actions/setupActions.ts deleted file mode 100644 index 07b4e2606..000000000 --- a/sdk/lib/actions/setupActions.ts +++ /dev/null @@ -1,29 +0,0 @@ -import * as T from "../types" -import { Effects, ExpectedExports } from "../types" -import { CreatedAction } from "./createAction" - -export function setupActions( - ...createdActions: CreatedAction[] -) { - const myActions = async (options: { effects: Effects }) => { - const actions: Record> = {} - for (const action of createdActions) { - actions[action.id] = action - } - return actions - } - const answer: { - actions: ExpectedExports.actions - actionsMetadata: ExpectedExports.actionsMetadata - } = { - actions(options: { effects: Effects }) { - return myActions(options) - }, - async actionsMetadata({ effects }: { effects: Effects }) { - return Promise.all( - createdActions.map((x) => x.ActionMetadata({ effects })), - ) - }, - } - return answer -} diff --git a/sdk/lib/backup/Backups.ts b/sdk/lib/backup/Backups.ts deleted file mode 100644 index 031ac4e4c..000000000 --- a/sdk/lib/backup/Backups.ts +++ /dev/null @@ -1,209 +0,0 @@ -import * as T from "../types" - -import * as child_process from "child_process" -import { promises as fsPromises } from "fs" -import { asError } from "../util" - -export type BACKUP = "BACKUP" -export const DEFAULT_OPTIONS: T.BackupOptions = { - delete: true, - force: true, - ignoreExisting: false, - exclude: [], -} -export type BackupSet = { - srcPath: string - srcVolume: Volumes | BACKUP - dstPath: string - dstVolume: Volumes | BACKUP - options?: Partial -} -/** - * This utility simplifies the volume backup process. - * ```ts - * export const { createBackup, restoreBackup } = Backups.volumes("main").build(); - * ``` - * - * Changing the options of the rsync, (ie exludes) use either - * ```ts - * Backups.volumes("main").set_options({exclude: ['bigdata/']}).volumes('excludedVolume').build() - * // or - * Backups.with_options({exclude: ['bigdata/']}).volumes('excludedVolume').build() - * ``` - * - * Using the more fine control, using the addSets for more control - * ```ts - * Backups.addSets({ - * srcVolume: 'main', srcPath:'smallData/', dstPath: 'main/smallData/', dstVolume: : Backups.BACKUP - * }, { - * srcVolume: 'main', srcPath:'bigData/', dstPath: 'main/bigData/', dstVolume: : Backups.BACKUP, options: {exclude:['bigData/excludeThis']}} - * ).build()q - * ``` - */ -export class Backups { - static BACKUP: BACKUP = "BACKUP" - - private constructor( - private options = DEFAULT_OPTIONS, - private backupSet = [] as BackupSet[], - ) {} - static volumes( - ...volumeNames: Array - ): Backups { - return new Backups().addSets( - ...volumeNames.map((srcVolume) => ({ - srcVolume, - srcPath: "./", - dstPath: `./${srcVolume}/`, - dstVolume: Backups.BACKUP, - })), - ) - } - static addSets( - ...options: BackupSet[] - ) { - return new Backups().addSets(...options) - } - static with_options( - options?: Partial, - ) { - return new Backups({ ...DEFAULT_OPTIONS, ...options }) - } - - static withOptions = Backups.with_options - setOptions(options?: Partial) { - this.options = { - ...this.options, - ...options, - } - return this - } - volumes(...volumeNames: Array) { - return this.addSets( - ...volumeNames.map((srcVolume) => ({ - srcVolume, - srcPath: "./", - dstPath: `./${srcVolume}/`, - dstVolume: Backups.BACKUP, - })), - ) - } - addSets(...options: BackupSet[]) { - options.forEach((x) => - this.backupSet.push({ ...x, options: { ...this.options, ...x.options } }), - ) - return this - } - build(pathMaker: T.PathMaker) { - const createBackup: T.ExpectedExports.createBackup = async ({ - effects, - }) => { - for (const item of this.backupSet) { - const rsyncResults = await runRsync( - { - dstPath: item.dstPath, - dstVolume: item.dstVolume, - options: { ...this.options, ...item.options }, - srcPath: item.srcPath, - srcVolume: item.srcVolume, - }, - pathMaker, - ) - await rsyncResults.wait() - } - return - } - const restoreBackup: T.ExpectedExports.restoreBackup = async ({ - effects, - }) => { - for (const item of this.backupSet) { - const rsyncResults = await runRsync( - { - dstPath: item.dstPath, - dstVolume: item.dstVolume, - options: { ...this.options, ...item.options }, - srcPath: item.srcPath, - srcVolume: item.srcVolume, - }, - pathMaker, - ) - await rsyncResults.wait() - } - return - } - return { createBackup, restoreBackup } - } -} -function notEmptyPath(file: string) { - return ["", ".", "./"].indexOf(file) === -1 -} -async function runRsync( - rsyncOptions: { - srcVolume: string - dstVolume: string - srcPath: string - dstPath: string - options: T.BackupOptions - }, - pathMaker: T.PathMaker, -): Promise<{ - id: () => Promise - wait: () => Promise - progress: () => Promise -}> { - const { srcVolume, dstVolume, srcPath, dstPath, options } = rsyncOptions - - const command = "rsync" - const args: string[] = [] - if (options.delete) { - args.push("--delete") - } - if (options.force) { - args.push("--force") - } - if (options.ignoreExisting) { - args.push("--ignore-existing") - } - for (const exclude of options.exclude) { - args.push(`--exclude=${exclude}`) - } - args.push("-actAXH") - args.push("--info=progress2") - args.push("--no-inc-recursive") - args.push(pathMaker({ volume: srcVolume, path: srcPath })) - args.push(pathMaker({ volume: dstVolume, path: dstPath })) - const spawned = child_process.spawn(command, args, { detached: true }) - let percentage = 0.0 - spawned.stdout.on("data", (data: unknown) => { - const lines = String(data).replace("\r", "\n").split("\n") - for (const line of lines) { - const parsed = /$([0-9.]+)%/.exec(line)?.[1] - if (!parsed) continue - percentage = Number.parseFloat(parsed) - } - }) - - spawned.stderr.on("data", (data: unknown) => { - console.error(`Backups.runAsync`, asError(data)) - }) - - const id = async () => { - const pid = spawned.pid - if (pid === undefined) { - throw new Error("rsync process has no pid") - } - return String(pid) - } - const waitPromise = new Promise((resolve, reject) => { - spawned.on("exit", (code: any) => { - if (code === 0) { - resolve(null) - } else { - reject(new Error(`rsync exited with code ${code}`)) - } - }) - }) - const wait = () => waitPromise - const progress = () => Promise.resolve(percentage) - return { id, wait, progress } -} diff --git a/sdk/lib/backup/setupBackups.ts b/sdk/lib/backup/setupBackups.ts deleted file mode 100644 index c12f1d2ed..000000000 --- a/sdk/lib/backup/setupBackups.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { Backups } from "./Backups" - -import * as T from "../types" -import { _ } from "../util" - -export type SetupBackupsParams = Array< - M["volumes"][number] | Backups -> - -export function setupBackups( - manifest: M, - ...args: _> -) { - const backups = Array>() - const volumes = new Set() - for (const arg of args) { - if (arg instanceof Backups) { - backups.push(arg) - } else { - volumes.add(arg) - } - } - backups.push(Backups.volumes(...volumes)) - const answer: { - createBackup: T.ExpectedExports.createBackup - restoreBackup: T.ExpectedExports.restoreBackup - } = { - get createBackup() { - return (async (options) => { - for (const backup of backups) { - await backup.build(options.pathMaker).createBackup(options) - } - }) as T.ExpectedExports.createBackup - }, - get restoreBackup() { - return (async (options) => { - for (const backup of backups) { - await backup.build(options.pathMaker).restoreBackup(options) - } - await options.effects.setDataVersion({ version: manifest.version }) - }) as T.ExpectedExports.restoreBackup - }, - } - return answer -} diff --git a/sdk/lib/config/configDependencies.ts b/sdk/lib/config/configDependencies.ts deleted file mode 100644 index d9865f25c..000000000 --- a/sdk/lib/config/configDependencies.ts +++ /dev/null @@ -1,28 +0,0 @@ -import * as T from "../types" - -export type ConfigDependencies = { - exists(id: keyof T["dependencies"]): T.Dependencies[number] - running( - id: keyof T["dependencies"], - healthChecks: string[], - ): T.Dependencies[number] -} - -export const configDependenciesSet = < - T extends T.Manifest, ->(): ConfigDependencies => ({ - exists(id: keyof T["dependencies"]) { - return { - id, - kind: "exists", - } as T.Dependencies[number] - }, - - running(id: keyof T["dependencies"], healthChecks: string[]) { - return { - id, - kind: "running", - healthChecks, - } as T.Dependencies[number] - }, -}) diff --git a/sdk/lib/config/index.ts b/sdk/lib/config/index.ts deleted file mode 100644 index 35c3e274e..000000000 --- a/sdk/lib/config/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * as constants from "./configConstants" -export * as types from "./configTypes" -export * as builder from "./builder" diff --git a/sdk/lib/config/setupConfig.ts b/sdk/lib/config/setupConfig.ts deleted file mode 100644 index f354c81ed..000000000 --- a/sdk/lib/config/setupConfig.ts +++ /dev/null @@ -1,87 +0,0 @@ -import * as T from "../types" - -import * as D from "./configDependencies" -import { Config, ExtractConfigType } from "./builder/config" -import nullIfEmpty from "../util/nullIfEmpty" -import { InterfacesReceipt as InterfacesReceipt } from "../interfaces/setupInterfaces" - -declare const dependencyProof: unique symbol -export type DependenciesReceipt = void & { - [dependencyProof]: never -} - -export type Save< - A extends - | Record - | Config, any> - | Config, never>, -> = (options: { - effects: T.Effects - input: ExtractConfigType & Record -}) => Promise<{ - dependenciesReceipt: DependenciesReceipt - interfacesReceipt: InterfacesReceipt - restart: boolean -}> -export type Read< - Manifest extends T.Manifest, - Store, - A extends - | Record - | Config, any> - | Config, never>, -> = (options: { - effects: T.Effects -}) => Promise & Record)> -/** - * We want to setup a config export with a get and set, this - * is going to be the default helper to setup config, because it will help - * enforce that we have a spec, write, and reading. - * @param options - * @returns - */ -export function setupConfig< - Store, - ConfigType extends - | Record - | Config - | Config, - Manifest extends T.Manifest, - Type extends Record = ExtractConfigType, ->( - spec: Config | Config, - write: Save, - read: Read, -) { - const validator = spec.validator - return { - setConfig: (async ({ effects, input }) => { - if (!validator.test(input)) { - await console.error( - new Error(validator.errorMessage(input)?.toString()), - ) - return { error: "Set config type error for config" } - } - await effects.clearBindings() - await effects.clearServiceInterfaces() - const { restart } = await write({ - input: JSON.parse(JSON.stringify(input)) as any, - effects, - }) - if (restart) { - await effects.restart() - } - }) as T.ExpectedExports.setConfig, - getConfig: (async ({ effects }) => { - const configValue = nullIfEmpty((await read({ effects })) || null) - return { - spec: await spec.build({ - effects, - }), - config: configValue, - } - }) as T.ExpectedExports.getConfig, - } -} - -export default setupConfig diff --git a/sdk/lib/coverage/clover.xml b/sdk/lib/coverage/clover.xml new file mode 100644 index 000000000..d53a0d99f --- /dev/null +++ b/sdk/lib/coverage/clover.xml @@ -0,0 +1,2881 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/lib/coverage/coverage-final.json b/sdk/lib/coverage/coverage-final.json new file mode 100644 index 000000000..11e057734 --- /dev/null +++ b/sdk/lib/coverage/coverage-final.json @@ -0,0 +1,73 @@ +{"/Users/matthill/Code/start9/start-os/sdk/lib/Dependency.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/Dependency.ts","statementMap":{"0":{"start":{"line":5,"column":13},"end":{"line":5,"column":null}},"1":{"start":{"line":3,"column":0},"end":{"line":3,"column":13}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":4,"column":2},"end":{"line":4,"column":null}},"loc":{"start":{"line":16,"column":9},"end":{"line":17,"column":6}}}},"branchMap":{},"s":{"0":0,"1":5},"f":{"0":0},"b":{}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/StartSdk.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/StartSdk.ts","statementMap":{"0":{"start":{"line":1,"column":0},"end":{"line":1,"column":63}},"1":{"start":{"line":2,"column":0},"end":{"line":2,"column":78}},"2":{"start":{"line":12,"column":0},"end":{"line":12,"column":52}},"3":{"start":{"line":13,"column":0},"end":{"line":13,"column":68}},"4":{"start":{"line":24,"column":0},"end":{"line":24,"column":43}},"5":{"start":{"line":25,"column":0},"end":{"line":25,"column":74}},"6":{"start":{"line":26,"column":0},"end":{"line":26,"column":53}},"7":{"start":{"line":27,"column":0},"end":{"line":27,"column":53}},"8":{"start":{"line":28,"column":0},"end":{"line":28,"column":42}},"9":{"start":{"line":29,"column":0},"end":{"line":29,"column":69}},"10":{"start":{"line":30,"column":0},"end":{"line":30,"column":73}},"11":{"start":{"line":31,"column":0},"end":{"line":31,"column":64}},"12":{"start":{"line":32,"column":0},"end":{"line":32,"column":44}},"13":{"start":{"line":33,"column":0},"end":{"line":33,"column":57}},"14":{"start":{"line":34,"column":0},"end":{"line":34,"column":53}},"15":{"start":{"line":35,"column":0},"end":{"line":35,"column":76}},"16":{"start":{"line":36,"column":0},"end":{"line":36,"column":72}},"17":{"start":{"line":37,"column":0},"end":{"line":37,"column":45}},"18":{"start":{"line":38,"column":0},"end":{"line":38,"column":79}},"19":{"start":{"line":39,"column":0},"end":{"line":39,"column":36}},"20":{"start":{"line":40,"column":0},"end":{"line":40,"column":57}},"21":{"start":{"line":41,"column":0},"end":{"line":41,"column":65}},"22":{"start":{"line":42,"column":0},"end":{"line":42,"column":null}},"23":{"start":{"line":47,"column":0},"end":{"line":47,"column":null}},"24":{"start":{"line":52,"column":0},"end":{"line":52,"column":57}},"25":{"start":{"line":54,"column":0},"end":{"line":54,"column":53}},"26":{"start":{"line":55,"column":0},"end":{"line":55,"column":78}},"27":{"start":{"line":56,"column":0},"end":{"line":56,"column":52}},"28":{"start":{"line":57,"column":0},"end":{"line":57,"column":44}},"29":{"start":{"line":58,"column":0},"end":{"line":58,"column":null}},"30":{"start":{"line":62,"column":0},"end":{"line":62,"column":66}},"31":{"start":{"line":63,"column":0},"end":{"line":63,"column":43}},"32":{"start":{"line":64,"column":0},"end":{"line":64,"column":80}},"33":{"start":{"line":65,"column":0},"end":{"line":65,"column":50}},"34":{"start":{"line":66,"column":0},"end":{"line":66,"column":40}},"35":{"start":{"line":67,"column":0},"end":{"line":67,"column":41}},"36":{"start":{"line":69,"column":0},"end":{"line":69,"column":56}},"37":{"start":{"line":71,"column":0},"end":{"line":71,"column":79}},"38":{"start":{"line":72,"column":0},"end":{"line":72,"column":null}},"39":{"start":{"line":77,"column":0},"end":{"line":77,"column":60}},"40":{"start":{"line":80,"column":13},"end":{"line":80,"column":null}},"41":{"start":{"line":95,"column":13},"end":{"line":95,"column":null}},"42":{"start":{"line":96,"column":13},"end":{"line":96,"column":null}},"43":{"start":{"line":97,"column":13},"end":{"line":97,"column":null}},"44":{"start":{"line":100,"column":2},"end":{"line":112,"column":null}},"45":{"start":{"line":101,"column":4},"end":{"line":111,"column":null}},"46":{"start":{"line":102,"column":6},"end":{"line":102,"column":null}},"47":{"start":{"line":104,"column":6},"end":{"line":106,"column":null}},"48":{"start":{"line":105,"column":8},"end":{"line":105,"column":null}},"49":{"start":{"line":107,"column":6},"end":{"line":109,"column":null}},"50":{"start":{"line":108,"column":8},"end":{"line":108,"column":null}},"51":{"start":{"line":110,"column":6},"end":{"line":110,"column":null}},"52":{"start":{"line":116,"column":31},"end":{"line":116,"column":49}},"53":{"start":{"line":118,"column":4},"end":{"line":118,"column":null}},"54":{"start":{"line":121,"column":4},"end":{"line":121,"column":null}},"55":{"start":{"line":124,"column":4},"end":{"line":124,"column":null}},"56":{"start":{"line":158,"column":57},"end":{"line":182,"column":null}},"57":{"start":{"line":159,"column":43},"end":{"line":159,"column":73}},"58":{"start":{"line":160,"column":42},"end":{"line":160,"column":71}},"59":{"start":{"line":161,"column":42},"end":{"line":161,"column":71}},"60":{"start":{"line":162,"column":43},"end":{"line":162,"column":73}},"61":{"start":{"line":163,"column":43},"end":{"line":163,"column":73}},"62":{"start":{"line":164,"column":37},"end":{"line":164,"column":61}},"63":{"start":{"line":165,"column":45},"end":{"line":165,"column":77}},"64":{"start":{"line":167,"column":8},"end":{"line":167,"column":42}},"65":{"start":{"line":168,"column":35},"end":{"line":168,"column":57}},"66":{"start":{"line":170,"column":8},"end":{"line":170,"column":45}},"67":{"start":{"line":172,"column":8},"end":{"line":172,"column":44}},"68":{"start":{"line":174,"column":8},"end":{"line":174,"column":46}},"69":{"start":{"line":175,"column":43},"end":{"line":175,"column":73}},"70":{"start":{"line":176,"column":44},"end":{"line":176,"column":75}},"71":{"start":{"line":177,"column":39},"end":{"line":177,"column":65}},"72":{"start":{"line":178,"column":44},"end":{"line":178,"column":75}},"73":{"start":{"line":179,"column":44},"end":{"line":179,"column":75}},"74":{"start":{"line":180,"column":38},"end":{"line":180,"column":63}},"75":{"start":{"line":181,"column":45},"end":{"line":181,"column":77}},"76":{"start":{"line":184,"column":4},"end":{"line":768,"column":null}},"77":{"start":{"line":196,"column":10},"end":{"line":199,"column":null}},"78":{"start":{"line":205,"column":10},"end":{"line":205,"column":77}},"79":{"start":{"line":207,"column":10},"end":{"line":207,"column":76}},"80":{"start":{"line":212,"column":10},"end":{"line":212,"column":78}},"81":{"start":{"line":221,"column":10},"end":{"line":224,"column":null}},"82":{"start":{"line":230,"column":10},"end":{"line":231,"column":null}},"83":{"start":{"line":238,"column":10},"end":{"line":241,"column":12}},"84":{"start":{"line":249,"column":49},"end":{"line":249,"column":79}},"85":{"start":{"line":263,"column":8},"end":{"line":263,"column":null}},"86":{"start":{"line":282,"column":35},"end":{"line":282,"column":43}},"87":{"start":{"line":283,"column":8},"end":{"line":288,"column":null}},"88":{"start":{"line":305,"column":11},"end":{"line":305,"column":63}},"89":{"start":{"line":307,"column":8},"end":{"line":307,"column":67}},"90":{"start":{"line":314,"column":8},"end":{"line":315,"column":null}},"91":{"start":{"line":335,"column":8},"end":{"line":340,"column":null}},"92":{"start":{"line":344,"column":10},"end":{"line":344,"column":null}},"93":{"start":{"line":349,"column":10},"end":{"line":349,"column":null}},"94":{"start":{"line":359,"column":8},"end":{"line":359,"column":56}},"95":{"start":{"line":361,"column":8},"end":{"line":361,"column":54}},"96":{"start":{"line":369,"column":11},"end":{"line":369,"column":76}},"97":{"start":{"line":377,"column":11},"end":{"line":377,"column":13}},"98":{"start":{"line":385,"column":11},"end":{"line":385,"column":13}},"99":{"start":{"line":396,"column":11},"end":{"line":396,"column":77}},"100":{"start":{"line":403,"column":8},"end":{"line":427,"column":null}},"101":{"start":{"line":404,"column":33},"end":{"line":404,"column":50}},"102":{"start":{"line":405,"column":10},"end":{"line":426,"column":null}},"103":{"start":{"line":412,"column":21},"end":{"line":424,"column":16}},"104":{"start":{"line":440,"column":8},"end":{"line":446,"column":null}},"105":{"start":{"line":448,"column":56},"end":{"line":448,"column":70}},"106":{"start":{"line":455,"column":11},"end":{"line":455,"column":38}},"107":{"start":{"line":461,"column":11},"end":{"line":461,"column":41}},"108":{"start":{"line":466,"column":8},"end":{"line":467,"column":45}},"109":{"start":{"line":467,"column":10},"end":{"line":467,"column":45}},"110":{"start":{"line":469,"column":8},"end":{"line":469,"column":43}},"111":{"start":{"line":478,"column":10},"end":{"line":478,"column":null}},"112":{"start":{"line":484,"column":13},"end":{"line":484,"column":54}},"113":{"start":{"line":487,"column":13},"end":{"line":487,"column":50}},"114":{"start":{"line":489,"column":10},"end":{"line":489,"column":49}},"115":{"start":{"line":496,"column":13},"end":{"line":496,"column":41}},"116":{"start":{"line":504,"column":10},"end":{"line":504,"column":null}},"117":{"start":{"line":529,"column":10},"end":{"line":534,"column":null}},"118":{"start":{"line":554,"column":13},"end":{"line":554,"column":44}},"119":{"start":{"line":580,"column":13},"end":{"line":580,"column":42}},"120":{"start":{"line":606,"column":13},"end":{"line":606,"column":42}},"121":{"start":{"line":627,"column":13},"end":{"line":627,"column":43}},"122":{"start":{"line":643,"column":13},"end":{"line":643,"column":47}},"123":{"start":{"line":662,"column":13},"end":{"line":662,"column":45}},"124":{"start":{"line":675,"column":13},"end":{"line":675,"column":44}},"125":{"start":{"line":691,"column":13},"end":{"line":691,"column":47}},"126":{"start":{"line":704,"column":13},"end":{"line":704,"column":45}},"127":{"start":{"line":719,"column":13},"end":{"line":719,"column":50}},"128":{"start":{"line":733,"column":10},"end":{"line":736,"column":null}},"129":{"start":{"line":754,"column":13},"end":{"line":754,"column":71}},"130":{"start":{"line":766,"column":13},"end":{"line":766,"column":49}},"131":{"start":{"line":115,"column":0},"end":{"line":115,"column":13}},"132":{"start":{"line":780,"column":19},"end":{"line":780,"column":40}},"133":{"start":{"line":781,"column":2},"end":{"line":786,"column":null}},"134":{"start":{"line":785,"column":22},"end":{"line":785,"column":49}},"135":{"start":{"line":772,"column":0},"end":{"line":772,"column":7}},"136":{"start":{"line":789,"column":2},"end":{"line":791,"column":null}},"137":{"start":{"line":790,"column":42},"end":{"line":790,"column":68}},"138":{"start":{"line":794,"column":2},"end":{"line":796,"column":null}},"139":{"start":{"line":795,"column":4},"end":{"line":795,"column":null}},"140":{"start":{"line":797,"column":2},"end":{"line":803,"column":null}},"141":{"start":{"line":801,"column":50},"end":{"line":801,"column":76}}},"fnMap":{"0":{"name":"removeCallbackTypes","decl":{"start":{"line":99,"column":9},"end":{"line":99,"column":28}},"loc":{"start":{"line":99,"column":58},"end":{"line":113,"column":1}}},"1":{"name":"(anonymous_8)","decl":{"start":{"line":100,"column":9},"end":{"line":100,"column":28}},"loc":{"start":{"line":100,"column":36},"end":{"line":112,"column":3}}},"2":{"name":"(anonymous_9)","decl":{"start":{"line":116,"column":2},"end":{"line":116,"column":31}},"loc":{"start":{"line":116,"column":49},"end":{"line":116,"column":53}}},"3":{"name":"(anonymous_10)","decl":{"start":{"line":117,"column":2},"end":{"line":117,"column":8}},"loc":{"start":{"line":117,"column":11},"end":{"line":119,"column":3}}},"4":{"name":"(anonymous_11)","decl":{"start":{"line":120,"column":2},"end":{"line":120,"column":14}},"loc":{"start":{"line":120,"column":70},"end":{"line":122,"column":3}}},"5":{"name":"(anonymous_12)","decl":{"start":{"line":123,"column":2},"end":{"line":123,"column":11}},"loc":{"start":{"line":123,"column":11},"end":{"line":125,"column":3}}},"6":{"name":"(anonymous_13)","decl":{"start":{"line":127,"column":2},"end":{"line":127,"column":7}},"loc":{"start":{"line":127,"column":73},"end":{"line":769,"column":3}}},"7":{"name":"(anonymous_14)","decl":{"start":{"line":159,"column":21},"end":{"line":159,"column":22}},"loc":{"start":{"line":159,"column":43},"end":{"line":159,"column":73}}},"8":{"name":"(anonymous_15)","decl":{"start":{"line":160,"column":20},"end":{"line":160,"column":21}},"loc":{"start":{"line":160,"column":42},"end":{"line":160,"column":71}}},"9":{"name":"(anonymous_16)","decl":{"start":{"line":161,"column":20},"end":{"line":161,"column":21}},"loc":{"start":{"line":161,"column":42},"end":{"line":161,"column":71}}},"10":{"name":"(anonymous_17)","decl":{"start":{"line":162,"column":21},"end":{"line":162,"column":22}},"loc":{"start":{"line":162,"column":43},"end":{"line":162,"column":73}}},"11":{"name":"(anonymous_18)","decl":{"start":{"line":163,"column":21},"end":{"line":163,"column":22}},"loc":{"start":{"line":163,"column":43},"end":{"line":163,"column":73}}},"12":{"name":"(anonymous_19)","decl":{"start":{"line":164,"column":15},"end":{"line":164,"column":16}},"loc":{"start":{"line":164,"column":37},"end":{"line":164,"column":61}}},"13":{"name":"(anonymous_20)","decl":{"start":{"line":165,"column":23},"end":{"line":165,"column":24}},"loc":{"start":{"line":165,"column":45},"end":{"line":165,"column":77}}},"14":{"name":"(anonymous_21)","decl":{"start":{"line":166,"column":25},"end":{"line":166,"column":26}},"loc":{"start":{"line":167,"column":8},"end":{"line":167,"column":42}}},"15":{"name":"(anonymous_22)","decl":{"start":{"line":168,"column":13},"end":{"line":168,"column":14}},"loc":{"start":{"line":168,"column":35},"end":{"line":168,"column":57}}},"16":{"name":"(anonymous_23)","decl":{"start":{"line":169,"column":28},"end":{"line":169,"column":29}},"loc":{"start":{"line":170,"column":8},"end":{"line":170,"column":45}}},"17":{"name":"(anonymous_24)","decl":{"start":{"line":171,"column":27},"end":{"line":171,"column":28}},"loc":{"start":{"line":172,"column":8},"end":{"line":172,"column":44}}},"18":{"name":"(anonymous_25)","decl":{"start":{"line":173,"column":29},"end":{"line":173,"column":30}},"loc":{"start":{"line":174,"column":8},"end":{"line":174,"column":46}}},"19":{"name":"(anonymous_26)","decl":{"start":{"line":175,"column":21},"end":{"line":175,"column":22}},"loc":{"start":{"line":175,"column":43},"end":{"line":175,"column":73}}},"20":{"name":"(anonymous_27)","decl":{"start":{"line":176,"column":22},"end":{"line":176,"column":23}},"loc":{"start":{"line":176,"column":44},"end":{"line":176,"column":75}}},"21":{"name":"(anonymous_28)","decl":{"start":{"line":177,"column":17},"end":{"line":177,"column":18}},"loc":{"start":{"line":177,"column":39},"end":{"line":177,"column":65}}},"22":{"name":"(anonymous_29)","decl":{"start":{"line":178,"column":22},"end":{"line":178,"column":23}},"loc":{"start":{"line":178,"column":44},"end":{"line":178,"column":75}}},"23":{"name":"(anonymous_30)","decl":{"start":{"line":179,"column":22},"end":{"line":179,"column":23}},"loc":{"start":{"line":179,"column":44},"end":{"line":179,"column":75}}},"24":{"name":"(anonymous_31)","decl":{"start":{"line":180,"column":16},"end":{"line":180,"column":17}},"loc":{"start":{"line":180,"column":38},"end":{"line":180,"column":63}}},"25":{"name":"(anonymous_32)","decl":{"start":{"line":181,"column":23},"end":{"line":181,"column":24}},"loc":{"start":{"line":181,"column":45},"end":{"line":181,"column":77}}},"26":{"name":"(anonymous_33)","decl":{"start":{"line":195,"column":16},"end":{"line":195,"column":36}},"loc":{"start":{"line":196,"column":10},"end":{"line":199,"column":null}}},"27":{"name":"(anonymous_34)","decl":{"start":{"line":201,"column":13},"end":{"line":201,"column":null}},"loc":{"start":{"line":205,"column":10},"end":{"line":205,"column":77}}},"28":{"name":"(anonymous_35)","decl":{"start":{"line":206,"column":19},"end":{"line":206,"column":39}},"loc":{"start":{"line":207,"column":10},"end":{"line":207,"column":76}}},"29":{"name":"(anonymous_36)","decl":{"start":{"line":208,"column":16},"end":{"line":208,"column":null}},"loc":{"start":{"line":212,"column":10},"end":{"line":212,"column":78}}},"30":{"name":"(anonymous_37)","decl":{"start":{"line":216,"column":13},"end":{"line":216,"column":null}},"loc":{"start":{"line":221,"column":10},"end":{"line":224,"column":null}}},"31":{"name":"(anonymous_38)","decl":{"start":{"line":226,"column":16},"end":{"line":226,"column":null}},"loc":{"start":{"line":230,"column":10},"end":{"line":231,"column":null}}},"32":{"name":"(anonymous_39)","decl":{"start":{"line":233,"column":16},"end":{"line":233,"column":null}},"loc":{"start":{"line":238,"column":10},"end":{"line":241,"column":12}}},"33":{"name":"(anonymous_40)","decl":{"start":{"line":249,"column":15},"end":{"line":249,"column":16}},"loc":{"start":{"line":249,"column":49},"end":{"line":249,"column":79}}},"34":{"name":"(anonymous_41)","decl":{"start":{"line":252,"column":18},"end":{"line":252,"column":23}},"loc":{"start":{"line":262,"column":73},"end":{"line":264,"column":7}}},"35":{"name":"(anonymous_42)","decl":{"start":{"line":266,"column":20},"end":{"line":266,"column":null}},"loc":{"start":{"line":281,"column":10},"end":{"line":289,"column":7}}},"36":{"name":"(anonymous_43)","decl":{"start":{"line":291,"column":23},"end":{"line":291,"column":null}},"loc":{"start":{"line":305,"column":11},"end":{"line":305,"column":63}}},"37":{"name":"(anonymous_44)","decl":{"start":{"line":306,"column":21},"end":{"line":306,"column":41}},"loc":{"start":{"line":307,"column":8},"end":{"line":307,"column":67}}},"38":{"name":"(anonymous_45)","decl":{"start":{"line":309,"column":24},"end":{"line":309,"column":null}},"loc":{"start":{"line":314,"column":8},"end":{"line":315,"column":null}}},"39":{"name":"(anonymous_46)","decl":{"start":{"line":318,"column":27},"end":{"line":318,"column":null}},"loc":{"start":{"line":334,"column":10},"end":{"line":341,"column":7}}},"40":{"name":"(anonymous_47)","decl":{"start":{"line":343,"column":8},"end":{"line":343,"column":10}},"loc":{"start":{"line":343,"column":31},"end":{"line":345,"column":9}}},"41":{"name":"(anonymous_48)","decl":{"start":{"line":348,"column":8},"end":{"line":348,"column":10}},"loc":{"start":{"line":348,"column":35},"end":{"line":350,"column":9}}},"42":{"name":"(anonymous_49)","decl":{"start":{"line":358,"column":20},"end":{"line":358,"column":21}},"loc":{"start":{"line":359,"column":8},"end":{"line":359,"column":56}}},"43":{"name":"(anonymous_50)","decl":{"start":{"line":360,"column":20},"end":{"line":360,"column":21}},"loc":{"start":{"line":361,"column":8},"end":{"line":361,"column":54}}},"44":{"name":"(anonymous_51)","decl":{"start":{"line":362,"column":19},"end":{"line":362,"column":null}},"loc":{"start":{"line":369,"column":11},"end":{"line":369,"column":76}}},"45":{"name":"(anonymous_52)","decl":{"start":{"line":370,"column":23},"end":{"line":370,"column":null}},"loc":{"start":{"line":377,"column":11},"end":{"line":377,"column":13}}},"46":{"name":"(anonymous_53)","decl":{"start":{"line":378,"column":23},"end":{"line":378,"column":null}},"loc":{"start":{"line":385,"column":11},"end":{"line":385,"column":13}}},"47":{"name":"(anonymous_54)","decl":{"start":{"line":386,"column":29},"end":{"line":386,"column":null}},"loc":{"start":{"line":396,"column":11},"end":{"line":396,"column":77}}},"48":{"name":"(anonymous_55)","decl":{"start":{"line":397,"column":25},"end":{"line":397,"column":null}},"loc":{"start":{"line":402,"column":10},"end":{"line":428,"column":7}}},"49":{"name":"(anonymous_56)","decl":{"start":{"line":403,"column":15},"end":{"line":403,"column":20}},"loc":{"start":{"line":403,"column":69},"end":{"line":427,"column":9}}},"50":{"name":"(anonymous_57)","decl":{"start":{"line":407,"column":14},"end":{"line":407,"column":15}},"loc":{"start":{"line":412,"column":21},"end":{"line":424,"column":16}}},"51":{"name":"(anonymous_58)","decl":{"start":{"line":429,"column":17},"end":{"line":429,"column":null}},"loc":{"start":{"line":440,"column":8},"end":{"line":446,"column":null}}},"52":{"name":"(anonymous_59)","decl":{"start":{"line":448,"column":20},"end":{"line":448,"column":21}},"loc":{"start":{"line":448,"column":56},"end":{"line":448,"column":70}}},"53":{"name":"(anonymous_60)","decl":{"start":{"line":449,"column":23},"end":{"line":449,"column":null}},"loc":{"start":{"line":455,"column":11},"end":{"line":455,"column":38}}},"54":{"name":"(anonymous_61)","decl":{"start":{"line":456,"column":17},"end":{"line":456,"column":null}},"loc":{"start":{"line":461,"column":11},"end":{"line":461,"column":41}}},"55":{"name":"(anonymous_62)","decl":{"start":{"line":463,"column":8},"end":{"line":463,"column":null}},"loc":{"start":{"line":466,"column":8},"end":{"line":467,"column":45}}},"56":{"name":"(anonymous_63)","decl":{"start":{"line":466,"column":8},"end":{"line":466,"column":9}},"loc":{"start":{"line":467,"column":10},"end":{"line":467,"column":45}}},"57":{"name":"(anonymous_64)","decl":{"start":{"line":468,"column":22},"end":{"line":468,"column":23}},"loc":{"start":{"line":469,"column":8},"end":{"line":469,"column":43}}},"58":{"name":"(anonymous_65)","decl":{"start":{"line":477,"column":8},"end":{"line":477,"column":10}},"loc":{"start":{"line":477,"column":10},"end":{"line":479,"column":9}}},"59":{"name":"(anonymous_66)","decl":{"start":{"line":482,"column":17},"end":{"line":482,"column":null}},"loc":{"start":{"line":484,"column":13},"end":{"line":484,"column":54}}},"60":{"name":"(anonymous_67)","decl":{"start":{"line":485,"column":17},"end":{"line":485,"column":null}},"loc":{"start":{"line":487,"column":13},"end":{"line":487,"column":50}}},"61":{"name":"(anonymous_68)","decl":{"start":{"line":488,"column":21},"end":{"line":488,"column":22}},"loc":{"start":{"line":489,"column":10},"end":{"line":489,"column":49}}},"62":{"name":"(anonymous_69)","decl":{"start":{"line":492,"column":12},"end":{"line":492,"column":null}},"loc":{"start":{"line":496,"column":13},"end":{"line":496,"column":41}}},"63":{"name":"(anonymous_70)","decl":{"start":{"line":499,"column":8},"end":{"line":499,"column":10}},"loc":{"start":{"line":503,"column":9},"end":{"line":505,"column":9}}},"64":{"name":"(anonymous_71)","decl":{"start":{"line":508,"column":8},"end":{"line":508,"column":10}},"loc":{"start":{"line":528,"column":9},"end":{"line":535,"column":9}}},"65":{"name":"(anonymous_72)","decl":{"start":{"line":539,"column":13},"end":{"line":539,"column":null}},"loc":{"start":{"line":554,"column":13},"end":{"line":554,"column":44}}},"66":{"name":"(anonymous_73)","decl":{"start":{"line":555,"column":21},"end":{"line":555,"column":null}},"loc":{"start":{"line":580,"column":13},"end":{"line":580,"column":42}}},"67":{"name":"(anonymous_74)","decl":{"start":{"line":595,"column":23},"end":{"line":595,"column":null}},"loc":{"start":{"line":606,"column":13},"end":{"line":606,"column":42}}},"68":{"name":"(anonymous_75)","decl":{"start":{"line":607,"column":21},"end":{"line":607,"column":null}},"loc":{"start":{"line":627,"column":13},"end":{"line":627,"column":43}}},"69":{"name":"(anonymous_76)","decl":{"start":{"line":628,"column":25},"end":{"line":628,"column":null}},"loc":{"start":{"line":643,"column":13},"end":{"line":643,"column":47}}},"70":{"name":"(anonymous_77)","decl":{"start":{"line":644,"column":23},"end":{"line":644,"column":null}},"loc":{"start":{"line":662,"column":13},"end":{"line":662,"column":45}}},"71":{"name":"(anonymous_78)","decl":{"start":{"line":663,"column":22},"end":{"line":663,"column":null}},"loc":{"start":{"line":675,"column":13},"end":{"line":675,"column":44}}},"72":{"name":"(anonymous_79)","decl":{"start":{"line":676,"column":25},"end":{"line":676,"column":null}},"loc":{"start":{"line":691,"column":13},"end":{"line":691,"column":47}}},"73":{"name":"(anonymous_80)","decl":{"start":{"line":692,"column":23},"end":{"line":692,"column":null}},"loc":{"start":{"line":704,"column":13},"end":{"line":704,"column":45}}},"74":{"name":"(anonymous_81)","decl":{"start":{"line":705,"column":28},"end":{"line":705,"column":null}},"loc":{"start":{"line":719,"column":13},"end":{"line":719,"column":50}}},"75":{"name":"(anonymous_82)","decl":{"start":{"line":720,"column":23},"end":{"line":720,"column":null}},"loc":{"start":{"line":733,"column":10},"end":{"line":736,"column":null}}},"76":{"name":"(anonymous_83)","decl":{"start":{"line":739,"column":22},"end":{"line":739,"column":null}},"loc":{"start":{"line":754,"column":13},"end":{"line":754,"column":71}}},"77":{"name":"(anonymous_84)","decl":{"start":{"line":757,"column":12},"end":{"line":757,"column":null}},"loc":{"start":{"line":766,"column":13},"end":{"line":766,"column":49}}},"78":{"name":"runCommand","decl":{"start":{"line":772,"column":22},"end":{"line":772,"column":32}},"loc":{"start":{"line":778,"column":3},"end":{"line":787,"column":1}}},"79":{"name":"(anonymous_86)","decl":{"start":{"line":785,"column":4},"end":{"line":785,"column":5}},"loc":{"start":{"line":785,"column":22},"end":{"line":785,"column":49}}},"80":{"name":"nullifyProperties","decl":{"start":{"line":788,"column":9},"end":{"line":788,"column":26}},"loc":{"start":{"line":788,"column":55},"end":{"line":792,"column":1}}},"81":{"name":"(anonymous_88)","decl":{"start":{"line":790,"column":30},"end":{"line":790,"column":31}},"loc":{"start":{"line":790,"column":42},"end":{"line":790,"column":68}}},"82":{"name":"nullifyProperties_","decl":{"start":{"line":793,"column":9},"end":{"line":793,"column":27}},"loc":{"start":{"line":793,"column":55},"end":{"line":804,"column":1}}},"83":{"name":"(anonymous_90)","decl":{"start":{"line":801,"column":38},"end":{"line":801,"column":39}},"loc":{"start":{"line":801,"column":50},"end":{"line":801,"column":76}}}},"branchMap":{"0":{"loc":{"start":{"line":101,"column":4},"end":{"line":111,"column":null}},"type":"if","locations":[{"start":{"line":101,"column":4},"end":{"line":111,"column":null}},{"start":{"line":103,"column":11},"end":{"line":111,"column":null}}]},"1":{"loc":{"start":{"line":101,"column":8},"end":{"line":101,"column":54}},"type":"binary-expr","locations":[{"start":{"line":101,"column":8},"end":{"line":101,"column":26}},{"start":{"line":101,"column":30},"end":{"line":101,"column":54}}]},"2":{"loc":{"start":{"line":104,"column":6},"end":{"line":106,"column":null}},"type":"if","locations":[{"start":{"line":104,"column":6},"end":{"line":106,"column":null}}]},"3":{"loc":{"start":{"line":107,"column":6},"end":{"line":109,"column":null}},"type":"if","locations":[{"start":{"line":107,"column":6},"end":{"line":109,"column":null}}]},"4":{"loc":{"start":{"line":415,"column":20},"end":{"line":422,"column":22}},"type":"cond-expr","locations":[{"start":{"line":416,"column":20},"end":{"line":419,"column":null}},{"start":{"line":420,"column":20},"end":{"line":422,"column":22}}]},"5":{"loc":{"start":{"line":784,"column":4},"end":{"line":784,"column":24}},"type":"binary-expr","locations":[{"start":{"line":784,"column":4},"end":{"line":784,"column":18}},{"start":{"line":784,"column":22},"end":{"line":784,"column":24}}]},"6":{"loc":{"start":{"line":794,"column":2},"end":{"line":796,"column":null}},"type":"if","locations":[{"start":{"line":794,"column":2},"end":{"line":796,"column":null}}]}},"s":{"0":5,"1":5,"2":5,"3":5,"4":5,"5":5,"6":5,"7":5,"8":5,"9":5,"10":5,"11":5,"12":5,"13":5,"14":5,"15":5,"16":5,"17":5,"18":5,"19":5,"20":5,"21":5,"22":5,"23":5,"24":5,"25":5,"26":5,"27":5,"28":5,"29":5,"30":5,"31":5,"32":5,"33":5,"34":5,"35":5,"36":5,"37":5,"38":5,"39":5,"40":5,"41":5,"42":5,"43":5,"44":0,"45":0,"46":0,"47":0,"48":0,"49":0,"50":0,"51":0,"52":18,"53":6,"54":6,"55":6,"56":6,"57":0,"58":0,"59":0,"60":0,"61":0,"62":0,"63":0,"64":0,"65":0,"66":0,"67":0,"68":0,"69":0,"70":0,"71":0,"72":0,"73":0,"74":0,"75":0,"76":6,"77":0,"78":0,"79":0,"80":0,"81":0,"82":0,"83":0,"84":0,"85":0,"86":0,"87":0,"88":0,"89":0,"90":0,"91":0,"92":0,"93":0,"94":0,"95":0,"96":0,"97":0,"98":0,"99":1,"100":0,"101":0,"102":0,"103":0,"104":0,"105":0,"106":0,"107":0,"108":0,"109":0,"110":0,"111":0,"112":0,"113":0,"114":0,"115":32,"116":0,"117":1,"118":4,"119":0,"120":0,"121":0,"122":0,"123":0,"124":0,"125":0,"126":0,"127":0,"128":0,"129":0,"130":4,"131":5,"132":0,"133":0,"134":0,"135":5,"136":0,"137":0,"138":0,"139":0,"140":0,"141":0},"f":{"0":0,"1":0,"2":18,"3":6,"4":6,"5":6,"6":6,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0,"36":0,"37":0,"38":0,"39":0,"40":0,"41":0,"42":0,"43":0,"44":0,"45":0,"46":0,"47":1,"48":0,"49":0,"50":0,"51":0,"52":0,"53":0,"54":0,"55":0,"56":0,"57":0,"58":0,"59":0,"60":0,"61":0,"62":32,"63":0,"64":1,"65":4,"66":0,"67":0,"68":0,"69":0,"70":0,"71":0,"72":0,"73":0,"74":0,"75":0,"76":0,"77":4,"78":0,"79":0,"80":0,"81":0,"82":0,"83":0},"b":{"0":[0,0],"1":[0,0],"2":[0],"3":[0],"4":[0,0],"5":[0,0],"6":[0]}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/actions/createAction.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/actions/createAction.ts","statementMap":{"0":{"start":{"line":19,"column":20},"end":{"line":19,"column":30}},"1":{"start":{"line":20,"column":20},"end":{"line":20,"column":null}},"2":{"start":{"line":25,"column":13},"end":{"line":25,"column":null}},"3":{"start":{"line":29,"column":13},"end":{"line":29,"column":39}},"4":{"start":{"line":30,"column":11},"end":{"line":30,"column":23}},"5":{"start":{"line":47,"column":4},"end":{"line":52,"column":null}},"6":{"start":{"line":55,"column":35},"end":{"line":60,"column":3}},"7":{"start":{"line":56,"column":4},"end":{"line":59,"column":null}},"8":{"start":{"line":62,"column":8},"end":{"line":67,"column":3}},"9":{"start":{"line":63,"column":4},"end":{"line":66,"column":null}},"10":{"start":{"line":70,"column":4},"end":{"line":71,"column":null}},"11":{"start":{"line":71,"column":6},"end":{"line":71,"column":null}},"12":{"start":{"line":72,"column":4},"end":{"line":72,"column":null}},"13":{"start":{"line":76,"column":4},"end":{"line":79,"column":null}},"14":{"start":{"line":83,"column":4},"end":{"line":85,"column":null}},"15":{"start":{"line":9,"column":0},"end":{"line":9,"column":13}},"16":{"start":{"line":89,"column":13},"end":{"line":89,"column":null}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":18,"column":2},"end":{"line":18,"column":null}},"loc":{"start":{"line":30,"column":38},"end":{"line":31,"column":6}}},"1":{"name":"(anonymous_1)","decl":{"start":{"line":33,"column":2},"end":{"line":33,"column":8}},"loc":{"start":{"line":45,"column":58},"end":{"line":53,"column":3}}},"2":{"name":"(anonymous_2)","decl":{"start":{"line":55,"column":35},"end":{"line":55,"column":36}},"loc":{"start":{"line":55,"column":58},"end":{"line":60,"column":3}}},"3":{"name":"(anonymous_3)","decl":{"start":{"line":62,"column":8},"end":{"line":62,"column":13}},"loc":{"start":{"line":62,"column":73},"end":{"line":67,"column":3}}},"4":{"name":"(anonymous_4)","decl":{"start":{"line":69,"column":2},"end":{"line":69,"column":7}},"loc":{"start":{"line":69,"column":46},"end":{"line":73,"column":3}}},"5":{"name":"(anonymous_5)","decl":{"start":{"line":75,"column":2},"end":{"line":75,"column":7}},"loc":{"start":{"line":75,"column":52},"end":{"line":80,"column":3}}},"6":{"name":"(anonymous_6)","decl":{"start":{"line":82,"column":2},"end":{"line":82,"column":7}},"loc":{"start":{"line":82,"column":51},"end":{"line":86,"column":3}}}},"branchMap":{"0":{"loc":{"start":{"line":30,"column":11},"end":{"line":30,"column":38}},"type":"default-arg","locations":[{"start":{"line":30,"column":23},"end":{"line":30,"column":38}}]},"1":{"loc":{"start":{"line":70,"column":4},"end":{"line":71,"column":null}},"type":"if","locations":[{"start":{"line":70,"column":4},"end":{"line":71,"column":null}}]}},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":5,"16":5},"f":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0},"b":{"0":[0],"1":[0]}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/actions/setupActions.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/actions/setupActions.ts","statementMap":{"0":{"start":{"line":8,"column":20},"end":{"line":14,"column":3}},"1":{"start":{"line":9,"column":73},"end":{"line":9,"column":75}},"2":{"start":{"line":10,"column":4},"end":{"line":12,"column":null}},"3":{"start":{"line":11,"column":6},"end":{"line":11,"column":null}},"4":{"start":{"line":13,"column":4},"end":{"line":13,"column":null}},"5":{"start":{"line":18,"column":6},"end":{"line":27,"column":null}},"6":{"start":{"line":20,"column":6},"end":{"line":20,"column":null}},"7":{"start":{"line":23,"column":6},"end":{"line":25,"column":null}},"8":{"start":{"line":24,"column":34},"end":{"line":24,"column":63}},"9":{"start":{"line":28,"column":2},"end":{"line":28,"column":null}},"10":{"start":{"line":5,"column":0},"end":{"line":5,"column":16}}},"fnMap":{"0":{"name":"setupActions","decl":{"start":{"line":5,"column":16},"end":{"line":5,"column":28}},"loc":{"start":{"line":6,"column":58},"end":{"line":29,"column":1}}},"1":{"name":"(anonymous_1)","decl":{"start":{"line":8,"column":20},"end":{"line":8,"column":25}},"loc":{"start":{"line":8,"column":60},"end":{"line":14,"column":3}}},"2":{"name":"(anonymous_2)","decl":{"start":{"line":19,"column":4},"end":{"line":19,"column":11}},"loc":{"start":{"line":19,"column":41},"end":{"line":21,"column":5}}},"3":{"name":"(anonymous_3)","decl":{"start":{"line":22,"column":4},"end":{"line":22,"column":9}},"loc":{"start":{"line":22,"column":59},"end":{"line":26,"column":5}}},"4":{"name":"(anonymous_4)","decl":{"start":{"line":24,"column":27},"end":{"line":24,"column":28}},"loc":{"start":{"line":24,"column":34},"end":{"line":24,"column":63}}}},"branchMap":{},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":5},"f":{"0":0,"1":0,"2":0,"3":0,"4":0},"b":{}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/backup/Backups.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/backup/Backups.ts","statementMap":{"0":{"start":{"line":3,"column":0},"end":{"line":3,"column":46}},"1":{"start":{"line":5,"column":0},"end":{"line":5,"column":33}},"2":{"start":{"line":8,"column":13},"end":{"line":13,"column":null}},"3":{"start":{"line":44,"column":26},"end":{"line":44,"column":34}},"4":{"start":{"line":47,"column":12},"end":{"line":47,"column":22}},"5":{"start":{"line":48,"column":12},"end":{"line":48,"column":24}},"6":{"start":{"line":53,"column":4},"end":{"line":60,"column":null}},"7":{"start":{"line":54,"column":41},"end":{"line":59,"column":8}},"8":{"start":{"line":65,"column":4},"end":{"line":65,"column":null}},"9":{"start":{"line":70,"column":4},"end":{"line":70,"column":null}},"10":{"start":{"line":73,"column":23},"end":{"line":73,"column":43}},"11":{"start":{"line":75,"column":4},"end":{"line":78,"column":null}},"12":{"start":{"line":79,"column":4},"end":{"line":79,"column":null}},"13":{"start":{"line":82,"column":4},"end":{"line":89,"column":null}},"14":{"start":{"line":83,"column":41},"end":{"line":88,"column":8}},"15":{"start":{"line":92,"column":4},"end":{"line":94,"column":null}},"16":{"start":{"line":93,"column":6},"end":{"line":93,"column":79}},"17":{"start":{"line":95,"column":4},"end":{"line":95,"column":null}},"18":{"start":{"line":98,"column":57},"end":{"line":115,"column":5}},"19":{"start":{"line":101,"column":6},"end":{"line":113,"column":null}},"20":{"start":{"line":102,"column":29},"end":{"line":110,"column":null}},"21":{"start":{"line":112,"column":8},"end":{"line":112,"column":null}},"22":{"start":{"line":114,"column":6},"end":{"line":114,"column":12}},"23":{"start":{"line":116,"column":59},"end":{"line":133,"column":5}},"24":{"start":{"line":119,"column":6},"end":{"line":131,"column":null}},"25":{"start":{"line":120,"column":29},"end":{"line":128,"column":null}},"26":{"start":{"line":130,"column":8},"end":{"line":130,"column":null}},"27":{"start":{"line":132,"column":6},"end":{"line":132,"column":12}},"28":{"start":{"line":134,"column":4},"end":{"line":134,"column":null}},"29":{"start":{"line":43,"column":13},"end":{"line":43,"column":20}},"30":{"start":{"line":138,"column":2},"end":{"line":138,"column":null}},"31":{"start":{"line":154,"column":62},"end":{"line":154,"column":74}},"32":{"start":{"line":156,"column":18},"end":{"line":156,"column":25}},"33":{"start":{"line":157,"column":25},"end":{"line":157,"column":27}},"34":{"start":{"line":158,"column":2},"end":{"line":160,"column":null}},"35":{"start":{"line":159,"column":4},"end":{"line":159,"column":null}},"36":{"start":{"line":161,"column":2},"end":{"line":163,"column":null}},"37":{"start":{"line":162,"column":4},"end":{"line":162,"column":null}},"38":{"start":{"line":164,"column":2},"end":{"line":166,"column":null}},"39":{"start":{"line":165,"column":4},"end":{"line":165,"column":null}},"40":{"start":{"line":167,"column":2},"end":{"line":169,"column":null}},"41":{"start":{"line":168,"column":4},"end":{"line":168,"column":null}},"42":{"start":{"line":170,"column":2},"end":{"line":170,"column":null}},"43":{"start":{"line":171,"column":2},"end":{"line":171,"column":null}},"44":{"start":{"line":172,"column":2},"end":{"line":172,"column":null}},"45":{"start":{"line":173,"column":2},"end":{"line":173,"column":null}},"46":{"start":{"line":174,"column":2},"end":{"line":174,"column":null}},"47":{"start":{"line":175,"column":18},"end":{"line":175,"column":72}},"48":{"start":{"line":176,"column":19},"end":{"line":176,"column":22}},"49":{"start":{"line":177,"column":2},"end":{"line":184,"column":null}},"50":{"start":{"line":178,"column":18},"end":{"line":178,"column":62}},"51":{"start":{"line":179,"column":4},"end":{"line":183,"column":null}},"52":{"start":{"line":180,"column":21},"end":{"line":180,"column":50}},"53":{"start":{"line":181,"column":6},"end":{"line":181,"column":27}},"54":{"start":{"line":181,"column":19},"end":{"line":181,"column":27}},"55":{"start":{"line":182,"column":6},"end":{"line":182,"column":null}},"56":{"start":{"line":186,"column":2},"end":{"line":188,"column":null}},"57":{"start":{"line":187,"column":4},"end":{"line":187,"column":null}},"58":{"start":{"line":190,"column":13},"end":{"line":196,"column":3}},"59":{"start":{"line":191,"column":16},"end":{"line":191,"column":27}},"60":{"start":{"line":192,"column":4},"end":{"line":194,"column":null}},"61":{"start":{"line":193,"column":6},"end":{"line":193,"column":null}},"62":{"start":{"line":195,"column":4},"end":{"line":195,"column":null}},"63":{"start":{"line":197,"column":22},"end":{"line":205,"column":4}},"64":{"start":{"line":198,"column":4},"end":{"line":204,"column":null}},"65":{"start":{"line":199,"column":6},"end":{"line":203,"column":null}},"66":{"start":{"line":200,"column":8},"end":{"line":200,"column":null}},"67":{"start":{"line":202,"column":8},"end":{"line":202,"column":null}},"68":{"start":{"line":206,"column":15},"end":{"line":206,"column":32}},"69":{"start":{"line":206,"column":21},"end":{"line":206,"column":32}},"70":{"start":{"line":207,"column":19},"end":{"line":207,"column":52}},"71":{"start":{"line":207,"column":25},"end":{"line":207,"column":52}},"72":{"start":{"line":208,"column":2},"end":{"line":208,"column":null}}},"fnMap":{"0":{"name":"(anonymous_6)","decl":{"start":{"line":46,"column":2},"end":{"line":46,"column":null}},"loc":{"start":{"line":48,"column":63},"end":{"line":49,"column":6}}},"1":{"name":"(anonymous_7)","decl":{"start":{"line":50,"column":2},"end":{"line":50,"column":8}},"loc":{"start":{"line":51,"column":42},"end":{"line":61,"column":3}}},"2":{"name":"(anonymous_8)","decl":{"start":{"line":54,"column":25},"end":{"line":54,"column":26}},"loc":{"start":{"line":54,"column":41},"end":{"line":59,"column":8}}},"3":{"name":"(anonymous_9)","decl":{"start":{"line":62,"column":2},"end":{"line":62,"column":8}},"loc":{"start":{"line":63,"column":44},"end":{"line":66,"column":3}}},"4":{"name":"(anonymous_10)","decl":{"start":{"line":67,"column":2},"end":{"line":67,"column":8}},"loc":{"start":{"line":68,"column":38},"end":{"line":71,"column":3}}},"5":{"name":"(anonymous_11)","decl":{"start":{"line":74,"column":2},"end":{"line":74,"column":12}},"loc":{"start":{"line":74,"column":47},"end":{"line":80,"column":3}}},"6":{"name":"(anonymous_12)","decl":{"start":{"line":81,"column":2},"end":{"line":81,"column":9}},"loc":{"start":{"line":81,"column":48},"end":{"line":90,"column":3}}},"7":{"name":"(anonymous_13)","decl":{"start":{"line":83,"column":25},"end":{"line":83,"column":26}},"loc":{"start":{"line":83,"column":41},"end":{"line":88,"column":8}}},"8":{"name":"(anonymous_14)","decl":{"start":{"line":91,"column":2},"end":{"line":91,"column":9}},"loc":{"start":{"line":91,"column":50},"end":{"line":96,"column":3}}},"9":{"name":"(anonymous_15)","decl":{"start":{"line":92,"column":20},"end":{"line":92,"column":21}},"loc":{"start":{"line":93,"column":6},"end":{"line":93,"column":79}}},"10":{"name":"(anonymous_16)","decl":{"start":{"line":97,"column":2},"end":{"line":97,"column":7}},"loc":{"start":{"line":97,"column":30},"end":{"line":135,"column":3}}},"11":{"name":"(anonymous_17)","decl":{"start":{"line":98,"column":57},"end":{"line":98,"column":62}},"loc":{"start":{"line":100,"column":9},"end":{"line":115,"column":5}}},"12":{"name":"(anonymous_18)","decl":{"start":{"line":116,"column":59},"end":{"line":116,"column":64}},"loc":{"start":{"line":118,"column":9},"end":{"line":133,"column":5}}},"13":{"name":"notEmptyPath","decl":{"start":{"line":137,"column":9},"end":{"line":137,"column":21}},"loc":{"start":{"line":137,"column":34},"end":{"line":139,"column":1}}},"14":{"name":"runRsync","decl":{"start":{"line":140,"column":15},"end":{"line":140,"column":23}},"loc":{"start":{"line":148,"column":24},"end":{"line":209,"column":1}}},"15":{"name":"(anonymous_21)","decl":{"start":{"line":177,"column":28},"end":{"line":177,"column":29}},"loc":{"start":{"line":177,"column":46},"end":{"line":184,"column":3}}},"16":{"name":"(anonymous_22)","decl":{"start":{"line":186,"column":28},"end":{"line":186,"column":29}},"loc":{"start":{"line":186,"column":46},"end":{"line":188,"column":3}}},"17":{"name":"(anonymous_23)","decl":{"start":{"line":190,"column":13},"end":{"line":190,"column":18}},"loc":{"start":{"line":190,"column":24},"end":{"line":196,"column":3}}},"18":{"name":"(anonymous_24)","decl":{"start":{"line":197,"column":40},"end":{"line":197,"column":41}},"loc":{"start":{"line":197,"column":60},"end":{"line":205,"column":3}}},"19":{"name":"(anonymous_25)","decl":{"start":{"line":198,"column":23},"end":{"line":198,"column":24}},"loc":{"start":{"line":198,"column":37},"end":{"line":204,"column":5}}},"20":{"name":"(anonymous_26)","decl":{"start":{"line":206,"column":15},"end":{"line":206,"column":18}},"loc":{"start":{"line":206,"column":21},"end":{"line":206,"column":32}}},"21":{"name":"(anonymous_27)","decl":{"start":{"line":207,"column":19},"end":{"line":207,"column":22}},"loc":{"start":{"line":207,"column":25},"end":{"line":207,"column":52}}}},"branchMap":{"0":{"loc":{"start":{"line":47,"column":12},"end":{"line":47,"column":37}},"type":"default-arg","locations":[{"start":{"line":47,"column":22},"end":{"line":47,"column":37}}]},"1":{"loc":{"start":{"line":48,"column":12},"end":{"line":48,"column":63}},"type":"default-arg","locations":[{"start":{"line":48,"column":24},"end":{"line":48,"column":63}}]},"2":{"loc":{"start":{"line":158,"column":2},"end":{"line":160,"column":null}},"type":"if","locations":[{"start":{"line":158,"column":2},"end":{"line":160,"column":null}}]},"3":{"loc":{"start":{"line":161,"column":2},"end":{"line":163,"column":null}},"type":"if","locations":[{"start":{"line":161,"column":2},"end":{"line":163,"column":null}}]},"4":{"loc":{"start":{"line":164,"column":2},"end":{"line":166,"column":null}},"type":"if","locations":[{"start":{"line":164,"column":2},"end":{"line":166,"column":null}}]},"5":{"loc":{"start":{"line":181,"column":6},"end":{"line":181,"column":27}},"type":"if","locations":[{"start":{"line":181,"column":6},"end":{"line":181,"column":27}}]},"6":{"loc":{"start":{"line":192,"column":4},"end":{"line":194,"column":null}},"type":"if","locations":[{"start":{"line":192,"column":4},"end":{"line":194,"column":null}}]},"7":{"loc":{"start":{"line":199,"column":6},"end":{"line":203,"column":null}},"type":"if","locations":[{"start":{"line":199,"column":6},"end":{"line":203,"column":null}},{"start":{"line":201,"column":13},"end":{"line":203,"column":null}}]}},"s":{"0":5,"1":5,"2":5,"3":5,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":5,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":5,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0,"36":0,"37":0,"38":0,"39":0,"40":0,"41":0,"42":0,"43":0,"44":0,"45":0,"46":0,"47":0,"48":0,"49":0,"50":0,"51":0,"52":0,"53":0,"54":0,"55":0,"56":0,"57":0,"58":0,"59":0,"60":0,"61":0,"62":0,"63":0,"64":0,"65":0,"66":0,"67":0,"68":0,"69":0,"70":0,"71":0,"72":0},"f":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0},"b":{"0":[0],"1":[0],"2":[0],"3":[0],"4":[0],"5":[0],"6":[0],"7":[0,0]}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/backup/setupBackups.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/backup/setupBackups.ts","statementMap":{"0":{"start":{"line":1,"column":0},"end":{"line":1,"column":35}},"1":{"start":{"line":14,"column":18},"end":{"line":14,"column":37}},"2":{"start":{"line":15,"column":18},"end":{"line":15,"column":44}},"3":{"start":{"line":16,"column":2},"end":{"line":22,"column":null}},"4":{"start":{"line":17,"column":4},"end":{"line":21,"column":null}},"5":{"start":{"line":18,"column":6},"end":{"line":18,"column":null}},"6":{"start":{"line":20,"column":6},"end":{"line":20,"column":null}},"7":{"start":{"line":23,"column":2},"end":{"line":23,"column":null}},"8":{"start":{"line":27,"column":6},"end":{"line":43,"column":null}},"9":{"start":{"line":29,"column":6},"end":{"line":33,"column":null}},"10":{"start":{"line":30,"column":8},"end":{"line":32,"column":null}},"11":{"start":{"line":31,"column":10},"end":{"line":31,"column":null}},"12":{"start":{"line":36,"column":6},"end":{"line":41,"column":null}},"13":{"start":{"line":37,"column":8},"end":{"line":39,"column":null}},"14":{"start":{"line":38,"column":10},"end":{"line":38,"column":null}},"15":{"start":{"line":40,"column":8},"end":{"line":40,"column":null}},"16":{"start":{"line":44,"column":2},"end":{"line":44,"column":null}},"17":{"start":{"line":10,"column":0},"end":{"line":10,"column":16}}},"fnMap":{"0":{"name":"setupBackups","decl":{"start":{"line":10,"column":16},"end":{"line":10,"column":28}},"loc":{"start":{"line":12,"column":35},"end":{"line":45,"column":1}}},"1":{"name":"(anonymous_1)","decl":{"start":{"line":28,"column":4},"end":{"line":28,"column":8}},"loc":{"start":{"line":28,"column":20},"end":{"line":34,"column":5}}},"2":{"name":"(anonymous_2)","decl":{"start":{"line":29,"column":14},"end":{"line":29,"column":19}},"loc":{"start":{"line":29,"column":32},"end":{"line":33,"column":7}}},"3":{"name":"(anonymous_3)","decl":{"start":{"line":35,"column":4},"end":{"line":35,"column":8}},"loc":{"start":{"line":35,"column":21},"end":{"line":42,"column":5}}},"4":{"name":"(anonymous_4)","decl":{"start":{"line":36,"column":14},"end":{"line":36,"column":19}},"loc":{"start":{"line":36,"column":32},"end":{"line":41,"column":7}}}},"branchMap":{"0":{"loc":{"start":{"line":17,"column":4},"end":{"line":21,"column":null}},"type":"if","locations":[{"start":{"line":17,"column":4},"end":{"line":21,"column":null}},{"start":{"line":19,"column":11},"end":{"line":21,"column":null}}]}},"s":{"0":5,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":5},"f":{"0":0,"1":0,"2":0,"3":0,"4":0},"b":{"0":[0,0]}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/config/configConstants.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/config/configConstants.ts","statementMap":{"0":{"start":{"line":2,"column":0},"end":{"line":2,"column":53}},"1":{"start":{"line":3,"column":0},"end":{"line":3,"column":40}},"2":{"start":{"line":4,"column":0},"end":{"line":4,"column":55}},"3":{"start":{"line":5,"column":0},"end":{"line":5,"column":39}},"4":{"start":{"line":6,"column":0},"end":{"line":6,"column":45}},"5":{"start":{"line":11,"column":13},"end":{"line":45,"column":null}},"6":{"start":{"line":50,"column":13},"end":{"line":81,"column":null}},"7":{"start":{"line":52,"column":17},"end":{"line":52,"column":56}},"8":{"start":{"line":53,"column":4},"end":{"line":53,"column":null}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":51,"column":2},"end":{"line":51,"column":7}},"loc":{"start":{"line":51,"column":24},"end":{"line":54,"column":3}}}},"branchMap":{"0":{"loc":{"start":{"line":53,"column":11},"end":{"line":53,"column":33}},"type":"cond-expr","locations":[{"start":{"line":53,"column":18},"end":{"line":53,"column":20}},{"start":{"line":53,"column":23},"end":{"line":53,"column":33}}]}},"s":{"0":5,"1":5,"2":5,"3":5,"4":5,"5":5,"6":5,"7":0,"8":0},"f":{"0":0},"b":{"0":[0,0]}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/config/configTypes.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/config/configTypes.ts","statementMap":{"0":{"start":{"line":271,"column":2},"end":{"line":271,"column":null}},"1":{"start":{"line":267,"column":0},"end":{"line":267,"column":16}}},"fnMap":{"0":{"name":"isValueSpecListOf","decl":{"start":{"line":267,"column":16},"end":{"line":267,"column":33}},"loc":{"start":{"line":269,"column":6},"end":{"line":272,"column":1}}}},"branchMap":{"0":{"loc":{"start":{"line":271,"column":9},"end":{"line":271,"column":41}},"type":"binary-expr","locations":[{"start":{"line":271,"column":9},"end":{"line":271,"column":20}},{"start":{"line":271,"column":24},"end":{"line":271,"column":41}}]}},"s":{"0":3,"1":1},"f":{"0":3},"b":{"0":[3,3]}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/config/setupConfig.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/config/setupConfig.ts","statementMap":{"0":{"start":{"line":5,"column":0},"end":{"line":5,"column":45}},"1":{"start":{"line":56,"column":20},"end":{"line":56,"column":34}},"2":{"start":{"line":57,"column":2},"end":{"line":84,"column":null}},"3":{"start":{"line":59,"column":6},"end":{"line":64,"column":null}},"4":{"start":{"line":60,"column":8},"end":{"line":62,"column":null}},"5":{"start":{"line":63,"column":8},"end":{"line":63,"column":null}},"6":{"start":{"line":65,"column":6},"end":{"line":65,"column":null}},"7":{"start":{"line":66,"column":6},"end":{"line":66,"column":null}},"8":{"start":{"line":67,"column":26},"end":{"line":70,"column":8}},"9":{"start":{"line":71,"column":6},"end":{"line":73,"column":null}},"10":{"start":{"line":72,"column":8},"end":{"line":72,"column":null}},"11":{"start":{"line":76,"column":26},"end":{"line":76,"column":72}},"12":{"start":{"line":77,"column":6},"end":{"line":82,"column":null}},"13":{"start":{"line":43,"column":0},"end":{"line":43,"column":16}},"14":{"start":{"line":87,"column":0},"end":{"line":87,"column":null}}},"fnMap":{"0":{"name":"setupConfig","decl":{"start":{"line":43,"column":16},"end":{"line":43,"column":27}},"loc":{"start":{"line":54,"column":35},"end":{"line":85,"column":1}}},"1":{"name":"(anonymous_2)","decl":{"start":{"line":58,"column":16},"end":{"line":58,"column":21}},"loc":{"start":{"line":58,"column":45},"end":{"line":74,"column":5}}},"2":{"name":"(anonymous_3)","decl":{"start":{"line":75,"column":16},"end":{"line":75,"column":21}},"loc":{"start":{"line":75,"column":38},"end":{"line":83,"column":5}}}},"branchMap":{"0":{"loc":{"start":{"line":59,"column":6},"end":{"line":64,"column":null}},"type":"if","locations":[{"start":{"line":59,"column":6},"end":{"line":64,"column":null}}]},"1":{"loc":{"start":{"line":71,"column":6},"end":{"line":73,"column":null}},"type":"if","locations":[{"start":{"line":71,"column":6},"end":{"line":73,"column":null}}]},"2":{"loc":{"start":{"line":76,"column":38},"end":{"line":76,"column":71}},"type":"binary-expr","locations":[{"start":{"line":76,"column":39},"end":{"line":76,"column":62}},{"start":{"line":76,"column":67},"end":{"line":76,"column":71}}]}},"s":{"0":5,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":5,"14":5},"f":{"0":0,"1":0,"2":0},"b":{"0":[0],"1":[0],"2":[0,0]}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/config/builder/config.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/config/builder/config.ts","statementMap":{"0":{"start":{"line":5,"column":0},"end":{"line":5,"column":43}},"1":{"start":{"line":82,"column":21},"end":{"line":82,"column":null}},"2":{"start":{"line":85,"column":11},"end":{"line":85,"column":43}},"3":{"start":{"line":88,"column":19},"end":{"line":88,"column":null}},"4":{"start":{"line":91,"column":4},"end":{"line":93,"column":null}},"5":{"start":{"line":92,"column":6},"end":{"line":92,"column":null}},"6":{"start":{"line":94,"column":4},"end":{"line":94,"column":null}},"7":{"start":{"line":101,"column":25},"end":{"line":101,"column":null}},"8":{"start":{"line":104,"column":4},"end":{"line":106,"column":null}},"9":{"start":{"line":105,"column":6},"end":{"line":105,"column":null}},"10":{"start":{"line":107,"column":22},"end":{"line":107,"column":42}},"11":{"start":{"line":108,"column":4},"end":{"line":117,"column":null}},"12":{"start":{"line":135,"column":4},"end":{"line":135,"column":null}},"13":{"start":{"line":80,"column":0},"end":{"line":80,"column":13}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":81,"column":2},"end":{"line":81,"column":null}},"loc":{"start":{"line":85,"column":43},"end":{"line":86,"column":6}}},"1":{"name":"(anonymous_1)","decl":{"start":{"line":87,"column":2},"end":{"line":87,"column":7}},"loc":{"start":{"line":87,"column":46},"end":{"line":95,"column":3}}},"2":{"name":"(anonymous_2)","decl":{"start":{"line":97,"column":2},"end":{"line":97,"column":8}},"loc":{"start":{"line":100,"column":14},"end":{"line":118,"column":3}}},"3":{"name":"(anonymous_3)","decl":{"start":{"line":134,"column":2},"end":{"line":134,"column":11}},"loc":{"start":{"line":134,"column":11},"end":{"line":136,"column":3}}}},"branchMap":{},"s":{"0":6,"1":62,"2":62,"3":6,"4":6,"5":5,"6":6,"7":62,"8":62,"9":131,"10":62,"11":62,"12":0,"13":6},"f":{"0":62,"1":6,"2":62,"3":0},"b":{}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/config/builder/list.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/config/builder/list.ts","statementMap":{"0":{"start":{"line":10,"column":0},"end":{"line":10,"column":60}},"1":{"start":{"line":26,"column":11},"end":{"line":26,"column":49}},"2":{"start":{"line":27,"column":11},"end":{"line":27,"column":43}},"3":{"start":{"line":51,"column":4},"end":{"line":74,"column":null}},"4":{"start":{"line":52,"column":19},"end":{"line":61,"column":null}},"5":{"start":{"line":62,"column":45},"end":{"line":72,"column":null}},"6":{"start":{"line":73,"column":6},"end":{"line":73,"column":null}},"7":{"start":{"line":102,"column":4},"end":{"line":126,"column":null}},"8":{"start":{"line":103,"column":36},"end":{"line":103,"column":55}},"9":{"start":{"line":104,"column":19},"end":{"line":113,"column":null}},"10":{"start":{"line":114,"column":45},"end":{"line":124,"column":null}},"11":{"start":{"line":125,"column":6},"end":{"line":125,"column":null}},"12":{"start":{"line":144,"column":4},"end":{"line":168,"column":null}},"13":{"start":{"line":145,"column":54},"end":{"line":145,"column":59}},"14":{"start":{"line":146,"column":23},"end":{"line":146,"column":60}},"15":{"start":{"line":147,"column":19},"end":{"line":153,"column":null}},"16":{"start":{"line":154,"column":20},"end":{"line":158,"column":null}},"17":{"start":{"line":159,"column":6},"end":{"line":167,"column":null}},"18":{"start":{"line":186,"column":4},"end":{"line":186,"column":null}},"19":{"start":{"line":24,"column":0},"end":{"line":24,"column":13}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":25,"column":2},"end":{"line":25,"column":null}},"loc":{"start":{"line":27,"column":43},"end":{"line":28,"column":6}}},"1":{"name":"(anonymous_1)","decl":{"start":{"line":29,"column":2},"end":{"line":29,"column":8}},"loc":{"start":{"line":49,"column":5},"end":{"line":75,"column":3}}},"2":{"name":"(anonymous_2)","decl":{"start":{"line":51,"column":37},"end":{"line":51,"column":40}},"loc":{"start":{"line":51,"column":42},"end":{"line":74,"column":5}}},"3":{"name":"(anonymous_3)","decl":{"start":{"line":76,"column":2},"end":{"line":76,"column":8}},"loc":{"start":{"line":100,"column":5},"end":{"line":127,"column":3}}},"4":{"name":"(anonymous_4)","decl":{"start":{"line":102,"column":37},"end":{"line":102,"column":42}},"loc":{"start":{"line":102,"column":55},"end":{"line":126,"column":5}}},"5":{"name":"(anonymous_5)","decl":{"start":{"line":128,"column":2},"end":{"line":128,"column":8}},"loc":{"start":{"line":142,"column":5},"end":{"line":169,"column":3}}},"6":{"name":"(anonymous_6)","decl":{"start":{"line":144,"column":35},"end":{"line":144,"column":40}},"loc":{"start":{"line":144,"column":53},"end":{"line":168,"column":5}}},"7":{"name":"(anonymous_7)","decl":{"start":{"line":185,"column":2},"end":{"line":185,"column":11}},"loc":{"start":{"line":185,"column":11},"end":{"line":187,"column":3}}}},"branchMap":{},"s":{"0":6,"1":11,"2":11,"3":4,"4":1,"5":1,"6":1,"7":1,"8":1,"9":1,"10":1,"11":1,"12":6,"13":1,"14":1,"15":1,"16":1,"17":1,"18":0,"19":6},"f":{"0":11,"1":4,"2":1,"3":1,"4":1,"5":6,"6":1,"7":0},"b":{}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/config/builder/value.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/config/builder/value.ts","statementMap":{"0":{"start":{"line":15,"column":0},"end":{"line":15,"column":null}},"1":{"start":{"line":27,"column":0},"end":{"line":27,"column":38}},"2":{"start":{"line":39,"column":2},"end":{"line":49,"column":4}},"3":{"start":{"line":62,"column":32},"end":{"line":63,"column":null}},"4":{"start":{"line":63,"column":8},"end":{"line":63,"column":63}},"5":{"start":{"line":72,"column":2},"end":{"line":72,"column":null}},"6":{"start":{"line":72,"column":40},"end":{"line":72,"column":null}},"7":{"start":{"line":73,"column":2},"end":{"line":73,"column":null}},"8":{"start":{"line":100,"column":11},"end":{"line":100,"column":45}},"9":{"start":{"line":101,"column":11},"end":{"line":101,"column":43}},"10":{"start":{"line":112,"column":4},"end":{"line":122,"column":null}},"11":{"start":{"line":113,"column":19},"end":{"line":120,"column":8}},"12":{"start":{"line":136,"column":4},"end":{"line":146,"column":null}},"13":{"start":{"line":137,"column":26},"end":{"line":144,"column":8}},"14":{"start":{"line":168,"column":4},"end":{"line":186,"column":null}},"15":{"start":{"line":169,"column":19},"end":{"line":184,"column":8}},"16":{"start":{"line":213,"column":4},"end":{"line":231,"column":null}},"17":{"start":{"line":214,"column":16},"end":{"line":214,"column":35}},"18":{"start":{"line":215,"column":6},"end":{"line":230,"column":null}},"19":{"start":{"line":245,"column":4},"end":{"line":258,"column":null}},"20":{"start":{"line":246,"column":39},"end":{"line":256,"column":null}},"21":{"start":{"line":257,"column":6},"end":{"line":257,"column":null}},"22":{"start":{"line":275,"column":4},"end":{"line":288,"column":null}},"23":{"start":{"line":276,"column":16},"end":{"line":276,"column":35}},"24":{"start":{"line":277,"column":6},"end":{"line":287,"column":null}},"25":{"start":{"line":306,"column":4},"end":{"line":322,"column":null}},"26":{"start":{"line":307,"column":13},"end":{"line":320,"column":8}},"27":{"start":{"line":343,"column":4},"end":{"line":359,"column":null}},"28":{"start":{"line":344,"column":16},"end":{"line":344,"column":35}},"29":{"start":{"line":345,"column":6},"end":{"line":358,"column":null}},"30":{"start":{"line":370,"column":4},"end":{"line":382,"column":null}},"31":{"start":{"line":371,"column":13},"end":{"line":379,"column":8}},"32":{"start":{"line":397,"column":4},"end":{"line":408,"column":null}},"33":{"start":{"line":398,"column":16},"end":{"line":398,"column":35}},"34":{"start":{"line":399,"column":6},"end":{"line":407,"column":null}},"35":{"start":{"line":423,"column":4},"end":{"line":438,"column":null}},"36":{"start":{"line":424,"column":13},"end":{"line":436,"column":8}},"37":{"start":{"line":456,"column":4},"end":{"line":470,"column":null}},"38":{"start":{"line":457,"column":16},"end":{"line":457,"column":35}},"39":{"start":{"line":458,"column":6},"end":{"line":469,"column":null}},"40":{"start":{"line":491,"column":4},"end":{"line":507,"column":null}},"41":{"start":{"line":492,"column":13},"end":{"line":500,"column":8}},"42":{"start":{"line":503,"column":64},"end":{"line":503,"column":74}},"43":{"start":{"line":527,"column":4},"end":{"line":538,"column":null}},"44":{"start":{"line":528,"column":16},"end":{"line":528,"column":35}},"45":{"start":{"line":529,"column":6},"end":{"line":537,"column":null}},"46":{"start":{"line":558,"column":4},"end":{"line":572,"column":null}},"47":{"start":{"line":559,"column":13},"end":{"line":568,"column":8}},"48":{"start":{"line":594,"column":4},"end":{"line":606,"column":null}},"49":{"start":{"line":595,"column":16},"end":{"line":595,"column":35}},"50":{"start":{"line":596,"column":6},"end":{"line":605,"column":null}},"51":{"start":{"line":616,"column":4},"end":{"line":625,"column":null}},"52":{"start":{"line":617,"column":20},"end":{"line":617,"column":52}},"53":{"start":{"line":618,"column":6},"end":{"line":624,"column":null}},"54":{"start":{"line":634,"column":23},"end":{"line":639,"column":null}},"55":{"start":{"line":640,"column":4},"end":{"line":647,"column":null}},"56":{"start":{"line":641,"column":13},"end":{"line":645,"column":8}},"57":{"start":{"line":661,"column":4},"end":{"line":669,"column":null}},"58":{"start":{"line":662,"column":26},"end":{"line":667,"column":8}},"59":{"start":{"line":689,"column":4},"end":{"line":701,"column":null}},"60":{"start":{"line":690,"column":26},"end":{"line":699,"column":8}},"61":{"start":{"line":717,"column":4},"end":{"line":729,"column":null}},"62":{"start":{"line":718,"column":26},"end":{"line":727,"column":8}},"63":{"start":{"line":748,"column":4},"end":{"line":759,"column":null}},"64":{"start":{"line":749,"column":24},"end":{"line":749,"column":43}},"65":{"start":{"line":750,"column":6},"end":{"line":758,"column":null}},"66":{"start":{"line":763,"column":4},"end":{"line":763,"column":null}},"67":{"start":{"line":763,"column":47},"end":{"line":763,"column":63}},"68":{"start":{"line":781,"column":4},"end":{"line":781,"column":null}},"69":{"start":{"line":98,"column":0},"end":{"line":98,"column":13}}},"fnMap":{"0":{"name":"requiredLikeToAbove","decl":{"start":{"line":35,"column":9},"end":{"line":35,"column":28}},"loc":{"start":{"line":36,"column":21},"end":{"line":50,"column":1}}},"1":{"name":"(anonymous_1)","decl":{"start":{"line":63,"column":2},"end":{"line":63,"column":5}},"loc":{"start":{"line":63,"column":8},"end":{"line":63,"column":63}}},"2":{"name":"asRequiredParser","decl":{"start":{"line":65,"column":9},"end":{"line":65,"column":25}},"loc":{"start":{"line":71,"column":45},"end":{"line":74,"column":1}}},"3":{"name":"(anonymous_3)","decl":{"start":{"line":99,"column":2},"end":{"line":99,"column":null}},"loc":{"start":{"line":101,"column":43},"end":{"line":102,"column":6}}},"4":{"name":"(anonymous_4)","decl":{"start":{"line":103,"column":2},"end":{"line":103,"column":8}},"loc":{"start":{"line":111,"column":3},"end":{"line":123,"column":3}}},"5":{"name":"(anonymous_5)","decl":{"start":{"line":113,"column":6},"end":{"line":113,"column":11}},"loc":{"start":{"line":113,"column":19},"end":{"line":120,"column":8}}},"6":{"name":"(anonymous_6)","decl":{"start":{"line":124,"column":2},"end":{"line":124,"column":8}},"loc":{"start":{"line":134,"column":5},"end":{"line":147,"column":3}}},"7":{"name":"(anonymous_7)","decl":{"start":{"line":137,"column":6},"end":{"line":137,"column":11}},"loc":{"start":{"line":137,"column":26},"end":{"line":144,"column":8}}},"8":{"name":"(anonymous_8)","decl":{"start":{"line":148,"column":2},"end":{"line":148,"column":8}},"loc":{"start":{"line":167,"column":3},"end":{"line":187,"column":3}}},"9":{"name":"(anonymous_9)","decl":{"start":{"line":169,"column":6},"end":{"line":169,"column":11}},"loc":{"start":{"line":169,"column":19},"end":{"line":184,"column":8}}},"10":{"name":"(anonymous_10)","decl":{"start":{"line":188,"column":2},"end":{"line":188,"column":8}},"loc":{"start":{"line":211,"column":5},"end":{"line":232,"column":3}}},"11":{"name":"(anonymous_11)","decl":{"start":{"line":213,"column":55},"end":{"line":213,"column":60}},"loc":{"start":{"line":213,"column":73},"end":{"line":231,"column":5}}},"12":{"name":"(anonymous_12)","decl":{"start":{"line":233,"column":2},"end":{"line":233,"column":8}},"loc":{"start":{"line":244,"column":3},"end":{"line":259,"column":3}}},"13":{"name":"(anonymous_13)","decl":{"start":{"line":245,"column":36},"end":{"line":245,"column":41}},"loc":{"start":{"line":245,"column":47},"end":{"line":258,"column":5}}},"14":{"name":"(anonymous_14)","decl":{"start":{"line":260,"column":2},"end":{"line":260,"column":8}},"loc":{"start":{"line":273,"column":5},"end":{"line":289,"column":3}}},"15":{"name":"(anonymous_15)","decl":{"start":{"line":275,"column":36},"end":{"line":275,"column":41}},"loc":{"start":{"line":275,"column":54},"end":{"line":288,"column":5}}},"16":{"name":"(anonymous_16)","decl":{"start":{"line":290,"column":2},"end":{"line":290,"column":8}},"loc":{"start":{"line":305,"column":3},"end":{"line":323,"column":3}}},"17":{"name":"(anonymous_17)","decl":{"start":{"line":307,"column":6},"end":{"line":307,"column":9}},"loc":{"start":{"line":307,"column":13},"end":{"line":320,"column":8}}},"18":{"name":"(anonymous_18)","decl":{"start":{"line":324,"column":2},"end":{"line":324,"column":8}},"loc":{"start":{"line":341,"column":5},"end":{"line":360,"column":3}}},"19":{"name":"(anonymous_19)","decl":{"start":{"line":343,"column":55},"end":{"line":343,"column":60}},"loc":{"start":{"line":343,"column":73},"end":{"line":359,"column":5}}},"20":{"name":"(anonymous_20)","decl":{"start":{"line":361,"column":2},"end":{"line":361,"column":8}},"loc":{"start":{"line":369,"column":3},"end":{"line":383,"column":3}}},"21":{"name":"(anonymous_21)","decl":{"start":{"line":371,"column":6},"end":{"line":371,"column":9}},"loc":{"start":{"line":371,"column":13},"end":{"line":379,"column":8}}},"22":{"name":"(anonymous_22)","decl":{"start":{"line":385,"column":2},"end":{"line":385,"column":8}},"loc":{"start":{"line":395,"column":5},"end":{"line":409,"column":3}}},"23":{"name":"(anonymous_23)","decl":{"start":{"line":397,"column":55},"end":{"line":397,"column":60}},"loc":{"start":{"line":397,"column":73},"end":{"line":408,"column":5}}},"24":{"name":"(anonymous_24)","decl":{"start":{"line":410,"column":2},"end":{"line":410,"column":8}},"loc":{"start":{"line":422,"column":3},"end":{"line":439,"column":3}}},"25":{"name":"(anonymous_25)","decl":{"start":{"line":424,"column":6},"end":{"line":424,"column":9}},"loc":{"start":{"line":424,"column":13},"end":{"line":436,"column":8}}},"26":{"name":"(anonymous_26)","decl":{"start":{"line":440,"column":2},"end":{"line":440,"column":8}},"loc":{"start":{"line":454,"column":5},"end":{"line":471,"column":3}}},"27":{"name":"(anonymous_27)","decl":{"start":{"line":456,"column":55},"end":{"line":456,"column":60}},"loc":{"start":{"line":456,"column":73},"end":{"line":470,"column":5}}},"28":{"name":"(anonymous_28)","decl":{"start":{"line":472,"column":2},"end":{"line":472,"column":8}},"loc":{"start":{"line":490,"column":3},"end":{"line":508,"column":3}}},"29":{"name":"(anonymous_29)","decl":{"start":{"line":492,"column":6},"end":{"line":492,"column":9}},"loc":{"start":{"line":492,"column":13},"end":{"line":500,"column":8}}},"30":{"name":"(anonymous_30)","decl":{"start":{"line":503,"column":39},"end":{"line":503,"column":40}},"loc":{"start":{"line":503,"column":64},"end":{"line":503,"column":74}}},"31":{"name":"(anonymous_31)","decl":{"start":{"line":509,"column":2},"end":{"line":509,"column":8}},"loc":{"start":{"line":525,"column":5},"end":{"line":539,"column":3}}},"32":{"name":"(anonymous_32)","decl":{"start":{"line":527,"column":55},"end":{"line":527,"column":60}},"loc":{"start":{"line":527,"column":73},"end":{"line":538,"column":5}}},"33":{"name":"(anonymous_33)","decl":{"start":{"line":540,"column":2},"end":{"line":540,"column":8}},"loc":{"start":{"line":557,"column":3},"end":{"line":573,"column":3}}},"34":{"name":"(anonymous_34)","decl":{"start":{"line":559,"column":6},"end":{"line":559,"column":9}},"loc":{"start":{"line":559,"column":13},"end":{"line":568,"column":8}}},"35":{"name":"(anonymous_35)","decl":{"start":{"line":574,"column":2},"end":{"line":574,"column":8}},"loc":{"start":{"line":592,"column":5},"end":{"line":607,"column":3}}},"36":{"name":"(anonymous_36)","decl":{"start":{"line":594,"column":38},"end":{"line":594,"column":43}},"loc":{"start":{"line":594,"column":56},"end":{"line":606,"column":5}}},"37":{"name":"(anonymous_37)","decl":{"start":{"line":608,"column":2},"end":{"line":608,"column":8}},"loc":{"start":{"line":614,"column":29},"end":{"line":626,"column":3}}},"38":{"name":"(anonymous_38)","decl":{"start":{"line":616,"column":34},"end":{"line":616,"column":39}},"loc":{"start":{"line":616,"column":52},"end":{"line":625,"column":5}}},"39":{"name":"(anonymous_39)","decl":{"start":{"line":627,"column":2},"end":{"line":627,"column":8}},"loc":{"start":{"line":633,"column":3},"end":{"line":648,"column":3}}},"40":{"name":"(anonymous_40)","decl":{"start":{"line":641,"column":6},"end":{"line":641,"column":9}},"loc":{"start":{"line":641,"column":13},"end":{"line":645,"column":8}}},"41":{"name":"(anonymous_41)","decl":{"start":{"line":649,"column":2},"end":{"line":649,"column":8}},"loc":{"start":{"line":659,"column":5},"end":{"line":670,"column":3}}},"42":{"name":"(anonymous_42)","decl":{"start":{"line":662,"column":6},"end":{"line":662,"column":11}},"loc":{"start":{"line":662,"column":26},"end":{"line":667,"column":8}}},"43":{"name":"(anonymous_43)","decl":{"start":{"line":671,"column":2},"end":{"line":671,"column":8}},"loc":{"start":{"line":687,"column":36},"end":{"line":702,"column":3}}},"44":{"name":"(anonymous_44)","decl":{"start":{"line":690,"column":6},"end":{"line":690,"column":11}},"loc":{"start":{"line":690,"column":26},"end":{"line":699,"column":8}}},"45":{"name":"(anonymous_45)","decl":{"start":{"line":703,"column":2},"end":{"line":703,"column":8}},"loc":{"start":{"line":715,"column":60},"end":{"line":730,"column":3}}},"46":{"name":"(anonymous_46)","decl":{"start":{"line":718,"column":6},"end":{"line":718,"column":11}},"loc":{"start":{"line":718,"column":26},"end":{"line":727,"column":8}}},"47":{"name":"(anonymous_47)","decl":{"start":{"line":731,"column":2},"end":{"line":731,"column":8}},"loc":{"start":{"line":746,"column":60},"end":{"line":760,"column":3}}},"48":{"name":"(anonymous_48)","decl":{"start":{"line":748,"column":53},"end":{"line":748,"column":58}},"loc":{"start":{"line":748,"column":71},"end":{"line":759,"column":5}}},"49":{"name":"(anonymous_49)","decl":{"start":{"line":762,"column":2},"end":{"line":762,"column":8}},"loc":{"start":{"line":762,"column":47},"end":{"line":764,"column":3}}},"50":{"name":"(anonymous_50)","decl":{"start":{"line":763,"column":34},"end":{"line":763,"column":35}},"loc":{"start":{"line":763,"column":47},"end":{"line":763,"column":63}}},"51":{"name":"(anonymous_51)","decl":{"start":{"line":780,"column":2},"end":{"line":780,"column":11}},"loc":{"start":{"line":780,"column":11},"end":{"line":782,"column":3}}}},"branchMap":{"0":{"loc":{"start":{"line":40,"column":15},"end":{"line":40,"column":69}},"type":"cond-expr","locations":[{"start":{"line":40,"column":50},"end":{"line":40,"column":54}},{"start":{"line":40,"column":57},"end":{"line":40,"column":69}}]},"1":{"loc":{"start":{"line":45,"column":13},"end":{"line":45,"column":75}},"type":"cond-expr","locations":[{"start":{"line":45,"column":48},"end":{"line":45,"column":68}},{"start":{"line":45,"column":71},"end":{"line":45,"column":75}}]},"2":{"loc":{"start":{"line":72,"column":2},"end":{"line":72,"column":null}},"type":"if","locations":[{"start":{"line":72,"column":2},"end":{"line":72,"column":null}}]},"3":{"loc":{"start":{"line":118,"column":19},"end":{"line":118,"column":39}},"type":"binary-expr","locations":[{"start":{"line":118,"column":19},"end":{"line":118,"column":30}},{"start":{"line":118,"column":34},"end":{"line":118,"column":39}}]},"4":{"loc":{"start":{"line":180,"column":19},"end":{"line":180,"column":39}},"type":"binary-expr","locations":[{"start":{"line":180,"column":19},"end":{"line":180,"column":30}},{"start":{"line":180,"column":34},"end":{"line":180,"column":39}}]},"5":{"loc":{"start":{"line":181,"column":18},"end":{"line":181,"column":36}},"type":"binary-expr","locations":[{"start":{"line":181,"column":18},"end":{"line":181,"column":28}},{"start":{"line":181,"column":32},"end":{"line":181,"column":36}}]},"6":{"loc":{"start":{"line":227,"column":18},"end":{"line":227,"column":36}},"type":"binary-expr","locations":[{"start":{"line":227,"column":18},"end":{"line":227,"column":28}},{"start":{"line":227,"column":32},"end":{"line":227,"column":36}}]},"7":{"loc":{"start":{"line":254,"column":19},"end":{"line":254,"column":39}},"type":"binary-expr","locations":[{"start":{"line":254,"column":19},"end":{"line":254,"column":30}},{"start":{"line":254,"column":34},"end":{"line":254,"column":39}}]},"8":{"loc":{"start":{"line":317,"column":19},"end":{"line":317,"column":39}},"type":"binary-expr","locations":[{"start":{"line":317,"column":19},"end":{"line":317,"column":30}},{"start":{"line":317,"column":34},"end":{"line":317,"column":39}}]},"9":{"loc":{"start":{"line":376,"column":19},"end":{"line":376,"column":39}},"type":"binary-expr","locations":[{"start":{"line":376,"column":19},"end":{"line":376,"column":30}},{"start":{"line":376,"column":34},"end":{"line":376,"column":39}}]},"10":{"loc":{"start":{"line":433,"column":19},"end":{"line":433,"column":39}},"type":"binary-expr","locations":[{"start":{"line":433,"column":19},"end":{"line":433,"column":30}},{"start":{"line":433,"column":34},"end":{"line":433,"column":39}}]},"11":{"loc":{"start":{"line":497,"column":19},"end":{"line":497,"column":39}},"type":"binary-expr","locations":[{"start":{"line":497,"column":19},"end":{"line":497,"column":30}},{"start":{"line":497,"column":34},"end":{"line":497,"column":39}}]},"12":{"loc":{"start":{"line":566,"column":19},"end":{"line":566,"column":39}},"type":"binary-expr","locations":[{"start":{"line":566,"column":19},"end":{"line":566,"column":30}},{"start":{"line":566,"column":34},"end":{"line":566,"column":39}}]},"13":{"loc":{"start":{"line":698,"column":19},"end":{"line":698,"column":39}},"type":"binary-expr","locations":[{"start":{"line":698,"column":19},"end":{"line":698,"column":30}},{"start":{"line":698,"column":34},"end":{"line":698,"column":39}}]},"14":{"loc":{"start":{"line":725,"column":18},"end":{"line":725,"column":57}},"type":"binary-expr","locations":[{"start":{"line":725,"column":19},"end":{"line":725,"column":47}},{"start":{"line":725,"column":52},"end":{"line":725,"column":57}}]}},"s":{"0":6,"1":6,"2":16,"3":6,"4":5,"5":89,"6":61,"7":28,"8":169,"9":169,"10":34,"11":4,"12":1,"13":1,"14":40,"15":4,"16":3,"17":5,"18":5,"19":3,"20":0,"21":0,"22":1,"23":1,"24":1,"25":28,"26":0,"27":1,"28":1,"29":1,"30":2,"31":0,"32":1,"33":1,"34":1,"35":2,"36":0,"37":1,"38":1,"39":1,"40":6,"41":1,"42":10,"43":1,"44":1,"45":1,"46":4,"47":0,"48":1,"49":1,"50":1,"51":17,"52":0,"53":0,"54":0,"55":0,"56":0,"57":0,"58":0,"59":5,"60":0,"61":6,"62":1,"63":1,"64":1,"65":1,"66":11,"67":3,"68":0,"69":6},"f":{"0":16,"1":5,"2":89,"3":169,"4":34,"5":4,"6":1,"7":1,"8":40,"9":4,"10":3,"11":5,"12":3,"13":0,"14":1,"15":1,"16":28,"17":0,"18":1,"19":1,"20":2,"21":0,"22":1,"23":1,"24":2,"25":0,"26":1,"27":1,"28":6,"29":1,"30":10,"31":1,"32":1,"33":4,"34":0,"35":1,"36":1,"37":17,"38":0,"39":0,"40":0,"41":0,"42":0,"43":5,"44":0,"45":6,"46":1,"47":1,"48":1,"49":11,"50":3,"51":0},"b":{"0":[11,5],"1":[11,5],"2":[61],"3":[4,4],"4":[4,4],"5":[4,4],"6":[5,5],"7":[0,0],"8":[0,0],"9":[0,0],"10":[0,0],"11":[1,1],"12":[0,0],"13":[0,0],"14":[1,0]}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/config/builder/variants.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/config/builder/variants.ts","statementMap":{"0":{"start":{"line":3,"column":0},"end":{"line":3,"column":60}},"1":{"start":{"line":57,"column":11},"end":{"line":57,"column":62}},"2":{"start":{"line":58,"column":11},"end":{"line":58,"column":43}},"3":{"start":{"line":69,"column":22},"end":{"line":75,"column":null}},"4":{"start":{"line":71,"column":8},"end":{"line":74,"column":10}},"5":{"start":{"line":78,"column":4},"end":{"line":101,"column":null}},"6":{"start":{"line":90,"column":23},"end":{"line":90,"column":null}},"7":{"start":{"line":93,"column":6},"end":{"line":99,"column":null}},"8":{"start":{"line":94,"column":22},"end":{"line":94,"column":28}},"9":{"start":{"line":95,"column":8},"end":{"line":98,"column":null}},"10":{"start":{"line":100,"column":6},"end":{"line":100,"column":null}},"11":{"start":{"line":118,"column":4},"end":{"line":118,"column":null}},"12":{"start":{"line":54,"column":0},"end":{"line":54,"column":13}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":56,"column":2},"end":{"line":56,"column":null}},"loc":{"start":{"line":58,"column":43},"end":{"line":59,"column":6}}},"1":{"name":"(anonymous_1)","decl":{"start":{"line":60,"column":2},"end":{"line":60,"column":8}},"loc":{"start":{"line":68,"column":20},"end":{"line":102,"column":3}}},"2":{"name":"(anonymous_2)","decl":{"start":{"line":70,"column":31},"end":{"line":70,"column":32}},"loc":{"start":{"line":71,"column":8},"end":{"line":74,"column":10}}},"3":{"name":"(anonymous_3)","decl":{"start":{"line":89,"column":6},"end":{"line":89,"column":11}},"loc":{"start":{"line":89,"column":24},"end":{"line":101,"column":5}}},"4":{"name":"(anonymous_4)","decl":{"start":{"line":117,"column":2},"end":{"line":117,"column":11}},"loc":{"start":{"line":117,"column":11},"end":{"line":119,"column":3}}}},"branchMap":{},"s":{"0":5,"1":12,"2":12,"3":12,"4":28,"5":12,"6":2,"7":2,"8":4,"9":4,"10":2,"11":0,"12":5},"f":{"0":12,"1":12,"2":28,"3":2,"4":0},"b":{}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/dependencies/DependencyConfig.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/dependencies/DependencyConfig.ts","statementMap":{"0":{"start":{"line":3,"column":0},"end":{"line":3,"column":45}},"1":{"start":{"line":16,"column":25},"end":{"line":21,"column":3}},"2":{"start":{"line":20,"column":4},"end":{"line":20,"column":null}},"3":{"start":{"line":23,"column":13},"end":{"line":23,"column":null}},"4":{"start":{"line":27,"column":13},"end":{"line":27,"column":null}},"5":{"start":{"line":34,"column":4},"end":{"line":37,"column":null}},"6":{"start":{"line":10,"column":13},"end":{"line":10,"column":29}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":16,"column":25},"end":{"line":16,"column":30}},"loc":{"start":{"line":19,"column":25},"end":{"line":21,"column":3}}},"1":{"name":"(anonymous_1)","decl":{"start":{"line":22,"column":2},"end":{"line":22,"column":null}},"loc":{"start":{"line":30,"column":45},"end":{"line":31,"column":6}}},"2":{"name":"(anonymous_2)","decl":{"start":{"line":33,"column":2},"end":{"line":33,"column":7}},"loc":{"start":{"line":33,"column":67},"end":{"line":38,"column":3}}}},"branchMap":{"0":{"loc":{"start":{"line":20,"column":47},"end":{"line":20,"column":73}},"type":"binary-expr","locations":[{"start":{"line":20,"column":47},"end":{"line":20,"column":67}},{"start":{"line":20,"column":71},"end":{"line":20,"column":73}}]},"1":{"loc":{"start":{"line":27,"column":13},"end":{"line":30,"column":45}},"type":"default-arg","locations":[{"start":{"line":30,"column":8},"end":{"line":30,"column":45}}]}},"s":{"0":5,"1":5,"2":0,"3":1,"4":1,"5":0,"6":5},"f":{"0":0,"1":1,"2":0},"b":{"0":[0,0],"1":[1]}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/dependencies/dependencies.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/dependencies/dependencies.ts","statementMap":{"0":{"start":{"line":1,"column":0},"end":{"line":1,"column":56}},"1":{"start":{"line":38,"column":32},"end":{"line":43,"column":4}},"2":{"start":{"line":44,"column":2},"end":{"line":48,"column":null}},"3":{"start":{"line":45,"column":4},"end":{"line":47,"column":null}},"4":{"start":{"line":46,"column":7},"end":{"line":46,"column":48}},"5":{"start":{"line":50,"column":15},"end":{"line":57,"column":3}},"6":{"start":{"line":51,"column":34},"end":{"line":51,"column":78}},"7":{"start":{"line":51,"column":59},"end":{"line":51,"column":77}},"8":{"start":{"line":52,"column":29},"end":{"line":52,"column":75}},"9":{"start":{"line":52,"column":49},"end":{"line":52,"column":74}},"10":{"start":{"line":53,"column":4},"end":{"line":55,"column":null}},"11":{"start":{"line":54,"column":6},"end":{"line":54,"column":null}},"12":{"start":{"line":56,"column":4},"end":{"line":56,"column":null}},"13":{"start":{"line":59,"column":29},"end":{"line":60,"column":45}},"14":{"start":{"line":60,"column":4},"end":{"line":60,"column":45}},"15":{"start":{"line":61,"column":36},"end":{"line":69,"column":3}},"16":{"start":{"line":62,"column":16},"end":{"line":62,"column":31}},"17":{"start":{"line":63,"column":4},"end":{"line":68,"column":null}},"18":{"start":{"line":70,"column":27},"end":{"line":73,"column":3}},"19":{"start":{"line":71,"column":16},"end":{"line":71,"column":31}},"20":{"start":{"line":72,"column":4},"end":{"line":72,"column":null}},"21":{"start":{"line":74,"column":26},"end":{"line":75,"column":42}},"22":{"start":{"line":75,"column":4},"end":{"line":75,"column":42}},"23":{"start":{"line":76,"column":31},"end":{"line":92,"column":3}},"24":{"start":{"line":80,"column":16},"end":{"line":80,"column":31}},"25":{"start":{"line":81,"column":4},"end":{"line":87,"column":null}},"26":{"start":{"line":86,"column":6},"end":{"line":86,"column":null}},"27":{"start":{"line":88,"column":19},"end":{"line":90,"column":53}},"28":{"start":{"line":89,"column":28},"end":{"line":89,"column":71}},"29":{"start":{"line":90,"column":28},"end":{"line":90,"column":52}},"30":{"start":{"line":91,"column":4},"end":{"line":91,"column":null}},"31":{"start":{"line":93,"column":23},"end":{"line":98,"column":35}},"32":{"start":{"line":94,"column":4},"end":{"line":98,"column":35}},"33":{"start":{"line":99,"column":20},"end":{"line":102,"column":69}},"34":{"start":{"line":100,"column":4},"end":{"line":102,"column":69}},"35":{"start":{"line":102,"column":34},"end":{"line":102,"column":68}},"36":{"start":{"line":104,"column":39},"end":{"line":109,"column":3}},"37":{"start":{"line":105,"column":16},"end":{"line":105,"column":31}},"38":{"start":{"line":106,"column":4},"end":{"line":108,"column":null}},"39":{"start":{"line":107,"column":6},"end":{"line":107,"column":null}},"40":{"start":{"line":110,"column":46},"end":{"line":126,"column":3}},"41":{"start":{"line":111,"column":16},"end":{"line":111,"column":31}},"42":{"start":{"line":112,"column":4},"end":{"line":114,"column":null}},"43":{"start":{"line":113,"column":6},"end":{"line":113,"column":null}},"44":{"start":{"line":115,"column":4},"end":{"line":125,"column":null}},"45":{"start":{"line":117,"column":8},"end":{"line":118,"column":null}},"46":{"start":{"line":122,"column":6},"end":{"line":124,"column":null}},"47":{"start":{"line":127,"column":37},"end":{"line":132,"column":3}},"48":{"start":{"line":128,"column":16},"end":{"line":128,"column":31}},"49":{"start":{"line":129,"column":4},"end":{"line":131,"column":null}},"50":{"start":{"line":130,"column":6},"end":{"line":130,"column":null}},"51":{"start":{"line":133,"column":36},"end":{"line":140,"column":3}},"52":{"start":{"line":134,"column":16},"end":{"line":134,"column":31}},"53":{"start":{"line":135,"column":4},"end":{"line":139,"column":null}},"54":{"start":{"line":136,"column":6},"end":{"line":138,"column":null}},"55":{"start":{"line":141,"column":36},"end":{"line":166,"column":3}},"56":{"start":{"line":145,"column":16},"end":{"line":145,"column":31}},"57":{"start":{"line":146,"column":4},"end":{"line":152,"column":null}},"58":{"start":{"line":151,"column":6},"end":{"line":151,"column":null}},"59":{"start":{"line":153,"column":19},"end":{"line":155,"column":53}},"60":{"start":{"line":154,"column":28},"end":{"line":154,"column":71}},"61":{"start":{"line":155,"column":28},"end":{"line":155,"column":52}},"62":{"start":{"line":156,"column":4},"end":{"line":165,"column":null}},"63":{"start":{"line":157,"column":6},"end":{"line":164,"column":null}},"64":{"start":{"line":161,"column":14},"end":{"line":161,"column":141}},"65":{"start":{"line":167,"column":33},"end":{"line":173,"column":3}},"66":{"start":{"line":168,"column":4},"end":{"line":168,"column":null}},"67":{"start":{"line":169,"column":4},"end":{"line":169,"column":null}},"68":{"start":{"line":170,"column":4},"end":{"line":170,"column":null}},"69":{"start":{"line":171,"column":4},"end":{"line":171,"column":null}},"70":{"start":{"line":172,"column":4},"end":{"line":172,"column":null}},"71":{"start":{"line":174,"column":30},"end":{"line":190,"column":12}},"72":{"start":{"line":175,"column":4},"end":{"line":190,"column":12}},"73":{"start":{"line":178,"column":22},"end":{"line":186,"column":12}},"74":{"start":{"line":179,"column":12},"end":{"line":184,"column":null}},"75":{"start":{"line":180,"column":14},"end":{"line":180,"column":null}},"76":{"start":{"line":182,"column":14},"end":{"line":182,"column":null}},"77":{"start":{"line":182,"column":38},"end":{"line":182,"column":null}},"78":{"start":{"line":183,"column":14},"end":{"line":183,"column":null}},"79":{"start":{"line":185,"column":12},"end":{"line":185,"column":null}},"80":{"start":{"line":187,"column":10},"end":{"line":189,"column":null}},"81":{"start":{"line":188,"column":12},"end":{"line":188,"column":null}},"82":{"start":{"line":192,"column":2},"end":{"line":205,"column":null}},"83":{"start":{"line":32,"column":0},"end":{"line":32,"column":7}}},"fnMap":{"0":{"name":"checkDependencies","decl":{"start":{"line":32,"column":22},"end":{"line":32,"column":39}},"loc":{"start":{"line":36,"column":29},"end":{"line":206,"column":1}}},"1":{"name":"(anonymous_1)","decl":{"start":{"line":45,"column":39},"end":{"line":45,"column":40}},"loc":{"start":{"line":46,"column":7},"end":{"line":46,"column":48}}},"2":{"name":"(anonymous_2)","decl":{"start":{"line":50,"column":15},"end":{"line":50,"column":16}},"loc":{"start":{"line":50,"column":43},"end":{"line":57,"column":3}}},"3":{"name":"(anonymous_3)","decl":{"start":{"line":51,"column":52},"end":{"line":51,"column":53}},"loc":{"start":{"line":51,"column":59},"end":{"line":51,"column":77}}},"4":{"name":"(anonymous_4)","decl":{"start":{"line":52,"column":42},"end":{"line":52,"column":43}},"loc":{"start":{"line":52,"column":49},"end":{"line":52,"column":74}}},"5":{"name":"(anonymous_5)","decl":{"start":{"line":59,"column":29},"end":{"line":59,"column":30}},"loc":{"start":{"line":60,"column":4},"end":{"line":60,"column":45}}},"6":{"name":"(anonymous_6)","decl":{"start":{"line":61,"column":36},"end":{"line":61,"column":37}},"loc":{"start":{"line":61,"column":64},"end":{"line":69,"column":3}}},"7":{"name":"(anonymous_7)","decl":{"start":{"line":70,"column":27},"end":{"line":70,"column":28}},"loc":{"start":{"line":70,"column":55},"end":{"line":73,"column":3}}},"8":{"name":"(anonymous_8)","decl":{"start":{"line":74,"column":26},"end":{"line":74,"column":27}},"loc":{"start":{"line":75,"column":4},"end":{"line":75,"column":42}}},"9":{"name":"(anonymous_9)","decl":{"start":{"line":76,"column":31},"end":{"line":76,"column":null}},"loc":{"start":{"line":79,"column":6},"end":{"line":92,"column":3}}},"10":{"name":"(anonymous_10)","decl":{"start":{"line":89,"column":14},"end":{"line":89,"column":15}},"loc":{"start":{"line":89,"column":28},"end":{"line":89,"column":71}}},"11":{"name":"(anonymous_11)","decl":{"start":{"line":90,"column":14},"end":{"line":90,"column":15}},"loc":{"start":{"line":90,"column":28},"end":{"line":90,"column":52}}},"12":{"name":"(anonymous_12)","decl":{"start":{"line":93,"column":23},"end":{"line":93,"column":24}},"loc":{"start":{"line":94,"column":4},"end":{"line":98,"column":35}}},"13":{"name":"(anonymous_13)","decl":{"start":{"line":99,"column":20},"end":{"line":99,"column":21}},"loc":{"start":{"line":100,"column":4},"end":{"line":102,"column":69}}},"14":{"name":"(anonymous_14)","decl":{"start":{"line":102,"column":27},"end":{"line":102,"column":28}},"loc":{"start":{"line":102,"column":34},"end":{"line":102,"column":68}}},"15":{"name":"(anonymous_15)","decl":{"start":{"line":104,"column":39},"end":{"line":104,"column":40}},"loc":{"start":{"line":104,"column":67},"end":{"line":109,"column":3}}},"16":{"name":"(anonymous_16)","decl":{"start":{"line":110,"column":46},"end":{"line":110,"column":47}},"loc":{"start":{"line":110,"column":74},"end":{"line":126,"column":3}}},"17":{"name":"(anonymous_17)","decl":{"start":{"line":116,"column":67},"end":{"line":116,"column":68}},"loc":{"start":{"line":117,"column":8},"end":{"line":118,"column":null}}},"18":{"name":"(anonymous_18)","decl":{"start":{"line":127,"column":37},"end":{"line":127,"column":38}},"loc":{"start":{"line":127,"column":65},"end":{"line":132,"column":3}}},"19":{"name":"(anonymous_19)","decl":{"start":{"line":133,"column":36},"end":{"line":133,"column":37}},"loc":{"start":{"line":133,"column":64},"end":{"line":140,"column":3}}},"20":{"name":"(anonymous_20)","decl":{"start":{"line":141,"column":36},"end":{"line":141,"column":null}},"loc":{"start":{"line":144,"column":6},"end":{"line":166,"column":3}}},"21":{"name":"(anonymous_21)","decl":{"start":{"line":154,"column":14},"end":{"line":154,"column":15}},"loc":{"start":{"line":154,"column":28},"end":{"line":154,"column":71}}},"22":{"name":"(anonymous_22)","decl":{"start":{"line":155,"column":14},"end":{"line":155,"column":15}},"loc":{"start":{"line":155,"column":28},"end":{"line":155,"column":52}}},"23":{"name":"(anonymous_23)","decl":{"start":{"line":160,"column":12},"end":{"line":160,"column":13}},"loc":{"start":{"line":161,"column":14},"end":{"line":161,"column":141}}},"24":{"name":"(anonymous_24)","decl":{"start":{"line":167,"column":33},"end":{"line":167,"column":34}},"loc":{"start":{"line":167,"column":61},"end":{"line":173,"column":3}}},"25":{"name":"(anonymous_25)","decl":{"start":{"line":174,"column":30},"end":{"line":174,"column":31}},"loc":{"start":{"line":175,"column":4},"end":{"line":190,"column":12}}},"26":{"name":"(anonymous_26)","decl":{"start":{"line":177,"column":9},"end":{"line":177,"column":12}},"loc":{"start":{"line":177,"column":14},"end":{"line":190,"column":9}}},"27":{"name":"(anonymous_27)","decl":{"start":{"line":178,"column":43},"end":{"line":178,"column":44}},"loc":{"start":{"line":178,"column":49},"end":{"line":186,"column":11}}}},"branchMap":{"0":{"loc":{"start":{"line":44,"column":2},"end":{"line":48,"column":null}},"type":"if","locations":[{"start":{"line":44,"column":2},"end":{"line":48,"column":null}}]},"1":{"loc":{"start":{"line":53,"column":4},"end":{"line":55,"column":null}},"type":"if","locations":[{"start":{"line":53,"column":4},"end":{"line":55,"column":null}}]},"2":{"loc":{"start":{"line":53,"column":8},"end":{"line":53,"column":51}},"type":"binary-expr","locations":[{"start":{"line":53,"column":8},"end":{"line":53,"column":30}},{"start":{"line":53,"column":34},"end":{"line":53,"column":51}}]},"3":{"loc":{"start":{"line":64,"column":6},"end":{"line":66,"column":null}},"type":"binary-expr","locations":[{"start":{"line":64,"column":6},"end":{"line":64,"column":35}},{"start":{"line":65,"column":6},"end":{"line":66,"column":null}}]},"4":{"loc":{"start":{"line":72,"column":11},"end":{"line":72,"column":69}},"type":"binary-expr","locations":[{"start":{"line":72,"column":11},"end":{"line":72,"column":45}},{"start":{"line":72,"column":49},"end":{"line":72,"column":69}}]},"5":{"loc":{"start":{"line":81,"column":4},"end":{"line":87,"column":null}},"type":"if","locations":[{"start":{"line":81,"column":4},"end":{"line":87,"column":null}}]},"6":{"loc":{"start":{"line":82,"column":6},"end":{"line":84,"column":62}},"type":"binary-expr","locations":[{"start":{"line":82,"column":6},"end":{"line":82,"column":19}},{"start":{"line":83,"column":7},"end":{"line":83,"column":41}},{"start":{"line":84,"column":8},"end":{"line":84,"column":61}}]},"7":{"loc":{"start":{"line":89,"column":28},"end":{"line":89,"column":71}},"type":"cond-expr","locations":[{"start":{"line":89,"column":44},"end":{"line":89,"column":64}},{"start":{"line":89,"column":67},"end":{"line":89,"column":71}}]},"8":{"loc":{"start":{"line":94,"column":4},"end":{"line":98,"column":35}},"type":"binary-expr","locations":[{"start":{"line":94,"column":4},"end":{"line":94,"column":33}},{"start":{"line":95,"column":4},"end":{"line":95,"column":40}},{"start":{"line":96,"column":4},"end":{"line":96,"column":31}},{"start":{"line":97,"column":4},"end":{"line":97,"column":30}},{"start":{"line":98,"column":4},"end":{"line":98,"column":35}}]},"9":{"loc":{"start":{"line":100,"column":4},"end":{"line":102,"column":69}},"type":"cond-expr","locations":[{"start":{"line":101,"column":8},"end":{"line":101,"column":31}},{"start":{"line":102,"column":8},"end":{"line":102,"column":69}}]},"10":{"loc":{"start":{"line":106,"column":4},"end":{"line":108,"column":null}},"type":"if","locations":[{"start":{"line":106,"column":4},"end":{"line":108,"column":null}}]},"11":{"loc":{"start":{"line":107,"column":25},"end":{"line":107,"column":54}},"type":"binary-expr","locations":[{"start":{"line":107,"column":25},"end":{"line":107,"column":41}},{"start":{"line":107,"column":45},"end":{"line":107,"column":54}}]},"12":{"loc":{"start":{"line":112,"column":4},"end":{"line":114,"column":null}},"type":"if","locations":[{"start":{"line":112,"column":4},"end":{"line":114,"column":null}}]},"13":{"loc":{"start":{"line":113,"column":25},"end":{"line":113,"column":54}},"type":"binary-expr","locations":[{"start":{"line":113,"column":25},"end":{"line":113,"column":41}},{"start":{"line":113,"column":45},"end":{"line":113,"column":54}}]},"14":{"loc":{"start":{"line":115,"column":4},"end":{"line":125,"column":null}},"type":"if","locations":[{"start":{"line":115,"column":4},"end":{"line":125,"column":null}}]},"15":{"loc":{"start":{"line":123,"column":63},"end":{"line":123,"column":92}},"type":"binary-expr","locations":[{"start":{"line":123,"column":63},"end":{"line":123,"column":79}},{"start":{"line":123,"column":83},"end":{"line":123,"column":92}}]},"16":{"loc":{"start":{"line":129,"column":4},"end":{"line":131,"column":null}},"type":"if","locations":[{"start":{"line":129,"column":4},"end":{"line":131,"column":null}}]},"17":{"loc":{"start":{"line":129,"column":8},"end":{"line":129,"column":67}},"type":"binary-expr","locations":[{"start":{"line":129,"column":8},"end":{"line":129,"column":42}},{"start":{"line":129,"column":46},"end":{"line":129,"column":67}}]},"18":{"loc":{"start":{"line":130,"column":25},"end":{"line":130,"column":54}},"type":"binary-expr","locations":[{"start":{"line":130,"column":25},"end":{"line":130,"column":41}},{"start":{"line":130,"column":45},"end":{"line":130,"column":54}}]},"19":{"loc":{"start":{"line":135,"column":4},"end":{"line":139,"column":null}},"type":"if","locations":[{"start":{"line":135,"column":4},"end":{"line":139,"column":null}}]},"20":{"loc":{"start":{"line":137,"column":11},"end":{"line":137,"column":40}},"type":"binary-expr","locations":[{"start":{"line":137,"column":11},"end":{"line":137,"column":27}},{"start":{"line":137,"column":31},"end":{"line":137,"column":40}}]},"21":{"loc":{"start":{"line":146,"column":4},"end":{"line":152,"column":null}},"type":"if","locations":[{"start":{"line":146,"column":4},"end":{"line":152,"column":null}}]},"22":{"loc":{"start":{"line":147,"column":6},"end":{"line":149,"column":62}},"type":"binary-expr","locations":[{"start":{"line":147,"column":6},"end":{"line":147,"column":19}},{"start":{"line":148,"column":7},"end":{"line":148,"column":41}},{"start":{"line":149,"column":8},"end":{"line":149,"column":61}}]},"23":{"loc":{"start":{"line":154,"column":28},"end":{"line":154,"column":71}},"type":"cond-expr","locations":[{"start":{"line":154,"column":44},"end":{"line":154,"column":64}},{"start":{"line":154,"column":67},"end":{"line":154,"column":71}}]},"24":{"loc":{"start":{"line":156,"column":4},"end":{"line":165,"column":null}},"type":"if","locations":[{"start":{"line":156,"column":4},"end":{"line":165,"column":null}}]},"25":{"loc":{"start":{"line":161,"column":43},"end":{"line":161,"column":72}},"type":"binary-expr","locations":[{"start":{"line":161,"column":43},"end":{"line":161,"column":59}},{"start":{"line":161,"column":63},"end":{"line":161,"column":72}}]},"26":{"loc":{"start":{"line":161,"column":106},"end":{"line":161,"column":139}},"type":"cond-expr","locations":[{"start":{"line":161,"column":118},"end":{"line":161,"column":134}},{"start":{"line":161,"column":137},"end":{"line":161,"column":139}}]},"27":{"loc":{"start":{"line":175,"column":4},"end":{"line":190,"column":12}},"type":"cond-expr","locations":[{"start":{"line":176,"column":8},"end":{"line":176,"column":41}},{"start":{"line":177,"column":8},"end":{"line":190,"column":12}}]},"28":{"loc":{"start":{"line":182,"column":14},"end":{"line":182,"column":null}},"type":"if","locations":[{"start":{"line":182,"column":14},"end":{"line":182,"column":null}}]},"29":{"loc":{"start":{"line":187,"column":10},"end":{"line":189,"column":null}},"type":"if","locations":[{"start":{"line":187,"column":10},"end":{"line":189,"column":null}}]}},"s":{"0":5,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0,"36":0,"37":0,"38":0,"39":0,"40":0,"41":0,"42":0,"43":0,"44":0,"45":0,"46":0,"47":0,"48":0,"49":0,"50":0,"51":0,"52":0,"53":0,"54":0,"55":0,"56":0,"57":0,"58":0,"59":0,"60":0,"61":0,"62":0,"63":0,"64":0,"65":0,"66":0,"67":0,"68":0,"69":0,"70":0,"71":0,"72":0,"73":0,"74":0,"75":0,"76":0,"77":0,"78":0,"79":0,"80":0,"81":0,"82":0,"83":5},"f":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0},"b":{"0":[0],"1":[0],"2":[0,0],"3":[0,0],"4":[0,0],"5":[0],"6":[0,0,0],"7":[0,0],"8":[0,0,0,0,0],"9":[0,0],"10":[0],"11":[0,0],"12":[0],"13":[0,0],"14":[0],"15":[0,0],"16":[0],"17":[0,0],"18":[0,0],"19":[0],"20":[0,0],"21":[0],"22":[0,0,0],"23":[0,0],"24":[0],"25":[0,0],"26":[0,0],"27":[0,0],"28":[0],"29":[0]}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/dependencies/setupDependencyConfig.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/dependencies/setupDependencyConfig.ts","statementMap":{"0":{"start":{"line":21,"column":2},"end":{"line":21,"column":null}},"1":{"start":{"line":6,"column":0},"end":{"line":6,"column":16}}},"fnMap":{"0":{"name":"setupDependencyConfig","decl":{"start":{"line":6,"column":16},"end":{"line":6,"column":37}},"loc":{"start":{"line":19,"column":3},"end":{"line":22,"column":1}}}},"branchMap":{},"s":{"0":1,"1":5},"f":{"0":1},"b":{}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/exver/exver.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/exver/exver.ts","statementMap":{"0":{"start":{"line":9,"column":0},"end":{"line":2352,"column":4}},"1":{"start":{"line":16,"column":17},"end":{"line":16,"column":42}},"2":{"start":{"line":18,"column":2},"end":{"line":18,"column":33}},"3":{"start":{"line":20,"column":2},"end":{"line":20,"column":28}},"4":{"start":{"line":26,"column":13},"end":{"line":26,"column":38}},"5":{"start":{"line":34,"column":2},"end":{"line":34,"column":27}},"6":{"start":{"line":36,"column":2},"end":{"line":36,"column":21}},"7":{"start":{"line":38,"column":2},"end":{"line":38,"column":27}},"8":{"start":{"line":40,"column":2},"end":{"line":40,"column":28}},"9":{"start":{"line":42,"column":2},"end":{"line":42,"column":14}},"10":{"start":{"line":46,"column":0},"end":{"line":46,"column":37}},"11":{"start":{"line":51,"column":2},"end":{"line":51,"column":31}},"12":{"start":{"line":53,"column":2},"end":{"line":53,"column":null}},"13":{"start":{"line":53,"column":35},"end":{"line":53,"column":46}},"14":{"start":{"line":55,"column":2},"end":{"line":55,"column":29}},"15":{"start":{"line":57,"column":2},"end":{"line":57,"column":46}},"16":{"start":{"line":59,"column":2},"end":{"line":59,"column":48}},"17":{"start":{"line":63,"column":0},"end":{"line":122,"column":2}},"18":{"start":{"line":65,"column":12},"end":{"line":65,"column":36}},"19":{"start":{"line":67,"column":2},"end":{"line":119,"column":null}},"20":{"start":{"line":69,"column":14},"end":{"line":69,"column":18}},"21":{"start":{"line":73,"column":4},"end":{"line":81,"column":null}},"22":{"start":{"line":75,"column":6},"end":{"line":80,"column":null}},"23":{"start":{"line":77,"column":8},"end":{"line":77,"column":51}},"24":{"start":{"line":79,"column":8},"end":{"line":79,"column":14}},"25":{"start":{"line":83,"column":12},"end":{"line":83,"column":31}},"26":{"start":{"line":85,"column":19},"end":{"line":89,"column":9}},"27":{"start":{"line":91,"column":14},"end":{"line":91,"column":80}},"28":{"start":{"line":93,"column":4},"end":{"line":118,"column":null}},"29":{"start":{"line":95,"column":14},"end":{"line":95,"column":31}},"30":{"start":{"line":97,"column":19},"end":{"line":97,"column":71}},"31":{"start":{"line":99,"column":17},"end":{"line":99,"column":32}},"32":{"start":{"line":101,"column":17},"end":{"line":101,"column":63}},"33":{"start":{"line":103,"column":19},"end":{"line":103,"column":41}},"34":{"start":{"line":105,"column":6},"end":{"line":113,"column":40}},"35":{"start":{"line":117,"column":6},"end":{"line":117,"column":28}},"36":{"start":{"line":121,"column":2},"end":{"line":121,"column":13}},"37":{"start":{"line":125,"column":0},"end":{"line":286,"column":2}},"38":{"start":{"line":127,"column":33},"end":{"line":167,"column":4}},"39":{"start":{"line":131,"column":6},"end":{"line":131,"column":59}},"40":{"start":{"line":137,"column":25},"end":{"line":144,"column":8}},"41":{"start":{"line":139,"column":8},"end":{"line":143,"column":30}},"42":{"start":{"line":147,"column":6},"end":{"line":147,"column":83}},"43":{"start":{"line":153,"column":6},"end":{"line":153,"column":29}},"44":{"start":{"line":159,"column":6},"end":{"line":159,"column":28}},"45":{"start":{"line":165,"column":6},"end":{"line":165,"column":37}},"46":{"start":{"line":172,"column":4},"end":{"line":172,"column":55}},"47":{"start":{"line":178,"column":4},"end":{"line":194,"column":83}},"48":{"start":{"line":192,"column":55},"end":{"line":192,"column":79}},"49":{"start":{"line":194,"column":55},"end":{"line":194,"column":79}},"50":{"start":{"line":200,"column":4},"end":{"line":220,"column":83}},"51":{"start":{"line":218,"column":55},"end":{"line":218,"column":79}},"52":{"start":{"line":220,"column":55},"end":{"line":220,"column":79}},"53":{"start":{"line":226,"column":4},"end":{"line":226,"column":67}},"54":{"start":{"line":232,"column":23},"end":{"line":232,"column":56}},"55":{"start":{"line":237,"column":4},"end":{"line":237,"column":24}},"56":{"start":{"line":240,"column":4},"end":{"line":253,"column":null}},"57":{"start":{"line":242,"column":6},"end":{"line":250,"column":null}},"58":{"start":{"line":244,"column":8},"end":{"line":249,"column":null}},"59":{"start":{"line":246,"column":10},"end":{"line":246,"column":44}},"60":{"start":{"line":248,"column":10},"end":{"line":248,"column":14}},"61":{"start":{"line":252,"column":6},"end":{"line":252,"column":30}},"62":{"start":{"line":256,"column":4},"end":{"line":275,"column":null}},"63":{"start":{"line":260,"column":8},"end":{"line":260,"column":31}},"64":{"start":{"line":265,"column":8},"end":{"line":265,"column":58}},"65":{"start":{"line":270,"column":8},"end":{"line":274,"column":50}},"66":{"start":{"line":281,"column":4},"end":{"line":281,"column":71}},"67":{"start":{"line":285,"column":2},"end":{"line":285,"column":95}},"68":{"start":{"line":291,"column":2},"end":{"line":291,"column":49}},"69":{"start":{"line":294,"column":19},"end":{"line":294,"column":21}},"70":{"start":{"line":296,"column":19},"end":{"line":296,"column":40}},"71":{"start":{"line":299,"column":31},"end":{"line":299,"column":649}},"72":{"start":{"line":301,"column":30},"end":{"line":301,"column":51}},"73":{"start":{"line":304,"column":15},"end":{"line":304,"column":19}},"74":{"start":{"line":305,"column":15},"end":{"line":305,"column":19}},"75":{"start":{"line":306,"column":15},"end":{"line":306,"column":18}},"76":{"start":{"line":307,"column":15},"end":{"line":307,"column":18}},"77":{"start":{"line":308,"column":15},"end":{"line":308,"column":18}},"78":{"start":{"line":309,"column":15},"end":{"line":309,"column":18}},"79":{"start":{"line":310,"column":15},"end":{"line":310,"column":18}},"80":{"start":{"line":311,"column":15},"end":{"line":311,"column":19}},"81":{"start":{"line":312,"column":15},"end":{"line":312,"column":19}},"82":{"start":{"line":313,"column":15},"end":{"line":313,"column":18}},"83":{"start":{"line":314,"column":16},"end":{"line":314,"column":19}},"84":{"start":{"line":315,"column":16},"end":{"line":315,"column":19}},"85":{"start":{"line":316,"column":16},"end":{"line":316,"column":20}},"86":{"start":{"line":317,"column":16},"end":{"line":317,"column":19}},"87":{"start":{"line":318,"column":16},"end":{"line":318,"column":19}},"88":{"start":{"line":319,"column":16},"end":{"line":319,"column":19}},"89":{"start":{"line":320,"column":16},"end":{"line":320,"column":19}},"90":{"start":{"line":321,"column":16},"end":{"line":321,"column":19}},"91":{"start":{"line":323,"column":15},"end":{"line":323,"column":23}},"92":{"start":{"line":324,"column":15},"end":{"line":324,"column":26}},"93":{"start":{"line":325,"column":15},"end":{"line":325,"column":23}},"94":{"start":{"line":326,"column":15},"end":{"line":326,"column":27}},"95":{"start":{"line":328,"column":15},"end":{"line":328,"column":50}},"96":{"start":{"line":329,"column":15},"end":{"line":329,"column":50}},"97":{"start":{"line":330,"column":15},"end":{"line":330,"column":49}},"98":{"start":{"line":331,"column":15},"end":{"line":331,"column":49}},"99":{"start":{"line":332,"column":15},"end":{"line":332,"column":49}},"100":{"start":{"line":333,"column":15},"end":{"line":333,"column":49}},"101":{"start":{"line":334,"column":15},"end":{"line":334,"column":49}},"102":{"start":{"line":335,"column":15},"end":{"line":335,"column":50}},"103":{"start":{"line":336,"column":15},"end":{"line":336,"column":50}},"104":{"start":{"line":337,"column":15},"end":{"line":337,"column":49}},"105":{"start":{"line":338,"column":16},"end":{"line":338,"column":50}},"106":{"start":{"line":339,"column":16},"end":{"line":339,"column":50}},"107":{"start":{"line":340,"column":16},"end":{"line":340,"column":51}},"108":{"start":{"line":341,"column":16},"end":{"line":341,"column":50}},"109":{"start":{"line":342,"column":16},"end":{"line":342,"column":50}},"110":{"start":{"line":343,"column":16},"end":{"line":343,"column":50}},"111":{"start":{"line":344,"column":16},"end":{"line":344,"column":50}},"112":{"start":{"line":345,"column":16},"end":{"line":345,"column":64}},"113":{"start":{"line":346,"column":16},"end":{"line":346,"column":76}},"114":{"start":{"line":347,"column":16},"end":{"line":347,"column":50}},"115":{"start":{"line":348,"column":16},"end":{"line":348,"column":64}},"116":{"start":{"line":349,"column":16},"end":{"line":349,"column":50}},"117":{"start":{"line":350,"column":16},"end":{"line":350,"column":75}},"118":{"start":{"line":353,"column":15},"end":{"line":354,"column":34}},"119":{"start":{"line":354,"column":1},"end":{"line":354,"column":33}},"120":{"start":{"line":356,"column":15},"end":{"line":357,"column":47}},"121":{"start":{"line":357,"column":1},"end":{"line":357,"column":46}},"122":{"start":{"line":359,"column":15},"end":{"line":360,"column":120}},"123":{"start":{"line":360,"column":1},"end":{"line":360,"column":119}},"124":{"start":{"line":362,"column":15},"end":{"line":363,"column":38}},"125":{"start":{"line":363,"column":1},"end":{"line":363,"column":38}},"126":{"start":{"line":365,"column":15},"end":{"line":366,"column":25}},"127":{"start":{"line":366,"column":1},"end":{"line":366,"column":24}},"128":{"start":{"line":368,"column":15},"end":{"line":369,"column":26}},"129":{"start":{"line":369,"column":1},"end":{"line":369,"column":25}},"130":{"start":{"line":371,"column":15},"end":{"line":372,"column":15}},"131":{"start":{"line":372,"column":1},"end":{"line":372,"column":13}},"132":{"start":{"line":374,"column":15},"end":{"line":375,"column":15}},"133":{"start":{"line":375,"column":1},"end":{"line":375,"column":13}},"134":{"start":{"line":377,"column":15},"end":{"line":378,"column":14}},"135":{"start":{"line":378,"column":1},"end":{"line":378,"column":12}},"136":{"start":{"line":380,"column":15},"end":{"line":381,"column":14}},"137":{"start":{"line":381,"column":1},"end":{"line":381,"column":12}},"138":{"start":{"line":383,"column":16},"end":{"line":384,"column":14}},"139":{"start":{"line":384,"column":1},"end":{"line":384,"column":12}},"140":{"start":{"line":386,"column":16},"end":{"line":387,"column":15}},"141":{"start":{"line":387,"column":1},"end":{"line":387,"column":13}},"142":{"start":{"line":389,"column":16},"end":{"line":390,"column":14}},"143":{"start":{"line":390,"column":1},"end":{"line":390,"column":12}},"144":{"start":{"line":392,"column":16},"end":{"line":393,"column":14}},"145":{"start":{"line":393,"column":1},"end":{"line":393,"column":12}},"146":{"start":{"line":395,"column":16},"end":{"line":398,"column":3}},"147":{"start":{"line":397,"column":4},"end":{"line":397,"column":null}},"148":{"start":{"line":400,"column":16},"end":{"line":420,"column":3}},"149":{"start":{"line":402,"column":4},"end":{"line":419,"column":null}},"150":{"start":{"line":422,"column":16},"end":{"line":423,"column":16}},"151":{"start":{"line":423,"column":1},"end":{"line":423,"column":15}},"152":{"start":{"line":425,"column":16},"end":{"line":426,"column":16}},"153":{"start":{"line":426,"column":1},"end":{"line":426,"column":15}},"154":{"start":{"line":428,"column":16},"end":{"line":429,"column":17}},"155":{"start":{"line":429,"column":1},"end":{"line":429,"column":15}},"156":{"start":{"line":431,"column":16},"end":{"line":439,"column":3}},"157":{"start":{"line":433,"column":4},"end":{"line":438,"column":6}},"158":{"start":{"line":441,"column":16},"end":{"line":444,"column":3}},"159":{"start":{"line":443,"column":4},"end":{"line":443,"column":47}},"160":{"start":{"line":443,"column":40},"end":{"line":443,"column":44}},"161":{"start":{"line":446,"column":16},"end":{"line":449,"column":3}},"162":{"start":{"line":448,"column":4},"end":{"line":448,"column":19}},"163":{"start":{"line":451,"column":16},"end":{"line":454,"column":3}},"164":{"start":{"line":453,"column":4},"end":{"line":453,"column":47}},"165":{"start":{"line":453,"column":40},"end":{"line":453,"column":44}},"166":{"start":{"line":456,"column":16},"end":{"line":457,"column":31}},"167":{"start":{"line":457,"column":1},"end":{"line":457,"column":29}},"168":{"start":{"line":459,"column":20},"end":{"line":459,"column":21}},"169":{"start":{"line":461,"column":21},"end":{"line":461,"column":22}},"170":{"start":{"line":463,"column":28},"end":{"line":463,"column":52}},"171":{"start":{"line":465,"column":23},"end":{"line":465,"column":24}},"172":{"start":{"line":467,"column":28},"end":{"line":467,"column":30}},"173":{"start":{"line":469,"column":24},"end":{"line":469,"column":25}},"174":{"start":{"line":475,"column":2},"end":{"line":484,"column":null}},"175":{"start":{"line":477,"column":4},"end":{"line":480,"column":null}},"176":{"start":{"line":479,"column":6},"end":{"line":479,"column":86}},"177":{"start":{"line":483,"column":4},"end":{"line":483,"column":70}},"178":{"start":{"line":489,"column":4},"end":{"line":489,"column":54}},"179":{"start":{"line":495,"column":4},"end":{"line":495,"column":24}},"180":{"start":{"line":501,"column":4},"end":{"line":508,"column":6}},"181":{"start":{"line":514,"column":4},"end":{"line":514,"column":58}},"182":{"start":{"line":520,"column":4},"end":{"line":524,"column":55}},"183":{"start":{"line":527,"column":4},"end":{"line":534,"column":6}},"184":{"start":{"line":540,"column":4},"end":{"line":544,"column":55}},"185":{"start":{"line":547,"column":4},"end":{"line":547,"column":50}},"186":{"start":{"line":553,"column":4},"end":{"line":553,"column":67}},"187":{"start":{"line":559,"column":4},"end":{"line":559,"column":87}},"188":{"start":{"line":565,"column":4},"end":{"line":565,"column":27}},"189":{"start":{"line":571,"column":4},"end":{"line":571,"column":27}},"190":{"start":{"line":577,"column":4},"end":{"line":577,"column":55}},"191":{"start":{"line":583,"column":18},"end":{"line":583,"column":42}},"192":{"start":{"line":588,"column":4},"end":{"line":634,"column":null}},"193":{"start":{"line":590,"column":6},"end":{"line":590,"column":21}},"194":{"start":{"line":594,"column":6},"end":{"line":594,"column":18}},"195":{"start":{"line":596,"column":6},"end":{"line":599,"column":null}},"196":{"start":{"line":598,"column":8},"end":{"line":598,"column":12}},"197":{"start":{"line":602,"column":6},"end":{"line":602,"column":39}},"198":{"start":{"line":604,"column":6},"end":{"line":609,"column":8}},"199":{"start":{"line":612,"column":6},"end":{"line":627,"column":null}},"200":{"start":{"line":614,"column":8},"end":{"line":623,"column":null}},"201":{"start":{"line":616,"column":10},"end":{"line":616,"column":25}},"202":{"start":{"line":618,"column":10},"end":{"line":618,"column":29}},"203":{"start":{"line":622,"column":10},"end":{"line":622,"column":27}},"204":{"start":{"line":626,"column":8},"end":{"line":626,"column":12}},"205":{"start":{"line":630,"column":6},"end":{"line":630,"column":41}},"206":{"start":{"line":633,"column":6},"end":{"line":633,"column":21}},"207":{"start":{"line":640,"column":26},"end":{"line":640,"column":57}},"208":{"start":{"line":642,"column":24},"end":{"line":642,"column":53}},"209":{"start":{"line":645,"column":14},"end":{"line":666,"column":6}},"210":{"start":{"line":668,"column":4},"end":{"line":673,"column":null}},"211":{"start":{"line":670,"column":6},"end":{"line":670,"column":47}},"212":{"start":{"line":672,"column":6},"end":{"line":672,"column":43}},"213":{"start":{"line":675,"column":4},"end":{"line":675,"column":15}},"214":{"start":{"line":681,"column":4},"end":{"line":681,"column":null}},"215":{"start":{"line":681,"column":40},"end":{"line":681,"column":47}},"216":{"start":{"line":684,"column":4},"end":{"line":689,"column":null}},"217":{"start":{"line":686,"column":6},"end":{"line":686,"column":35}},"218":{"start":{"line":688,"column":6},"end":{"line":688,"column":31}},"219":{"start":{"line":692,"column":4},"end":{"line":692,"column":39}},"220":{"start":{"line":698,"column":4},"end":{"line":698,"column":62}},"221":{"start":{"line":704,"column":4},"end":{"line":713,"column":6}},"222":{"start":{"line":723,"column":4},"end":{"line":723,"column":21}},"223":{"start":{"line":725,"column":4},"end":{"line":725,"column":37}},"224":{"start":{"line":727,"column":4},"end":{"line":841,"column":null}},"225":{"start":{"line":729,"column":6},"end":{"line":729,"column":14}},"226":{"start":{"line":731,"column":6},"end":{"line":731,"column":23}},"227":{"start":{"line":733,"column":6},"end":{"line":733,"column":24}},"228":{"start":{"line":735,"column":6},"end":{"line":735,"column":23}},"229":{"start":{"line":737,"column":6},"end":{"line":737,"column":25}},"230":{"start":{"line":739,"column":6},"end":{"line":742,"column":null}},"231":{"start":{"line":741,"column":8},"end":{"line":741,"column":28}},"232":{"start":{"line":744,"column":6},"end":{"line":757,"column":null}},"233":{"start":{"line":746,"column":8},"end":{"line":746,"column":26}},"234":{"start":{"line":748,"column":8},"end":{"line":748,"column":22}},"235":{"start":{"line":750,"column":8},"end":{"line":750,"column":16}},"236":{"start":{"line":754,"column":8},"end":{"line":754,"column":25}},"237":{"start":{"line":756,"column":8},"end":{"line":756,"column":24}},"238":{"start":{"line":759,"column":6},"end":{"line":762,"column":null}},"239":{"start":{"line":761,"column":8},"end":{"line":761,"column":18}},"240":{"start":{"line":764,"column":6},"end":{"line":764,"column":39}},"241":{"start":{"line":766,"column":6},"end":{"line":777,"column":null}},"242":{"start":{"line":768,"column":8},"end":{"line":768,"column":26}},"243":{"start":{"line":770,"column":8},"end":{"line":770,"column":16}},"244":{"start":{"line":774,"column":8},"end":{"line":774,"column":25}},"245":{"start":{"line":776,"column":8},"end":{"line":776,"column":24}},"246":{"start":{"line":779,"column":6},"end":{"line":830,"column":null}},"247":{"start":{"line":781,"column":8},"end":{"line":781,"column":20}},"248":{"start":{"line":783,"column":8},"end":{"line":783,"column":25}},"249":{"start":{"line":785,"column":8},"end":{"line":785,"column":26}},"250":{"start":{"line":787,"column":8},"end":{"line":787,"column":25}},"251":{"start":{"line":789,"column":8},"end":{"line":789,"column":27}},"252":{"start":{"line":791,"column":8},"end":{"line":794,"column":null}},"253":{"start":{"line":793,"column":10},"end":{"line":793,"column":30}},"254":{"start":{"line":796,"column":8},"end":{"line":809,"column":null}},"255":{"start":{"line":798,"column":10},"end":{"line":798,"column":28}},"256":{"start":{"line":800,"column":10},"end":{"line":800,"column":24}},"257":{"start":{"line":802,"column":10},"end":{"line":802,"column":18}},"258":{"start":{"line":806,"column":10},"end":{"line":806,"column":27}},"259":{"start":{"line":808,"column":10},"end":{"line":808,"column":26}},"260":{"start":{"line":811,"column":8},"end":{"line":814,"column":null}},"261":{"start":{"line":813,"column":10},"end":{"line":813,"column":20}},"262":{"start":{"line":816,"column":8},"end":{"line":816,"column":41}},"263":{"start":{"line":818,"column":8},"end":{"line":829,"column":null}},"264":{"start":{"line":820,"column":10},"end":{"line":820,"column":28}},"265":{"start":{"line":822,"column":10},"end":{"line":822,"column":18}},"266":{"start":{"line":826,"column":10},"end":{"line":826,"column":27}},"267":{"start":{"line":828,"column":10},"end":{"line":828,"column":26}},"268":{"start":{"line":832,"column":6},"end":{"line":832,"column":20}},"269":{"start":{"line":834,"column":6},"end":{"line":834,"column":14}},"270":{"start":{"line":838,"column":6},"end":{"line":838,"column":23}},"271":{"start":{"line":840,"column":6},"end":{"line":840,"column":22}},"272":{"start":{"line":844,"column":4},"end":{"line":844,"column":14}},"273":{"start":{"line":854,"column":4},"end":{"line":865,"column":null}},"274":{"start":{"line":856,"column":6},"end":{"line":856,"column":18}},"275":{"start":{"line":858,"column":6},"end":{"line":858,"column":23}},"276":{"start":{"line":862,"column":6},"end":{"line":862,"column":22}},"277":{"start":{"line":864,"column":6},"end":{"line":864,"column":null}},"278":{"start":{"line":864,"column":35},"end":{"line":864,"column":52}},"279":{"start":{"line":868,"column":4},"end":{"line":868,"column":14}},"280":{"start":{"line":878,"column":4},"end":{"line":889,"column":null}},"281":{"start":{"line":880,"column":6},"end":{"line":880,"column":18}},"282":{"start":{"line":882,"column":6},"end":{"line":882,"column":23}},"283":{"start":{"line":886,"column":6},"end":{"line":886,"column":22}},"284":{"start":{"line":888,"column":6},"end":{"line":888,"column":null}},"285":{"start":{"line":888,"column":35},"end":{"line":888,"column":52}},"286":{"start":{"line":892,"column":4},"end":{"line":892,"column":14}},"287":{"start":{"line":902,"column":4},"end":{"line":902,"column":27}},"288":{"start":{"line":904,"column":4},"end":{"line":922,"column":null}},"289":{"start":{"line":906,"column":6},"end":{"line":906,"column":29}},"290":{"start":{"line":908,"column":6},"end":{"line":921,"column":null}},"291":{"start":{"line":910,"column":8},"end":{"line":910,"column":28}},"292":{"start":{"line":912,"column":8},"end":{"line":920,"column":null}},"293":{"start":{"line":914,"column":10},"end":{"line":914,"column":30}},"294":{"start":{"line":916,"column":10},"end":{"line":919,"column":null}},"295":{"start":{"line":918,"column":12},"end":{"line":918,"column":33}},"296":{"start":{"line":925,"column":4},"end":{"line":925,"column":14}},"297":{"start":{"line":935,"column":4},"end":{"line":935,"column":21}},"298":{"start":{"line":937,"column":4},"end":{"line":948,"column":null}},"299":{"start":{"line":939,"column":6},"end":{"line":939,"column":18}},"300":{"start":{"line":941,"column":6},"end":{"line":941,"column":20}},"301":{"start":{"line":945,"column":6},"end":{"line":945,"column":22}},"302":{"start":{"line":947,"column":6},"end":{"line":947,"column":null}},"303":{"start":{"line":947,"column":35},"end":{"line":947,"column":52}},"304":{"start":{"line":950,"column":4},"end":{"line":998,"column":null}},"305":{"start":{"line":952,"column":6},"end":{"line":952,"column":24}},"306":{"start":{"line":954,"column":6},"end":{"line":954,"column":35}},"307":{"start":{"line":956,"column":6},"end":{"line":991,"column":null}},"308":{"start":{"line":958,"column":8},"end":{"line":958,"column":26}},"309":{"start":{"line":960,"column":8},"end":{"line":971,"column":null}},"310":{"start":{"line":962,"column":10},"end":{"line":962,"column":22}},"311":{"start":{"line":964,"column":10},"end":{"line":964,"column":24}},"312":{"start":{"line":968,"column":10},"end":{"line":968,"column":26}},"313":{"start":{"line":970,"column":10},"end":{"line":970,"column":null}},"314":{"start":{"line":970,"column":39},"end":{"line":970,"column":56}},"315":{"start":{"line":973,"column":8},"end":{"line":984,"column":null}},"316":{"start":{"line":975,"column":10},"end":{"line":975,"column":28}},"317":{"start":{"line":977,"column":10},"end":{"line":977,"column":26}},"318":{"start":{"line":981,"column":10},"end":{"line":981,"column":27}},"319":{"start":{"line":983,"column":10},"end":{"line":983,"column":26}},"320":{"start":{"line":988,"column":8},"end":{"line":988,"column":25}},"321":{"start":{"line":990,"column":8},"end":{"line":990,"column":24}},"322":{"start":{"line":995,"column":6},"end":{"line":995,"column":23}},"323":{"start":{"line":997,"column":6},"end":{"line":997,"column":22}},"324":{"start":{"line":1001,"column":4},"end":{"line":1001,"column":14}},"325":{"start":{"line":1011,"column":4},"end":{"line":1011,"column":21}},"326":{"start":{"line":1013,"column":4},"end":{"line":1013,"column":26}},"327":{"start":{"line":1015,"column":4},"end":{"line":1018,"column":null}},"328":{"start":{"line":1017,"column":6},"end":{"line":1017,"column":16}},"329":{"start":{"line":1020,"column":4},"end":{"line":1020,"column":22}},"330":{"start":{"line":1022,"column":4},"end":{"line":1022,"column":32}},"331":{"start":{"line":1024,"column":4},"end":{"line":1035,"column":null}},"332":{"start":{"line":1026,"column":6},"end":{"line":1026,"column":24}},"333":{"start":{"line":1028,"column":6},"end":{"line":1028,"column":26}},"334":{"start":{"line":1032,"column":6},"end":{"line":1032,"column":23}},"335":{"start":{"line":1034,"column":6},"end":{"line":1034,"column":22}},"336":{"start":{"line":1038,"column":4},"end":{"line":1038,"column":14}},"337":{"start":{"line":1048,"column":4},"end":{"line":1048,"column":21}},"338":{"start":{"line":1050,"column":4},"end":{"line":1050,"column":27}},"339":{"start":{"line":1052,"column":4},"end":{"line":1055,"column":null}},"340":{"start":{"line":1054,"column":6},"end":{"line":1054,"column":16}},"341":{"start":{"line":1057,"column":4},"end":{"line":1057,"column":28}},"342":{"start":{"line":1059,"column":4},"end":{"line":1114,"column":null}},"343":{"start":{"line":1061,"column":6},"end":{"line":1061,"column":23}},"344":{"start":{"line":1063,"column":6},"end":{"line":1074,"column":null}},"345":{"start":{"line":1065,"column":8},"end":{"line":1065,"column":20}},"346":{"start":{"line":1067,"column":8},"end":{"line":1067,"column":22}},"347":{"start":{"line":1071,"column":8},"end":{"line":1071,"column":24}},"348":{"start":{"line":1073,"column":8},"end":{"line":1073,"column":null}},"349":{"start":{"line":1073,"column":37},"end":{"line":1073,"column":54}},"350":{"start":{"line":1076,"column":6},"end":{"line":1098,"column":null}},"351":{"start":{"line":1078,"column":8},"end":{"line":1078,"column":32}},"352":{"start":{"line":1080,"column":8},"end":{"line":1091,"column":null}},"353":{"start":{"line":1082,"column":10},"end":{"line":1082,"column":24}},"354":{"start":{"line":1084,"column":10},"end":{"line":1084,"column":18}},"355":{"start":{"line":1088,"column":10},"end":{"line":1088,"column":27}},"356":{"start":{"line":1090,"column":10},"end":{"line":1090,"column":26}},"357":{"start":{"line":1095,"column":8},"end":{"line":1095,"column":25}},"358":{"start":{"line":1097,"column":8},"end":{"line":1097,"column":24}},"359":{"start":{"line":1100,"column":6},"end":{"line":1103,"column":null}},"360":{"start":{"line":1102,"column":8},"end":{"line":1102,"column":18}},"361":{"start":{"line":1105,"column":6},"end":{"line":1105,"column":24}},"362":{"start":{"line":1107,"column":6},"end":{"line":1107,"column":30}},"363":{"start":{"line":1111,"column":6},"end":{"line":1111,"column":23}},"364":{"start":{"line":1113,"column":6},"end":{"line":1113,"column":22}},"365":{"start":{"line":1117,"column":4},"end":{"line":1117,"column":14}},"366":{"start":{"line":1127,"column":4},"end":{"line":1127,"column":21}},"367":{"start":{"line":1129,"column":4},"end":{"line":1140,"column":null}},"368":{"start":{"line":1131,"column":6},"end":{"line":1131,"column":18}},"369":{"start":{"line":1133,"column":6},"end":{"line":1133,"column":20}},"370":{"start":{"line":1137,"column":6},"end":{"line":1137,"column":22}},"371":{"start":{"line":1139,"column":6},"end":{"line":1139,"column":null}},"372":{"start":{"line":1139,"column":35},"end":{"line":1139,"column":52}},"373":{"start":{"line":1142,"column":4},"end":{"line":1166,"column":null}},"374":{"start":{"line":1144,"column":6},"end":{"line":1144,"column":24}},"375":{"start":{"line":1146,"column":6},"end":{"line":1146,"column":39}},"376":{"start":{"line":1148,"column":6},"end":{"line":1159,"column":null}},"377":{"start":{"line":1150,"column":8},"end":{"line":1150,"column":26}},"378":{"start":{"line":1152,"column":8},"end":{"line":1152,"column":24}},"379":{"start":{"line":1156,"column":8},"end":{"line":1156,"column":25}},"380":{"start":{"line":1158,"column":8},"end":{"line":1158,"column":24}},"381":{"start":{"line":1163,"column":6},"end":{"line":1163,"column":23}},"382":{"start":{"line":1165,"column":6},"end":{"line":1165,"column":22}},"383":{"start":{"line":1169,"column":4},"end":{"line":1169,"column":14}},"384":{"start":{"line":1179,"column":4},"end":{"line":1179,"column":21}},"385":{"start":{"line":1181,"column":4},"end":{"line":1192,"column":null}},"386":{"start":{"line":1183,"column":6},"end":{"line":1183,"column":18}},"387":{"start":{"line":1185,"column":6},"end":{"line":1185,"column":20}},"388":{"start":{"line":1189,"column":6},"end":{"line":1189,"column":22}},"389":{"start":{"line":1191,"column":6},"end":{"line":1191,"column":null}},"390":{"start":{"line":1191,"column":35},"end":{"line":1191,"column":52}},"391":{"start":{"line":1194,"column":4},"end":{"line":1199,"column":null}},"392":{"start":{"line":1196,"column":6},"end":{"line":1196,"column":24}},"393":{"start":{"line":1198,"column":6},"end":{"line":1198,"column":20}},"394":{"start":{"line":1201,"column":4},"end":{"line":1201,"column":12}},"395":{"start":{"line":1204,"column":4},"end":{"line":1204,"column":14}},"396":{"start":{"line":1214,"column":4},"end":{"line":1214,"column":21}},"397":{"start":{"line":1216,"column":4},"end":{"line":1227,"column":null}},"398":{"start":{"line":1218,"column":6},"end":{"line":1218,"column":18}},"399":{"start":{"line":1220,"column":6},"end":{"line":1220,"column":20}},"400":{"start":{"line":1224,"column":6},"end":{"line":1224,"column":22}},"401":{"start":{"line":1226,"column":6},"end":{"line":1226,"column":null}},"402":{"start":{"line":1226,"column":35},"end":{"line":1226,"column":52}},"403":{"start":{"line":1229,"column":4},"end":{"line":1234,"column":null}},"404":{"start":{"line":1231,"column":6},"end":{"line":1231,"column":24}},"405":{"start":{"line":1233,"column":6},"end":{"line":1233,"column":20}},"406":{"start":{"line":1236,"column":4},"end":{"line":1236,"column":12}},"407":{"start":{"line":1239,"column":4},"end":{"line":1239,"column":14}},"408":{"start":{"line":1249,"column":4},"end":{"line":1249,"column":21}},"409":{"start":{"line":1251,"column":4},"end":{"line":1262,"column":null}},"410":{"start":{"line":1253,"column":6},"end":{"line":1253,"column":18}},"411":{"start":{"line":1255,"column":6},"end":{"line":1255,"column":23}},"412":{"start":{"line":1259,"column":6},"end":{"line":1259,"column":22}},"413":{"start":{"line":1261,"column":6},"end":{"line":1261,"column":null}},"414":{"start":{"line":1261,"column":35},"end":{"line":1261,"column":52}},"415":{"start":{"line":1264,"column":4},"end":{"line":1269,"column":null}},"416":{"start":{"line":1266,"column":6},"end":{"line":1266,"column":24}},"417":{"start":{"line":1268,"column":6},"end":{"line":1268,"column":20}},"418":{"start":{"line":1271,"column":4},"end":{"line":1271,"column":12}},"419":{"start":{"line":1273,"column":4},"end":{"line":1460,"column":null}},"420":{"start":{"line":1275,"column":6},"end":{"line":1275,"column":23}},"421":{"start":{"line":1277,"column":6},"end":{"line":1288,"column":null}},"422":{"start":{"line":1279,"column":8},"end":{"line":1279,"column":20}},"423":{"start":{"line":1281,"column":8},"end":{"line":1281,"column":25}},"424":{"start":{"line":1285,"column":8},"end":{"line":1285,"column":24}},"425":{"start":{"line":1287,"column":8},"end":{"line":1287,"column":null}},"426":{"start":{"line":1287,"column":37},"end":{"line":1287,"column":54}},"427":{"start":{"line":1290,"column":6},"end":{"line":1295,"column":null}},"428":{"start":{"line":1292,"column":8},"end":{"line":1292,"column":26}},"429":{"start":{"line":1294,"column":8},"end":{"line":1294,"column":22}},"430":{"start":{"line":1297,"column":6},"end":{"line":1297,"column":14}},"431":{"start":{"line":1299,"column":6},"end":{"line":1459,"column":null}},"432":{"start":{"line":1301,"column":8},"end":{"line":1301,"column":25}},"433":{"start":{"line":1303,"column":8},"end":{"line":1314,"column":null}},"434":{"start":{"line":1305,"column":10},"end":{"line":1305,"column":22}},"435":{"start":{"line":1307,"column":10},"end":{"line":1307,"column":24}},"436":{"start":{"line":1311,"column":10},"end":{"line":1311,"column":26}},"437":{"start":{"line":1313,"column":10},"end":{"line":1313,"column":null}},"438":{"start":{"line":1313,"column":39},"end":{"line":1313,"column":56}},"439":{"start":{"line":1316,"column":8},"end":{"line":1321,"column":null}},"440":{"start":{"line":1318,"column":10},"end":{"line":1318,"column":28}},"441":{"start":{"line":1320,"column":10},"end":{"line":1320,"column":24}},"442":{"start":{"line":1323,"column":8},"end":{"line":1323,"column":16}},"443":{"start":{"line":1325,"column":8},"end":{"line":1458,"column":null}},"444":{"start":{"line":1327,"column":10},"end":{"line":1327,"column":27}},"445":{"start":{"line":1329,"column":10},"end":{"line":1340,"column":null}},"446":{"start":{"line":1331,"column":12},"end":{"line":1331,"column":25}},"447":{"start":{"line":1333,"column":12},"end":{"line":1333,"column":26}},"448":{"start":{"line":1337,"column":12},"end":{"line":1337,"column":28}},"449":{"start":{"line":1339,"column":12},"end":{"line":1339,"column":null}},"450":{"start":{"line":1339,"column":41},"end":{"line":1339,"column":59}},"451":{"start":{"line":1342,"column":10},"end":{"line":1347,"column":null}},"452":{"start":{"line":1344,"column":12},"end":{"line":1344,"column":30}},"453":{"start":{"line":1346,"column":12},"end":{"line":1346,"column":26}},"454":{"start":{"line":1349,"column":10},"end":{"line":1349,"column":18}},"455":{"start":{"line":1351,"column":10},"end":{"line":1457,"column":null}},"456":{"start":{"line":1353,"column":12},"end":{"line":1353,"column":29}},"457":{"start":{"line":1355,"column":12},"end":{"line":1366,"column":null}},"458":{"start":{"line":1357,"column":14},"end":{"line":1357,"column":27}},"459":{"start":{"line":1359,"column":14},"end":{"line":1359,"column":28}},"460":{"start":{"line":1363,"column":14},"end":{"line":1363,"column":30}},"461":{"start":{"line":1365,"column":14},"end":{"line":1365,"column":null}},"462":{"start":{"line":1365,"column":43},"end":{"line":1365,"column":61}},"463":{"start":{"line":1368,"column":12},"end":{"line":1373,"column":null}},"464":{"start":{"line":1370,"column":14},"end":{"line":1370,"column":32}},"465":{"start":{"line":1372,"column":14},"end":{"line":1372,"column":29}},"466":{"start":{"line":1375,"column":12},"end":{"line":1375,"column":20}},"467":{"start":{"line":1377,"column":12},"end":{"line":1456,"column":null}},"468":{"start":{"line":1379,"column":14},"end":{"line":1379,"column":31}},"469":{"start":{"line":1381,"column":14},"end":{"line":1392,"column":null}},"470":{"start":{"line":1383,"column":16},"end":{"line":1383,"column":29}},"471":{"start":{"line":1385,"column":16},"end":{"line":1385,"column":33}},"472":{"start":{"line":1389,"column":16},"end":{"line":1389,"column":32}},"473":{"start":{"line":1391,"column":16},"end":{"line":1391,"column":null}},"474":{"start":{"line":1391,"column":45},"end":{"line":1391,"column":63}},"475":{"start":{"line":1394,"column":14},"end":{"line":1399,"column":null}},"476":{"start":{"line":1396,"column":16},"end":{"line":1396,"column":34}},"477":{"start":{"line":1398,"column":16},"end":{"line":1398,"column":31}},"478":{"start":{"line":1401,"column":14},"end":{"line":1401,"column":22}},"479":{"start":{"line":1403,"column":14},"end":{"line":1455,"column":null}},"480":{"start":{"line":1405,"column":16},"end":{"line":1405,"column":33}},"481":{"start":{"line":1407,"column":16},"end":{"line":1418,"column":null}},"482":{"start":{"line":1409,"column":18},"end":{"line":1409,"column":31}},"483":{"start":{"line":1411,"column":18},"end":{"line":1411,"column":32}},"484":{"start":{"line":1415,"column":18},"end":{"line":1415,"column":34}},"485":{"start":{"line":1417,"column":18},"end":{"line":1417,"column":null}},"486":{"start":{"line":1417,"column":47},"end":{"line":1417,"column":65}},"487":{"start":{"line":1420,"column":16},"end":{"line":1425,"column":null}},"488":{"start":{"line":1422,"column":18},"end":{"line":1422,"column":36}},"489":{"start":{"line":1424,"column":18},"end":{"line":1424,"column":33}},"490":{"start":{"line":1427,"column":16},"end":{"line":1427,"column":24}},"491":{"start":{"line":1429,"column":16},"end":{"line":1454,"column":null}},"492":{"start":{"line":1431,"column":18},"end":{"line":1431,"column":35}},"493":{"start":{"line":1433,"column":18},"end":{"line":1444,"column":null}},"494":{"start":{"line":1435,"column":20},"end":{"line":1435,"column":33}},"495":{"start":{"line":1437,"column":20},"end":{"line":1437,"column":34}},"496":{"start":{"line":1441,"column":20},"end":{"line":1441,"column":36}},"497":{"start":{"line":1443,"column":20},"end":{"line":1443,"column":null}},"498":{"start":{"line":1443,"column":49},"end":{"line":1443,"column":67}},"499":{"start":{"line":1446,"column":18},"end":{"line":1451,"column":null}},"500":{"start":{"line":1448,"column":20},"end":{"line":1448,"column":38}},"501":{"start":{"line":1450,"column":20},"end":{"line":1450,"column":35}},"502":{"start":{"line":1453,"column":18},"end":{"line":1453,"column":26}},"503":{"start":{"line":1463,"column":4},"end":{"line":1463,"column":14}},"504":{"start":{"line":1473,"column":4},"end":{"line":1473,"column":21}},"505":{"start":{"line":1475,"column":4},"end":{"line":1475,"column":27}},"506":{"start":{"line":1477,"column":4},"end":{"line":1480,"column":null}},"507":{"start":{"line":1479,"column":6},"end":{"line":1479,"column":16}},"508":{"start":{"line":1482,"column":4},"end":{"line":1482,"column":28}},"509":{"start":{"line":1484,"column":4},"end":{"line":1528,"column":null}},"510":{"start":{"line":1486,"column":6},"end":{"line":1497,"column":null}},"511":{"start":{"line":1488,"column":8},"end":{"line":1488,"column":20}},"512":{"start":{"line":1490,"column":8},"end":{"line":1490,"column":22}},"513":{"start":{"line":1494,"column":8},"end":{"line":1494,"column":24}},"514":{"start":{"line":1496,"column":8},"end":{"line":1496,"column":null}},"515":{"start":{"line":1496,"column":37},"end":{"line":1496,"column":54}},"516":{"start":{"line":1499,"column":6},"end":{"line":1521,"column":null}},"517":{"start":{"line":1501,"column":8},"end":{"line":1501,"column":32}},"518":{"start":{"line":1503,"column":8},"end":{"line":1514,"column":null}},"519":{"start":{"line":1505,"column":10},"end":{"line":1505,"column":28}},"520":{"start":{"line":1507,"column":10},"end":{"line":1507,"column":35}},"521":{"start":{"line":1511,"column":10},"end":{"line":1511,"column":27}},"522":{"start":{"line":1513,"column":10},"end":{"line":1513,"column":26}},"523":{"start":{"line":1518,"column":8},"end":{"line":1518,"column":25}},"524":{"start":{"line":1520,"column":8},"end":{"line":1520,"column":24}},"525":{"start":{"line":1525,"column":6},"end":{"line":1525,"column":23}},"526":{"start":{"line":1527,"column":6},"end":{"line":1527,"column":22}},"527":{"start":{"line":1531,"column":4},"end":{"line":1531,"column":14}},"528":{"start":{"line":1541,"column":4},"end":{"line":1541,"column":21}},"529":{"start":{"line":1543,"column":4},"end":{"line":1543,"column":26}},"530":{"start":{"line":1545,"column":4},"end":{"line":1666,"column":null}},"531":{"start":{"line":1547,"column":6},"end":{"line":1558,"column":null}},"532":{"start":{"line":1549,"column":8},"end":{"line":1549,"column":21}},"533":{"start":{"line":1551,"column":8},"end":{"line":1551,"column":22}},"534":{"start":{"line":1555,"column":8},"end":{"line":1555,"column":24}},"535":{"start":{"line":1557,"column":8},"end":{"line":1557,"column":null}},"536":{"start":{"line":1557,"column":37},"end":{"line":1557,"column":55}},"537":{"start":{"line":1560,"column":6},"end":{"line":1659,"column":null}},"538":{"start":{"line":1562,"column":8},"end":{"line":1562,"column":30}},"539":{"start":{"line":1564,"column":8},"end":{"line":1652,"column":null}},"540":{"start":{"line":1566,"column":10},"end":{"line":1577,"column":null}},"541":{"start":{"line":1568,"column":12},"end":{"line":1568,"column":25}},"542":{"start":{"line":1570,"column":12},"end":{"line":1570,"column":26}},"543":{"start":{"line":1574,"column":12},"end":{"line":1574,"column":28}},"544":{"start":{"line":1576,"column":12},"end":{"line":1576,"column":null}},"545":{"start":{"line":1576,"column":41},"end":{"line":1576,"column":59}},"546":{"start":{"line":1579,"column":10},"end":{"line":1645,"column":null}},"547":{"start":{"line":1581,"column":12},"end":{"line":1581,"column":34}},"548":{"start":{"line":1583,"column":12},"end":{"line":1638,"column":null}},"549":{"start":{"line":1585,"column":14},"end":{"line":1585,"column":31}},"550":{"start":{"line":1587,"column":14},"end":{"line":1598,"column":null}},"551":{"start":{"line":1589,"column":16},"end":{"line":1589,"column":29}},"552":{"start":{"line":1591,"column":16},"end":{"line":1591,"column":30}},"553":{"start":{"line":1595,"column":16},"end":{"line":1595,"column":32}},"554":{"start":{"line":1597,"column":16},"end":{"line":1597,"column":null}},"555":{"start":{"line":1597,"column":45},"end":{"line":1597,"column":63}},"556":{"start":{"line":1600,"column":14},"end":{"line":1622,"column":null}},"557":{"start":{"line":1602,"column":16},"end":{"line":1602,"column":38}},"558":{"start":{"line":1604,"column":16},"end":{"line":1615,"column":null}},"559":{"start":{"line":1606,"column":18},"end":{"line":1606,"column":32}},"560":{"start":{"line":1608,"column":18},"end":{"line":1608,"column":26}},"561":{"start":{"line":1612,"column":18},"end":{"line":1612,"column":35}},"562":{"start":{"line":1614,"column":18},"end":{"line":1614,"column":34}},"563":{"start":{"line":1619,"column":16},"end":{"line":1619,"column":33}},"564":{"start":{"line":1621,"column":16},"end":{"line":1621,"column":32}},"565":{"start":{"line":1624,"column":14},"end":{"line":1627,"column":null}},"566":{"start":{"line":1626,"column":16},"end":{"line":1626,"column":26}},"567":{"start":{"line":1629,"column":14},"end":{"line":1629,"column":32}},"568":{"start":{"line":1631,"column":14},"end":{"line":1631,"column":39}},"569":{"start":{"line":1635,"column":14},"end":{"line":1635,"column":31}},"570":{"start":{"line":1637,"column":14},"end":{"line":1637,"column":30}},"571":{"start":{"line":1642,"column":12},"end":{"line":1642,"column":29}},"572":{"start":{"line":1644,"column":12},"end":{"line":1644,"column":28}},"573":{"start":{"line":1649,"column":10},"end":{"line":1649,"column":27}},"574":{"start":{"line":1651,"column":10},"end":{"line":1651,"column":26}},"575":{"start":{"line":1656,"column":8},"end":{"line":1656,"column":25}},"576":{"start":{"line":1658,"column":8},"end":{"line":1658,"column":24}},"577":{"start":{"line":1663,"column":6},"end":{"line":1663,"column":23}},"578":{"start":{"line":1665,"column":6},"end":{"line":1665,"column":22}},"579":{"start":{"line":1669,"column":4},"end":{"line":1669,"column":14}},"580":{"start":{"line":1679,"column":4},"end":{"line":1679,"column":21}},"581":{"start":{"line":1681,"column":4},"end":{"line":1692,"column":null}},"582":{"start":{"line":1683,"column":6},"end":{"line":1683,"column":19}},"583":{"start":{"line":1685,"column":6},"end":{"line":1685,"column":20}},"584":{"start":{"line":1689,"column":6},"end":{"line":1689,"column":22}},"585":{"start":{"line":1691,"column":6},"end":{"line":1691,"column":null}},"586":{"start":{"line":1691,"column":35},"end":{"line":1691,"column":53}},"587":{"start":{"line":1694,"column":4},"end":{"line":1738,"column":null}},"588":{"start":{"line":1696,"column":6},"end":{"line":1696,"column":32}},"589":{"start":{"line":1698,"column":6},"end":{"line":1731,"column":null}},"590":{"start":{"line":1700,"column":8},"end":{"line":1711,"column":null}},"591":{"start":{"line":1702,"column":10},"end":{"line":1702,"column":22}},"592":{"start":{"line":1704,"column":10},"end":{"line":1704,"column":24}},"593":{"start":{"line":1708,"column":10},"end":{"line":1708,"column":26}},"594":{"start":{"line":1710,"column":10},"end":{"line":1710,"column":null}},"595":{"start":{"line":1710,"column":39},"end":{"line":1710,"column":56}},"596":{"start":{"line":1713,"column":8},"end":{"line":1724,"column":null}},"597":{"start":{"line":1715,"column":10},"end":{"line":1715,"column":28}},"598":{"start":{"line":1717,"column":10},"end":{"line":1717,"column":27}},"599":{"start":{"line":1721,"column":10},"end":{"line":1721,"column":27}},"600":{"start":{"line":1723,"column":10},"end":{"line":1723,"column":26}},"601":{"start":{"line":1728,"column":8},"end":{"line":1728,"column":25}},"602":{"start":{"line":1730,"column":8},"end":{"line":1730,"column":24}},"603":{"start":{"line":1735,"column":6},"end":{"line":1735,"column":23}},"604":{"start":{"line":1737,"column":6},"end":{"line":1737,"column":22}},"605":{"start":{"line":1741,"column":4},"end":{"line":1741,"column":14}},"606":{"start":{"line":1751,"column":4},"end":{"line":1751,"column":21}},"607":{"start":{"line":1753,"column":4},"end":{"line":1753,"column":12}},"608":{"start":{"line":1755,"column":4},"end":{"line":1766,"column":null}},"609":{"start":{"line":1757,"column":6},"end":{"line":1757,"column":37}},"610":{"start":{"line":1759,"column":6},"end":{"line":1759,"column":20}},"611":{"start":{"line":1763,"column":6},"end":{"line":1763,"column":22}},"612":{"start":{"line":1765,"column":6},"end":{"line":1765,"column":null}},"613":{"start":{"line":1765,"column":35},"end":{"line":1765,"column":53}},"614":{"start":{"line":1768,"column":4},"end":{"line":1791,"column":null}},"615":{"start":{"line":1770,"column":6},"end":{"line":1786,"column":null}},"616":{"start":{"line":1772,"column":8},"end":{"line":1772,"column":20}},"617":{"start":{"line":1774,"column":8},"end":{"line":1785,"column":null}},"618":{"start":{"line":1776,"column":10},"end":{"line":1776,"column":41}},"619":{"start":{"line":1778,"column":10},"end":{"line":1778,"column":24}},"620":{"start":{"line":1782,"column":10},"end":{"line":1782,"column":26}},"621":{"start":{"line":1784,"column":10},"end":{"line":1784,"column":null}},"622":{"start":{"line":1784,"column":39},"end":{"line":1784,"column":57}},"623":{"start":{"line":1790,"column":6},"end":{"line":1790,"column":22}},"624":{"start":{"line":1793,"column":4},"end":{"line":1798,"column":null}},"625":{"start":{"line":1795,"column":6},"end":{"line":1795,"column":24}},"626":{"start":{"line":1797,"column":6},"end":{"line":1797,"column":21}},"627":{"start":{"line":1800,"column":4},"end":{"line":1800,"column":12}},"628":{"start":{"line":1803,"column":4},"end":{"line":1803,"column":14}},"629":{"start":{"line":1813,"column":4},"end":{"line":1813,"column":21}},"630":{"start":{"line":1815,"column":4},"end":{"line":1815,"column":12}},"631":{"start":{"line":1817,"column":4},"end":{"line":1828,"column":null}},"632":{"start":{"line":1819,"column":6},"end":{"line":1819,"column":37}},"633":{"start":{"line":1821,"column":6},"end":{"line":1821,"column":20}},"634":{"start":{"line":1825,"column":6},"end":{"line":1825,"column":22}},"635":{"start":{"line":1827,"column":6},"end":{"line":1827,"column":null}},"636":{"start":{"line":1827,"column":35},"end":{"line":1827,"column":53}},"637":{"start":{"line":1830,"column":4},"end":{"line":1853,"column":null}},"638":{"start":{"line":1832,"column":6},"end":{"line":1848,"column":null}},"639":{"start":{"line":1834,"column":8},"end":{"line":1834,"column":20}},"640":{"start":{"line":1836,"column":8},"end":{"line":1847,"column":null}},"641":{"start":{"line":1838,"column":10},"end":{"line":1838,"column":41}},"642":{"start":{"line":1840,"column":10},"end":{"line":1840,"column":24}},"643":{"start":{"line":1844,"column":10},"end":{"line":1844,"column":26}},"644":{"start":{"line":1846,"column":10},"end":{"line":1846,"column":null}},"645":{"start":{"line":1846,"column":39},"end":{"line":1846,"column":57}},"646":{"start":{"line":1852,"column":6},"end":{"line":1852,"column":22}},"647":{"start":{"line":1855,"column":4},"end":{"line":1860,"column":null}},"648":{"start":{"line":1857,"column":6},"end":{"line":1857,"column":24}},"649":{"start":{"line":1859,"column":6},"end":{"line":1859,"column":21}},"650":{"start":{"line":1862,"column":4},"end":{"line":1862,"column":12}},"651":{"start":{"line":1865,"column":4},"end":{"line":1865,"column":14}},"652":{"start":{"line":1875,"column":4},"end":{"line":1875,"column":21}},"653":{"start":{"line":1877,"column":4},"end":{"line":1877,"column":34}},"654":{"start":{"line":1879,"column":4},"end":{"line":1897,"column":null}},"655":{"start":{"line":1881,"column":6},"end":{"line":1881,"column":33}},"656":{"start":{"line":1883,"column":6},"end":{"line":1886,"column":null}},"657":{"start":{"line":1885,"column":8},"end":{"line":1885,"column":18}},"658":{"start":{"line":1888,"column":6},"end":{"line":1888,"column":24}},"659":{"start":{"line":1890,"column":6},"end":{"line":1890,"column":27}},"660":{"start":{"line":1894,"column":6},"end":{"line":1894,"column":23}},"661":{"start":{"line":1896,"column":6},"end":{"line":1896,"column":22}},"662":{"start":{"line":1900,"column":4},"end":{"line":1900,"column":14}},"663":{"start":{"line":1910,"column":4},"end":{"line":1910,"column":21}},"664":{"start":{"line":1912,"column":4},"end":{"line":1923,"column":null}},"665":{"start":{"line":1914,"column":6},"end":{"line":1914,"column":19}},"666":{"start":{"line":1916,"column":6},"end":{"line":1916,"column":20}},"667":{"start":{"line":1920,"column":6},"end":{"line":1920,"column":22}},"668":{"start":{"line":1922,"column":6},"end":{"line":1922,"column":null}},"669":{"start":{"line":1922,"column":35},"end":{"line":1922,"column":53}},"670":{"start":{"line":1925,"column":4},"end":{"line":2032,"column":null}},"671":{"start":{"line":1927,"column":6},"end":{"line":1927,"column":40}},"672":{"start":{"line":1929,"column":6},"end":{"line":2025,"column":null}},"673":{"start":{"line":1931,"column":8},"end":{"line":1931,"column":16}},"674":{"start":{"line":1933,"column":8},"end":{"line":1933,"column":25}},"675":{"start":{"line":1935,"column":8},"end":{"line":1946,"column":null}},"676":{"start":{"line":1937,"column":10},"end":{"line":1937,"column":23}},"677":{"start":{"line":1939,"column":10},"end":{"line":1939,"column":24}},"678":{"start":{"line":1943,"column":10},"end":{"line":1943,"column":26}},"679":{"start":{"line":1945,"column":10},"end":{"line":1945,"column":null}},"680":{"start":{"line":1945,"column":39},"end":{"line":1945,"column":57}},"681":{"start":{"line":1948,"column":8},"end":{"line":1970,"column":null}},"682":{"start":{"line":1950,"column":10},"end":{"line":1950,"column":44}},"683":{"start":{"line":1952,"column":10},"end":{"line":1963,"column":null}},"684":{"start":{"line":1954,"column":12},"end":{"line":1954,"column":26}},"685":{"start":{"line":1956,"column":12},"end":{"line":1956,"column":20}},"686":{"start":{"line":1960,"column":12},"end":{"line":1960,"column":29}},"687":{"start":{"line":1962,"column":12},"end":{"line":1962,"column":28}},"688":{"start":{"line":1967,"column":10},"end":{"line":1967,"column":27}},"689":{"start":{"line":1969,"column":10},"end":{"line":1969,"column":26}},"690":{"start":{"line":1972,"column":8},"end":{"line":2014,"column":null}},"691":{"start":{"line":1974,"column":10},"end":{"line":1974,"column":22}},"692":{"start":{"line":1976,"column":10},"end":{"line":1976,"column":27}},"693":{"start":{"line":1978,"column":10},"end":{"line":1989,"column":null}},"694":{"start":{"line":1980,"column":12},"end":{"line":1980,"column":25}},"695":{"start":{"line":1982,"column":12},"end":{"line":1982,"column":26}},"696":{"start":{"line":1986,"column":12},"end":{"line":1986,"column":28}},"697":{"start":{"line":1988,"column":12},"end":{"line":1988,"column":null}},"698":{"start":{"line":1988,"column":41},"end":{"line":1988,"column":59}},"699":{"start":{"line":1991,"column":10},"end":{"line":2013,"column":null}},"700":{"start":{"line":1993,"column":12},"end":{"line":1993,"column":46}},"701":{"start":{"line":1995,"column":12},"end":{"line":2006,"column":null}},"702":{"start":{"line":1997,"column":14},"end":{"line":1997,"column":28}},"703":{"start":{"line":1999,"column":14},"end":{"line":1999,"column":22}},"704":{"start":{"line":2003,"column":14},"end":{"line":2003,"column":31}},"705":{"start":{"line":2005,"column":14},"end":{"line":2005,"column":30}},"706":{"start":{"line":2010,"column":12},"end":{"line":2010,"column":29}},"707":{"start":{"line":2012,"column":12},"end":{"line":2012,"column":28}},"708":{"start":{"line":2016,"column":8},"end":{"line":2016,"column":26}},"709":{"start":{"line":2018,"column":8},"end":{"line":2018,"column":29}},"710":{"start":{"line":2022,"column":8},"end":{"line":2022,"column":25}},"711":{"start":{"line":2024,"column":8},"end":{"line":2024,"column":24}},"712":{"start":{"line":2029,"column":6},"end":{"line":2029,"column":23}},"713":{"start":{"line":2031,"column":6},"end":{"line":2031,"column":22}},"714":{"start":{"line":2035,"column":4},"end":{"line":2035,"column":14}},"715":{"start":{"line":2045,"column":4},"end":{"line":2045,"column":21}},"716":{"start":{"line":2047,"column":4},"end":{"line":2058,"column":null}},"717":{"start":{"line":2049,"column":6},"end":{"line":2049,"column":19}},"718":{"start":{"line":2051,"column":6},"end":{"line":2051,"column":20}},"719":{"start":{"line":2055,"column":6},"end":{"line":2055,"column":22}},"720":{"start":{"line":2057,"column":6},"end":{"line":2057,"column":null}},"721":{"start":{"line":2057,"column":35},"end":{"line":2057,"column":53}},"722":{"start":{"line":2060,"column":4},"end":{"line":2063,"column":null}},"723":{"start":{"line":2062,"column":6},"end":{"line":2062,"column":16}},"724":{"start":{"line":2065,"column":4},"end":{"line":2065,"column":26}},"725":{"start":{"line":2067,"column":4},"end":{"line":2070,"column":null}},"726":{"start":{"line":2069,"column":6},"end":{"line":2069,"column":29}},"727":{"start":{"line":2072,"column":4},"end":{"line":2083,"column":null}},"728":{"start":{"line":2074,"column":6},"end":{"line":2074,"column":24}},"729":{"start":{"line":2076,"column":6},"end":{"line":2076,"column":23}},"730":{"start":{"line":2080,"column":6},"end":{"line":2080,"column":23}},"731":{"start":{"line":2082,"column":6},"end":{"line":2082,"column":22}},"732":{"start":{"line":2086,"column":4},"end":{"line":2086,"column":14}},"733":{"start":{"line":2096,"column":4},"end":{"line":2096,"column":21}},"734":{"start":{"line":2098,"column":4},"end":{"line":2098,"column":26}},"735":{"start":{"line":2100,"column":4},"end":{"line":2196,"column":null}},"736":{"start":{"line":2102,"column":6},"end":{"line":2102,"column":14}},"737":{"start":{"line":2104,"column":6},"end":{"line":2104,"column":23}},"738":{"start":{"line":2106,"column":6},"end":{"line":2117,"column":null}},"739":{"start":{"line":2108,"column":8},"end":{"line":2108,"column":21}},"740":{"start":{"line":2110,"column":8},"end":{"line":2110,"column":22}},"741":{"start":{"line":2114,"column":8},"end":{"line":2114,"column":24}},"742":{"start":{"line":2116,"column":8},"end":{"line":2116,"column":null}},"743":{"start":{"line":2116,"column":37},"end":{"line":2116,"column":55}},"744":{"start":{"line":2119,"column":6},"end":{"line":2141,"column":null}},"745":{"start":{"line":2121,"column":8},"end":{"line":2121,"column":30}},"746":{"start":{"line":2123,"column":8},"end":{"line":2134,"column":null}},"747":{"start":{"line":2125,"column":10},"end":{"line":2125,"column":24}},"748":{"start":{"line":2127,"column":10},"end":{"line":2127,"column":18}},"749":{"start":{"line":2131,"column":10},"end":{"line":2131,"column":27}},"750":{"start":{"line":2133,"column":10},"end":{"line":2133,"column":26}},"751":{"start":{"line":2138,"column":8},"end":{"line":2138,"column":25}},"752":{"start":{"line":2140,"column":8},"end":{"line":2140,"column":24}},"753":{"start":{"line":2143,"column":6},"end":{"line":2185,"column":null}},"754":{"start":{"line":2145,"column":8},"end":{"line":2145,"column":20}},"755":{"start":{"line":2147,"column":8},"end":{"line":2147,"column":25}},"756":{"start":{"line":2149,"column":8},"end":{"line":2160,"column":null}},"757":{"start":{"line":2151,"column":10},"end":{"line":2151,"column":23}},"758":{"start":{"line":2153,"column":10},"end":{"line":2153,"column":24}},"759":{"start":{"line":2157,"column":10},"end":{"line":2157,"column":26}},"760":{"start":{"line":2159,"column":10},"end":{"line":2159,"column":null}},"761":{"start":{"line":2159,"column":39},"end":{"line":2159,"column":57}},"762":{"start":{"line":2162,"column":8},"end":{"line":2184,"column":null}},"763":{"start":{"line":2164,"column":10},"end":{"line":2164,"column":32}},"764":{"start":{"line":2166,"column":10},"end":{"line":2177,"column":null}},"765":{"start":{"line":2168,"column":12},"end":{"line":2168,"column":26}},"766":{"start":{"line":2170,"column":12},"end":{"line":2170,"column":20}},"767":{"start":{"line":2174,"column":12},"end":{"line":2174,"column":29}},"768":{"start":{"line":2176,"column":12},"end":{"line":2176,"column":28}},"769":{"start":{"line":2181,"column":10},"end":{"line":2181,"column":27}},"770":{"start":{"line":2183,"column":10},"end":{"line":2183,"column":26}},"771":{"start":{"line":2187,"column":6},"end":{"line":2187,"column":24}},"772":{"start":{"line":2189,"column":6},"end":{"line":2189,"column":27}},"773":{"start":{"line":2193,"column":6},"end":{"line":2193,"column":23}},"774":{"start":{"line":2195,"column":6},"end":{"line":2195,"column":22}},"775":{"start":{"line":2199,"column":4},"end":{"line":2199,"column":14}},"776":{"start":{"line":2209,"column":4},"end":{"line":2209,"column":21}},"777":{"start":{"line":2211,"column":4},"end":{"line":2211,"column":12}},"778":{"start":{"line":2213,"column":4},"end":{"line":2224,"column":null}},"779":{"start":{"line":2215,"column":6},"end":{"line":2215,"column":37}},"780":{"start":{"line":2217,"column":6},"end":{"line":2217,"column":20}},"781":{"start":{"line":2221,"column":6},"end":{"line":2221,"column":22}},"782":{"start":{"line":2223,"column":6},"end":{"line":2223,"column":null}},"783":{"start":{"line":2223,"column":35},"end":{"line":2223,"column":53}},"784":{"start":{"line":2226,"column":4},"end":{"line":2249,"column":null}},"785":{"start":{"line":2228,"column":6},"end":{"line":2244,"column":null}},"786":{"start":{"line":2230,"column":8},"end":{"line":2230,"column":20}},"787":{"start":{"line":2232,"column":8},"end":{"line":2243,"column":null}},"788":{"start":{"line":2234,"column":10},"end":{"line":2234,"column":41}},"789":{"start":{"line":2236,"column":10},"end":{"line":2236,"column":24}},"790":{"start":{"line":2240,"column":10},"end":{"line":2240,"column":26}},"791":{"start":{"line":2242,"column":10},"end":{"line":2242,"column":null}},"792":{"start":{"line":2242,"column":39},"end":{"line":2242,"column":57}},"793":{"start":{"line":2248,"column":6},"end":{"line":2248,"column":22}},"794":{"start":{"line":2251,"column":4},"end":{"line":2256,"column":null}},"795":{"start":{"line":2253,"column":6},"end":{"line":2253,"column":24}},"796":{"start":{"line":2255,"column":6},"end":{"line":2255,"column":21}},"797":{"start":{"line":2258,"column":4},"end":{"line":2258,"column":12}},"798":{"start":{"line":2261,"column":4},"end":{"line":2261,"column":14}},"799":{"start":{"line":2271,"column":4},"end":{"line":2271,"column":22}},"800":{"start":{"line":2273,"column":4},"end":{"line":2273,"column":12}},"801":{"start":{"line":2275,"column":4},"end":{"line":2286,"column":null}},"802":{"start":{"line":2277,"column":6},"end":{"line":2277,"column":37}},"803":{"start":{"line":2279,"column":6},"end":{"line":2279,"column":20}},"804":{"start":{"line":2283,"column":6},"end":{"line":2283,"column":22}},"805":{"start":{"line":2285,"column":6},"end":{"line":2285,"column":null}},"806":{"start":{"line":2285,"column":35},"end":{"line":2285,"column":53}},"807":{"start":{"line":2288,"column":4},"end":{"line":2304,"column":null}},"808":{"start":{"line":2290,"column":6},"end":{"line":2290,"column":18}},"809":{"start":{"line":2292,"column":6},"end":{"line":2303,"column":null}},"810":{"start":{"line":2294,"column":8},"end":{"line":2294,"column":39}},"811":{"start":{"line":2296,"column":8},"end":{"line":2296,"column":22}},"812":{"start":{"line":2300,"column":8},"end":{"line":2300,"column":24}},"813":{"start":{"line":2302,"column":8},"end":{"line":2302,"column":null}},"814":{"start":{"line":2302,"column":37},"end":{"line":2302,"column":55}},"815":{"start":{"line":2306,"column":4},"end":{"line":2306,"column":22}},"816":{"start":{"line":2308,"column":4},"end":{"line":2308,"column":20}},"817":{"start":{"line":2310,"column":4},"end":{"line":2310,"column":null}},"818":{"start":{"line":2310,"column":33},"end":{"line":2310,"column":51}},"819":{"start":{"line":2313,"column":4},"end":{"line":2313,"column":14}},"820":{"start":{"line":2317,"column":2},"end":{"line":2317,"column":39}},"821":{"start":{"line":2320,"column":2},"end":{"line":2344,"column":null}},"822":{"start":{"line":2322,"column":4},"end":{"line":2322,"column":22}},"823":{"start":{"line":2326,"column":4},"end":{"line":2329,"column":null}},"824":{"start":{"line":2328,"column":6},"end":{"line":2328,"column":37}},"825":{"start":{"line":2332,"column":4},"end":{"line":2343,"column":6}},"826":{"start":{"line":2348,"column":2},"end":{"line":2351,"column":4}},"827":{"start":{"line":2422,"column":0},"end":{"line":2422,"column":60}},"828":{"start":{"line":2457,"column":13},"end":{"line":2457,"column":54}},"829":{"start":{"line":2459,"column":13},"end":{"line":2459,"column":84}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":9,"column":1},"end":{"line":9,"column":null}},"loc":{"start":{"line":9,"column":1},"end":{"line":2352,"column":1}}},"1":{"name":"peg$subclass","decl":{"start":{"line":14,"column":9},"end":{"line":14,"column":21}},"loc":{"start":{"line":14,"column":35},"end":{"line":21,"column":1}}},"2":{"name":"C","decl":{"start":{"line":16,"column":11},"end":{"line":16,"column":12}},"loc":{"start":{"line":16,"column":12},"end":{"line":16,"column":44}}},"3":{"name":"peg$SyntaxError","decl":{"start":{"line":24,"column":9},"end":{"line":24,"column":24}},"loc":{"start":{"line":24,"column":59},"end":{"line":43,"column":1}}},"4":{"name":"peg$padEnd","decl":{"start":{"line":49,"column":9},"end":{"line":49,"column":19}},"loc":{"start":{"line":49,"column":48},"end":{"line":60,"column":1}}},"5":{"name":"(anonymous_5)","decl":{"start":{"line":63,"column":35},"end":{"line":63,"column":44}},"loc":{"start":{"line":63,"column":51},"end":{"line":122,"column":1}}},"6":{"name":"(anonymous_6)","decl":{"start":{"line":125,"column":31},"end":{"line":125,"column":40}},"loc":{"start":{"line":125,"column":55},"end":{"line":286,"column":1}}},"7":{"name":"(anonymous_7)","decl":{"start":{"line":129,"column":13},"end":{"line":129,"column":22}},"loc":{"start":{"line":129,"column":33},"end":{"line":132,"column":5}}},"8":{"name":"(anonymous_8)","decl":{"start":{"line":135,"column":11},"end":{"line":135,"column":20}},"loc":{"start":{"line":135,"column":31},"end":{"line":148,"column":5}}},"9":{"name":"(anonymous_9)","decl":{"start":{"line":137,"column":47},"end":{"line":137,"column":56}},"loc":{"start":{"line":137,"column":60},"end":{"line":144,"column":7}}},"10":{"name":"(anonymous_10)","decl":{"start":{"line":151,"column":9},"end":{"line":151,"column":null}},"loc":{"start":{"line":151,"column":9},"end":{"line":154,"column":5}}},"11":{"name":"(anonymous_11)","decl":{"start":{"line":157,"column":9},"end":{"line":157,"column":null}},"loc":{"start":{"line":157,"column":9},"end":{"line":160,"column":5}}},"12":{"name":"(anonymous_12)","decl":{"start":{"line":163,"column":11},"end":{"line":163,"column":20}},"loc":{"start":{"line":163,"column":31},"end":{"line":166,"column":5}}},"13":{"name":"hex","decl":{"start":{"line":170,"column":11},"end":{"line":170,"column":14}},"loc":{"start":{"line":170,"column":17},"end":{"line":173,"column":3}}},"14":{"name":"literalEscape","decl":{"start":{"line":176,"column":11},"end":{"line":176,"column":24}},"loc":{"start":{"line":176,"column":26},"end":{"line":195,"column":3}}},"15":{"name":"(anonymous_15)","decl":{"start":{"line":192,"column":40},"end":{"line":192,"column":49}},"loc":{"start":{"line":192,"column":51},"end":{"line":192,"column":81}}},"16":{"name":"(anonymous_16)","decl":{"start":{"line":194,"column":40},"end":{"line":194,"column":49}},"loc":{"start":{"line":194,"column":51},"end":{"line":194,"column":81}}},"17":{"name":"classEscape","decl":{"start":{"line":198,"column":11},"end":{"line":198,"column":22}},"loc":{"start":{"line":198,"column":24},"end":{"line":221,"column":3}}},"18":{"name":"(anonymous_18)","decl":{"start":{"line":218,"column":40},"end":{"line":218,"column":49}},"loc":{"start":{"line":218,"column":51},"end":{"line":218,"column":81}}},"19":{"name":"(anonymous_19)","decl":{"start":{"line":220,"column":40},"end":{"line":220,"column":49}},"loc":{"start":{"line":220,"column":51},"end":{"line":220,"column":81}}},"20":{"name":"describeExpectation","decl":{"start":{"line":224,"column":11},"end":{"line":224,"column":30}},"loc":{"start":{"line":224,"column":42},"end":{"line":227,"column":3}}},"21":{"name":"describeExpected","decl":{"start":{"line":230,"column":11},"end":{"line":230,"column":27}},"loc":{"start":{"line":230,"column":36},"end":{"line":276,"column":3}}},"22":{"name":"describeFound","decl":{"start":{"line":279,"column":11},"end":{"line":279,"column":24}},"loc":{"start":{"line":279,"column":30},"end":{"line":282,"column":3}}},"23":{"name":"peg$parse","decl":{"start":{"line":289,"column":9},"end":{"line":289,"column":18}},"loc":{"start":{"line":289,"column":33},"end":{"line":2345,"column":1}}},"24":{"name":"(anonymous_24)","decl":{"start":{"line":353,"column":15},"end":{"line":353,"column":24}},"loc":{"start":{"line":353,"column":28},"end":{"line":354,"column":34}}},"25":{"name":"(anonymous_25)","decl":{"start":{"line":356,"column":15},"end":{"line":356,"column":24}},"loc":{"start":{"line":356,"column":41},"end":{"line":357,"column":47}}},"26":{"name":"(anonymous_26)","decl":{"start":{"line":359,"column":15},"end":{"line":359,"column":24}},"loc":{"start":{"line":359,"column":52},"end":{"line":360,"column":120}}},"27":{"name":"(anonymous_27)","decl":{"start":{"line":362,"column":15},"end":{"line":362,"column":24}},"loc":{"start":{"line":362,"column":29},"end":{"line":363,"column":38}}},"28":{"name":"(anonymous_28)","decl":{"start":{"line":365,"column":15},"end":{"line":365,"column":null}},"loc":{"start":{"line":365,"column":15},"end":{"line":366,"column":25}}},"29":{"name":"(anonymous_29)","decl":{"start":{"line":368,"column":15},"end":{"line":368,"column":null}},"loc":{"start":{"line":368,"column":15},"end":{"line":369,"column":26}}},"30":{"name":"(anonymous_30)","decl":{"start":{"line":371,"column":15},"end":{"line":371,"column":null}},"loc":{"start":{"line":371,"column":15},"end":{"line":372,"column":15}}},"31":{"name":"(anonymous_31)","decl":{"start":{"line":374,"column":15},"end":{"line":374,"column":null}},"loc":{"start":{"line":374,"column":15},"end":{"line":375,"column":15}}},"32":{"name":"(anonymous_32)","decl":{"start":{"line":377,"column":15},"end":{"line":377,"column":null}},"loc":{"start":{"line":377,"column":15},"end":{"line":378,"column":14}}},"33":{"name":"(anonymous_33)","decl":{"start":{"line":380,"column":15},"end":{"line":380,"column":null}},"loc":{"start":{"line":380,"column":15},"end":{"line":381,"column":14}}},"34":{"name":"(anonymous_34)","decl":{"start":{"line":383,"column":16},"end":{"line":383,"column":null}},"loc":{"start":{"line":383,"column":16},"end":{"line":384,"column":14}}},"35":{"name":"(anonymous_35)","decl":{"start":{"line":386,"column":16},"end":{"line":386,"column":null}},"loc":{"start":{"line":386,"column":16},"end":{"line":387,"column":15}}},"36":{"name":"(anonymous_36)","decl":{"start":{"line":389,"column":16},"end":{"line":389,"column":null}},"loc":{"start":{"line":389,"column":16},"end":{"line":390,"column":14}}},"37":{"name":"(anonymous_37)","decl":{"start":{"line":392,"column":16},"end":{"line":392,"column":null}},"loc":{"start":{"line":392,"column":16},"end":{"line":393,"column":14}}},"38":{"name":"(anonymous_38)","decl":{"start":{"line":395,"column":16},"end":{"line":395,"column":25}},"loc":{"start":{"line":395,"column":53},"end":{"line":398,"column":3}}},"39":{"name":"(anonymous_39)","decl":{"start":{"line":400,"column":16},"end":{"line":400,"column":25}},"loc":{"start":{"line":400,"column":44},"end":{"line":420,"column":3}}},"40":{"name":"(anonymous_40)","decl":{"start":{"line":422,"column":16},"end":{"line":422,"column":25}},"loc":{"start":{"line":422,"column":31},"end":{"line":423,"column":16}}},"41":{"name":"(anonymous_41)","decl":{"start":{"line":425,"column":16},"end":{"line":425,"column":null}},"loc":{"start":{"line":425,"column":16},"end":{"line":426,"column":16}}},"42":{"name":"(anonymous_42)","decl":{"start":{"line":428,"column":16},"end":{"line":428,"column":null}},"loc":{"start":{"line":428,"column":16},"end":{"line":429,"column":17}}},"43":{"name":"(anonymous_43)","decl":{"start":{"line":431,"column":16},"end":{"line":431,"column":25}},"loc":{"start":{"line":431,"column":43},"end":{"line":439,"column":3}}},"44":{"name":"(anonymous_44)","decl":{"start":{"line":441,"column":16},"end":{"line":441,"column":25}},"loc":{"start":{"line":441,"column":36},"end":{"line":444,"column":3}}},"45":{"name":"(anonymous_45)","decl":{"start":{"line":443,"column":35},"end":{"line":443,"column":36}},"loc":{"start":{"line":443,"column":40},"end":{"line":443,"column":44}}},"46":{"name":"(anonymous_46)","decl":{"start":{"line":446,"column":16},"end":{"line":446,"column":25}},"loc":{"start":{"line":446,"column":32},"end":{"line":449,"column":3}}},"47":{"name":"(anonymous_47)","decl":{"start":{"line":451,"column":16},"end":{"line":451,"column":25}},"loc":{"start":{"line":451,"column":36},"end":{"line":454,"column":3}}},"48":{"name":"(anonymous_48)","decl":{"start":{"line":453,"column":35},"end":{"line":453,"column":36}},"loc":{"start":{"line":453,"column":40},"end":{"line":453,"column":44}}},"49":{"name":"(anonymous_49)","decl":{"start":{"line":456,"column":16},"end":{"line":456,"column":null}},"loc":{"start":{"line":456,"column":16},"end":{"line":457,"column":31}}},"50":{"name":"text","decl":{"start":{"line":487,"column":11},"end":{"line":487,"column":15}},"loc":{"start":{"line":487,"column":15},"end":{"line":490,"column":3}}},"51":{"name":"offset","decl":{"start":{"line":493,"column":11},"end":{"line":493,"column":17}},"loc":{"start":{"line":493,"column":17},"end":{"line":496,"column":3}}},"52":{"name":"range","decl":{"start":{"line":499,"column":11},"end":{"line":499,"column":16}},"loc":{"start":{"line":499,"column":16},"end":{"line":509,"column":3}}},"53":{"name":"location","decl":{"start":{"line":512,"column":11},"end":{"line":512,"column":19}},"loc":{"start":{"line":512,"column":19},"end":{"line":515,"column":3}}},"54":{"name":"expected","decl":{"start":{"line":518,"column":11},"end":{"line":518,"column":19}},"loc":{"start":{"line":518,"column":41},"end":{"line":535,"column":3}}},"55":{"name":"error","decl":{"start":{"line":538,"column":11},"end":{"line":538,"column":16}},"loc":{"start":{"line":538,"column":34},"end":{"line":548,"column":3}}},"56":{"name":"peg$literalExpectation","decl":{"start":{"line":551,"column":11},"end":{"line":551,"column":33}},"loc":{"start":{"line":551,"column":50},"end":{"line":554,"column":3}}},"57":{"name":"peg$classExpectation","decl":{"start":{"line":557,"column":11},"end":{"line":557,"column":31}},"loc":{"start":{"line":557,"column":59},"end":{"line":560,"column":3}}},"58":{"name":"peg$anyExpectation","decl":{"start":{"line":563,"column":11},"end":{"line":563,"column":29}},"loc":{"start":{"line":563,"column":29},"end":{"line":566,"column":3}}},"59":{"name":"peg$endExpectation","decl":{"start":{"line":569,"column":11},"end":{"line":569,"column":29}},"loc":{"start":{"line":569,"column":29},"end":{"line":572,"column":3}}},"60":{"name":"peg$otherExpectation","decl":{"start":{"line":575,"column":11},"end":{"line":575,"column":31}},"loc":{"start":{"line":575,"column":43},"end":{"line":578,"column":3}}},"61":{"name":"peg$computePosDetails","decl":{"start":{"line":581,"column":11},"end":{"line":581,"column":32}},"loc":{"start":{"line":581,"column":36},"end":{"line":635,"column":3}}},"62":{"name":"peg$computeLocation","decl":{"start":{"line":638,"column":11},"end":{"line":638,"column":30}},"loc":{"start":{"line":638,"column":55},"end":{"line":676,"column":3}}},"63":{"name":"peg$fail","decl":{"start":{"line":679,"column":11},"end":{"line":679,"column":19}},"loc":{"start":{"line":679,"column":28},"end":{"line":693,"column":3}}},"64":{"name":"peg$buildSimpleError","decl":{"start":{"line":696,"column":11},"end":{"line":696,"column":31}},"loc":{"start":{"line":696,"column":49},"end":{"line":699,"column":3}}},"65":{"name":"peg$buildStructuredError","decl":{"start":{"line":702,"column":11},"end":{"line":702,"column":35}},"loc":{"start":{"line":702,"column":61},"end":{"line":714,"column":3}}},"66":{"name":"peg$parseVersionRange","decl":{"start":{"line":718,"column":0},"end":{"line":718,"column":21}},"loc":{"start":{"line":718,"column":21},"end":{"line":845,"column":3}}},"67":{"name":"peg$parseOr","decl":{"start":{"line":849,"column":0},"end":{"line":849,"column":11}},"loc":{"start":{"line":849,"column":11},"end":{"line":869,"column":3}}},"68":{"name":"peg$parseAnd","decl":{"start":{"line":873,"column":0},"end":{"line":873,"column":12}},"loc":{"start":{"line":873,"column":12},"end":{"line":893,"column":3}}},"69":{"name":"peg$parseVersionRangeAtom","decl":{"start":{"line":897,"column":0},"end":{"line":897,"column":25}},"loc":{"start":{"line":897,"column":25},"end":{"line":926,"column":3}}},"70":{"name":"peg$parseParens","decl":{"start":{"line":930,"column":0},"end":{"line":930,"column":15}},"loc":{"start":{"line":930,"column":15},"end":{"line":1002,"column":3}}},"71":{"name":"peg$parseAnchor","decl":{"start":{"line":1006,"column":0},"end":{"line":1006,"column":15}},"loc":{"start":{"line":1006,"column":15},"end":{"line":1039,"column":3}}},"72":{"name":"peg$parseVersionSpec","decl":{"start":{"line":1043,"column":0},"end":{"line":1043,"column":20}},"loc":{"start":{"line":1043,"column":20},"end":{"line":1118,"column":3}}},"73":{"name":"peg$parseNot","decl":{"start":{"line":1122,"column":0},"end":{"line":1122,"column":12}},"loc":{"start":{"line":1122,"column":12},"end":{"line":1170,"column":3}}},"74":{"name":"peg$parseAny","decl":{"start":{"line":1174,"column":0},"end":{"line":1174,"column":12}},"loc":{"start":{"line":1174,"column":12},"end":{"line":1205,"column":3}}},"75":{"name":"peg$parseNone","decl":{"start":{"line":1209,"column":0},"end":{"line":1209,"column":13}},"loc":{"start":{"line":1209,"column":13},"end":{"line":1240,"column":3}}},"76":{"name":"peg$parseCmpOp","decl":{"start":{"line":1244,"column":0},"end":{"line":1244,"column":14}},"loc":{"start":{"line":1244,"column":14},"end":{"line":1464,"column":3}}},"77":{"name":"peg$parseExtendedVersion","decl":{"start":{"line":1468,"column":0},"end":{"line":1468,"column":24}},"loc":{"start":{"line":1468,"column":24},"end":{"line":1532,"column":3}}},"78":{"name":"peg$parseEmVer","decl":{"start":{"line":1536,"column":0},"end":{"line":1536,"column":14}},"loc":{"start":{"line":1536,"column":14},"end":{"line":1670,"column":3}}},"79":{"name":"peg$parseFlavor","decl":{"start":{"line":1674,"column":0},"end":{"line":1674,"column":15}},"loc":{"start":{"line":1674,"column":15},"end":{"line":1742,"column":3}}},"80":{"name":"peg$parseLowercase","decl":{"start":{"line":1746,"column":0},"end":{"line":1746,"column":18}},"loc":{"start":{"line":1746,"column":18},"end":{"line":1804,"column":3}}},"81":{"name":"peg$parseString","decl":{"start":{"line":1808,"column":0},"end":{"line":1808,"column":15}},"loc":{"start":{"line":1808,"column":15},"end":{"line":1866,"column":3}}},"82":{"name":"peg$parseVersion","decl":{"start":{"line":1870,"column":0},"end":{"line":1870,"column":16}},"loc":{"start":{"line":1870,"column":16},"end":{"line":1901,"column":3}}},"83":{"name":"peg$parsePreRelease","decl":{"start":{"line":1905,"column":0},"end":{"line":1905,"column":19}},"loc":{"start":{"line":1905,"column":19},"end":{"line":2036,"column":3}}},"84":{"name":"peg$parsePreReleaseSegment","decl":{"start":{"line":2040,"column":0},"end":{"line":2040,"column":26}},"loc":{"start":{"line":2040,"column":26},"end":{"line":2087,"column":3}}},"85":{"name":"peg$parseVersionNumber","decl":{"start":{"line":2091,"column":0},"end":{"line":2091,"column":22}},"loc":{"start":{"line":2091,"column":22},"end":{"line":2200,"column":3}}},"86":{"name":"peg$parseDigit","decl":{"start":{"line":2204,"column":0},"end":{"line":2204,"column":14}},"loc":{"start":{"line":2204,"column":14},"end":{"line":2262,"column":3}}},"87":{"name":"peg$parse_","decl":{"start":{"line":2266,"column":0},"end":{"line":2266,"column":10}},"loc":{"start":{"line":2266,"column":10},"end":{"line":2314,"column":3}}}},"branchMap":{"0":{"loc":{"start":{"line":51,"column":14},"end":{"line":51,"column":30}},"type":"binary-expr","locations":[{"start":{"line":51,"column":14},"end":{"line":51,"column":23}},{"start":{"line":51,"column":27},"end":{"line":51,"column":30}}]},"1":{"loc":{"start":{"line":53,"column":2},"end":{"line":53,"column":null}},"type":"if","locations":[{"start":{"line":53,"column":2},"end":{"line":53,"column":null}}]},"2":{"loc":{"start":{"line":67,"column":2},"end":{"line":119,"column":null}},"type":"if","locations":[{"start":{"line":67,"column":2},"end":{"line":119,"column":null}}]},"3":{"loc":{"start":{"line":75,"column":6},"end":{"line":80,"column":null}},"type":"if","locations":[{"start":{"line":75,"column":6},"end":{"line":80,"column":null}}]},"4":{"loc":{"start":{"line":85,"column":19},"end":{"line":89,"column":9}},"type":"cond-expr","locations":[{"start":{"line":87,"column":8},"end":{"line":87,"column":38}},{"start":{"line":89,"column":8},"end":{"line":89,"column":9}}]},"5":{"loc":{"start":{"line":85,"column":20},"end":{"line":85,"column":95}},"type":"binary-expr","locations":[{"start":{"line":85,"column":20},"end":{"line":85,"column":40}},{"start":{"line":85,"column":45},"end":{"line":85,"column":94}}]},"6":{"loc":{"start":{"line":93,"column":4},"end":{"line":118,"column":null}},"type":"if","locations":[{"start":{"line":93,"column":4},"end":{"line":118,"column":null}},{"start":{"line":115,"column":11},"end":{"line":118,"column":null}}]},"7":{"loc":{"start":{"line":101,"column":17},"end":{"line":101,"column":63}},"type":"cond-expr","locations":[{"start":{"line":101,"column":37},"end":{"line":101,"column":45}},{"start":{"line":101,"column":48},"end":{"line":101,"column":63}}]},"8":{"loc":{"start":{"line":103,"column":19},"end":{"line":103,"column":41}},"type":"binary-expr","locations":[{"start":{"line":103,"column":20},"end":{"line":103,"column":35}},{"start":{"line":103,"column":40},"end":{"line":103,"column":41}}]},"9":{"loc":{"start":{"line":139,"column":15},"end":{"line":143,"column":29}},"type":"cond-expr","locations":[{"start":{"line":141,"column":12},"end":{"line":141,"column":61}},{"start":{"line":143,"column":12},"end":{"line":143,"column":29}}]},"10":{"loc":{"start":{"line":147,"column":20},"end":{"line":147,"column":51}},"type":"cond-expr","locations":[{"start":{"line":147,"column":43},"end":{"line":147,"column":46}},{"start":{"line":147,"column":49},"end":{"line":147,"column":51}}]},"11":{"loc":{"start":{"line":240,"column":4},"end":{"line":253,"column":null}},"type":"if","locations":[{"start":{"line":240,"column":4},"end":{"line":253,"column":null}}]},"12":{"loc":{"start":{"line":244,"column":8},"end":{"line":249,"column":null}},"type":"if","locations":[{"start":{"line":244,"column":8},"end":{"line":249,"column":null}}]},"13":{"loc":{"start":{"line":256,"column":4},"end":{"line":275,"column":null}},"type":"switch","locations":[{"start":{"line":258,"column":6},"end":{"line":260,"column":31}},{"start":{"line":263,"column":6},"end":{"line":265,"column":58}},{"start":{"line":268,"column":6},"end":{"line":274,"column":50}}]},"14":{"loc":{"start":{"line":281,"column":11},"end":{"line":281,"column":70}},"type":"cond-expr","locations":[{"start":{"line":281,"column":19},"end":{"line":281,"column":53}},{"start":{"line":281,"column":56},"end":{"line":281,"column":70}}]},"15":{"loc":{"start":{"line":291,"column":12},"end":{"line":291,"column":48}},"type":"cond-expr","locations":[{"start":{"line":291,"column":36},"end":{"line":291,"column":43}},{"start":{"line":291,"column":46},"end":{"line":291,"column":48}}]},"16":{"loc":{"start":{"line":360,"column":18},"end":{"line":360,"column":32}},"type":"binary-expr","locations":[{"start":{"line":360,"column":18},"end":{"line":360,"column":24}},{"start":{"line":360,"column":28},"end":{"line":360,"column":32}}]},"17":{"loc":{"start":{"line":360,"column":56},"end":{"line":360,"column":116}},"type":"cond-expr","locations":[{"start":{"line":360,"column":69},"end":{"line":360,"column":82}},{"start":{"line":360,"column":85},"end":{"line":360,"column":116}}]},"18":{"loc":{"start":{"line":397,"column":21},"end":{"line":397,"column":35}},"type":"binary-expr","locations":[{"start":{"line":397,"column":21},"end":{"line":397,"column":27}},{"start":{"line":397,"column":31},"end":{"line":397,"column":35}}]},"19":{"loc":{"start":{"line":415,"column":17},"end":{"line":415,"column":30}},"type":"binary-expr","locations":[{"start":{"line":415,"column":17},"end":{"line":415,"column":25}},{"start":{"line":415,"column":29},"end":{"line":415,"column":30}}]},"20":{"loc":{"start":{"line":437,"column":18},"end":{"line":437,"column":34}},"type":"binary-expr","locations":[{"start":{"line":437,"column":18},"end":{"line":437,"column":28}},{"start":{"line":437,"column":32},"end":{"line":437,"column":34}}]},"21":{"loc":{"start":{"line":475,"column":2},"end":{"line":484,"column":null}},"type":"if","locations":[{"start":{"line":475,"column":2},"end":{"line":484,"column":null}}]},"22":{"loc":{"start":{"line":477,"column":4},"end":{"line":480,"column":null}},"type":"if","locations":[{"start":{"line":477,"column":4},"end":{"line":480,"column":null}}]},"23":{"loc":{"start":{"line":520,"column":15},"end":{"line":524,"column":54}},"type":"cond-expr","locations":[{"start":{"line":522,"column":8},"end":{"line":522,"column":16}},{"start":{"line":524,"column":8},"end":{"line":524,"column":54}}]},"24":{"loc":{"start":{"line":540,"column":15},"end":{"line":544,"column":54}},"type":"cond-expr","locations":[{"start":{"line":542,"column":8},"end":{"line":542,"column":16}},{"start":{"line":544,"column":8},"end":{"line":544,"column":54}}]},"25":{"loc":{"start":{"line":588,"column":4},"end":{"line":634,"column":null}},"type":"if","locations":[{"start":{"line":588,"column":4},"end":{"line":634,"column":null}},{"start":{"line":592,"column":11},"end":{"line":634,"column":null}}]},"26":{"loc":{"start":{"line":614,"column":8},"end":{"line":623,"column":null}},"type":"if","locations":[{"start":{"line":614,"column":8},"end":{"line":623,"column":null}},{"start":{"line":620,"column":15},"end":{"line":623,"column":null}}]},"27":{"loc":{"start":{"line":668,"column":4},"end":{"line":673,"column":null}},"type":"if","locations":[{"start":{"line":668,"column":4},"end":{"line":673,"column":null}}]},"28":{"loc":{"start":{"line":668,"column":8},"end":{"line":668,"column":73}},"type":"binary-expr","locations":[{"start":{"line":668,"column":8},"end":{"line":668,"column":14}},{"start":{"line":668,"column":18},"end":{"line":668,"column":28}},{"start":{"line":668,"column":33},"end":{"line":668,"column":72}}]},"29":{"loc":{"start":{"line":681,"column":4},"end":{"line":681,"column":null}},"type":"if","locations":[{"start":{"line":681,"column":4},"end":{"line":681,"column":null}}]},"30":{"loc":{"start":{"line":684,"column":4},"end":{"line":689,"column":null}},"type":"if","locations":[{"start":{"line":684,"column":4},"end":{"line":689,"column":null}}]},"31":{"loc":{"start":{"line":727,"column":4},"end":{"line":841,"column":null}},"type":"if","locations":[{"start":{"line":727,"column":4},"end":{"line":841,"column":null}},{"start":{"line":836,"column":11},"end":{"line":841,"column":null}}]},"32":{"loc":{"start":{"line":739,"column":6},"end":{"line":742,"column":null}},"type":"if","locations":[{"start":{"line":739,"column":6},"end":{"line":742,"column":null}}]},"33":{"loc":{"start":{"line":744,"column":6},"end":{"line":757,"column":null}},"type":"if","locations":[{"start":{"line":744,"column":6},"end":{"line":757,"column":null}},{"start":{"line":752,"column":13},"end":{"line":757,"column":null}}]},"34":{"loc":{"start":{"line":759,"column":6},"end":{"line":762,"column":null}},"type":"if","locations":[{"start":{"line":759,"column":6},"end":{"line":762,"column":null}}]},"35":{"loc":{"start":{"line":766,"column":6},"end":{"line":777,"column":null}},"type":"if","locations":[{"start":{"line":766,"column":6},"end":{"line":777,"column":null}},{"start":{"line":772,"column":13},"end":{"line":777,"column":null}}]},"36":{"loc":{"start":{"line":791,"column":8},"end":{"line":794,"column":null}},"type":"if","locations":[{"start":{"line":791,"column":8},"end":{"line":794,"column":null}}]},"37":{"loc":{"start":{"line":796,"column":8},"end":{"line":809,"column":null}},"type":"if","locations":[{"start":{"line":796,"column":8},"end":{"line":809,"column":null}},{"start":{"line":804,"column":15},"end":{"line":809,"column":null}}]},"38":{"loc":{"start":{"line":811,"column":8},"end":{"line":814,"column":null}},"type":"if","locations":[{"start":{"line":811,"column":8},"end":{"line":814,"column":null}}]},"39":{"loc":{"start":{"line":818,"column":8},"end":{"line":829,"column":null}},"type":"if","locations":[{"start":{"line":818,"column":8},"end":{"line":829,"column":null}},{"start":{"line":824,"column":15},"end":{"line":829,"column":null}}]},"40":{"loc":{"start":{"line":854,"column":4},"end":{"line":865,"column":null}},"type":"if","locations":[{"start":{"line":854,"column":4},"end":{"line":865,"column":null}},{"start":{"line":860,"column":11},"end":{"line":865,"column":null}}]},"41":{"loc":{"start":{"line":864,"column":6},"end":{"line":864,"column":null}},"type":"if","locations":[{"start":{"line":864,"column":6},"end":{"line":864,"column":null}}]},"42":{"loc":{"start":{"line":878,"column":4},"end":{"line":889,"column":null}},"type":"if","locations":[{"start":{"line":878,"column":4},"end":{"line":889,"column":null}},{"start":{"line":884,"column":11},"end":{"line":889,"column":null}}]},"43":{"loc":{"start":{"line":888,"column":6},"end":{"line":888,"column":null}},"type":"if","locations":[{"start":{"line":888,"column":6},"end":{"line":888,"column":null}}]},"44":{"loc":{"start":{"line":904,"column":4},"end":{"line":922,"column":null}},"type":"if","locations":[{"start":{"line":904,"column":4},"end":{"line":922,"column":null}}]},"45":{"loc":{"start":{"line":908,"column":6},"end":{"line":921,"column":null}},"type":"if","locations":[{"start":{"line":908,"column":6},"end":{"line":921,"column":null}}]},"46":{"loc":{"start":{"line":912,"column":8},"end":{"line":920,"column":null}},"type":"if","locations":[{"start":{"line":912,"column":8},"end":{"line":920,"column":null}}]},"47":{"loc":{"start":{"line":916,"column":10},"end":{"line":919,"column":null}},"type":"if","locations":[{"start":{"line":916,"column":10},"end":{"line":919,"column":null}}]},"48":{"loc":{"start":{"line":937,"column":4},"end":{"line":948,"column":null}},"type":"if","locations":[{"start":{"line":937,"column":4},"end":{"line":948,"column":null}},{"start":{"line":943,"column":11},"end":{"line":948,"column":null}}]},"49":{"loc":{"start":{"line":947,"column":6},"end":{"line":947,"column":null}},"type":"if","locations":[{"start":{"line":947,"column":6},"end":{"line":947,"column":null}}]},"50":{"loc":{"start":{"line":950,"column":4},"end":{"line":998,"column":null}},"type":"if","locations":[{"start":{"line":950,"column":4},"end":{"line":998,"column":null}},{"start":{"line":993,"column":11},"end":{"line":998,"column":null}}]},"51":{"loc":{"start":{"line":956,"column":6},"end":{"line":991,"column":null}},"type":"if","locations":[{"start":{"line":956,"column":6},"end":{"line":991,"column":null}},{"start":{"line":986,"column":13},"end":{"line":991,"column":null}}]},"52":{"loc":{"start":{"line":960,"column":8},"end":{"line":971,"column":null}},"type":"if","locations":[{"start":{"line":960,"column":8},"end":{"line":971,"column":null}},{"start":{"line":966,"column":15},"end":{"line":971,"column":null}}]},"53":{"loc":{"start":{"line":970,"column":10},"end":{"line":970,"column":null}},"type":"if","locations":[{"start":{"line":970,"column":10},"end":{"line":970,"column":null}}]},"54":{"loc":{"start":{"line":973,"column":8},"end":{"line":984,"column":null}},"type":"if","locations":[{"start":{"line":973,"column":8},"end":{"line":984,"column":null}},{"start":{"line":979,"column":15},"end":{"line":984,"column":null}}]},"55":{"loc":{"start":{"line":1015,"column":4},"end":{"line":1018,"column":null}},"type":"if","locations":[{"start":{"line":1015,"column":4},"end":{"line":1018,"column":null}}]},"56":{"loc":{"start":{"line":1024,"column":4},"end":{"line":1035,"column":null}},"type":"if","locations":[{"start":{"line":1024,"column":4},"end":{"line":1035,"column":null}},{"start":{"line":1030,"column":11},"end":{"line":1035,"column":null}}]},"57":{"loc":{"start":{"line":1052,"column":4},"end":{"line":1055,"column":null}},"type":"if","locations":[{"start":{"line":1052,"column":4},"end":{"line":1055,"column":null}}]},"58":{"loc":{"start":{"line":1059,"column":4},"end":{"line":1114,"column":null}},"type":"if","locations":[{"start":{"line":1059,"column":4},"end":{"line":1114,"column":null}},{"start":{"line":1109,"column":11},"end":{"line":1114,"column":null}}]},"59":{"loc":{"start":{"line":1063,"column":6},"end":{"line":1074,"column":null}},"type":"if","locations":[{"start":{"line":1063,"column":6},"end":{"line":1074,"column":null}},{"start":{"line":1069,"column":13},"end":{"line":1074,"column":null}}]},"60":{"loc":{"start":{"line":1073,"column":8},"end":{"line":1073,"column":null}},"type":"if","locations":[{"start":{"line":1073,"column":8},"end":{"line":1073,"column":null}}]},"61":{"loc":{"start":{"line":1076,"column":6},"end":{"line":1098,"column":null}},"type":"if","locations":[{"start":{"line":1076,"column":6},"end":{"line":1098,"column":null}},{"start":{"line":1093,"column":13},"end":{"line":1098,"column":null}}]},"62":{"loc":{"start":{"line":1080,"column":8},"end":{"line":1091,"column":null}},"type":"if","locations":[{"start":{"line":1080,"column":8},"end":{"line":1091,"column":null}},{"start":{"line":1086,"column":15},"end":{"line":1091,"column":null}}]},"63":{"loc":{"start":{"line":1100,"column":6},"end":{"line":1103,"column":null}},"type":"if","locations":[{"start":{"line":1100,"column":6},"end":{"line":1103,"column":null}}]},"64":{"loc":{"start":{"line":1129,"column":4},"end":{"line":1140,"column":null}},"type":"if","locations":[{"start":{"line":1129,"column":4},"end":{"line":1140,"column":null}},{"start":{"line":1135,"column":11},"end":{"line":1140,"column":null}}]},"65":{"loc":{"start":{"line":1139,"column":6},"end":{"line":1139,"column":null}},"type":"if","locations":[{"start":{"line":1139,"column":6},"end":{"line":1139,"column":null}}]},"66":{"loc":{"start":{"line":1142,"column":4},"end":{"line":1166,"column":null}},"type":"if","locations":[{"start":{"line":1142,"column":4},"end":{"line":1166,"column":null}},{"start":{"line":1161,"column":11},"end":{"line":1166,"column":null}}]},"67":{"loc":{"start":{"line":1148,"column":6},"end":{"line":1159,"column":null}},"type":"if","locations":[{"start":{"line":1148,"column":6},"end":{"line":1159,"column":null}},{"start":{"line":1154,"column":13},"end":{"line":1159,"column":null}}]},"68":{"loc":{"start":{"line":1181,"column":4},"end":{"line":1192,"column":null}},"type":"if","locations":[{"start":{"line":1181,"column":4},"end":{"line":1192,"column":null}},{"start":{"line":1187,"column":11},"end":{"line":1192,"column":null}}]},"69":{"loc":{"start":{"line":1191,"column":6},"end":{"line":1191,"column":null}},"type":"if","locations":[{"start":{"line":1191,"column":6},"end":{"line":1191,"column":null}}]},"70":{"loc":{"start":{"line":1194,"column":4},"end":{"line":1199,"column":null}},"type":"if","locations":[{"start":{"line":1194,"column":4},"end":{"line":1199,"column":null}}]},"71":{"loc":{"start":{"line":1216,"column":4},"end":{"line":1227,"column":null}},"type":"if","locations":[{"start":{"line":1216,"column":4},"end":{"line":1227,"column":null}},{"start":{"line":1222,"column":11},"end":{"line":1227,"column":null}}]},"72":{"loc":{"start":{"line":1226,"column":6},"end":{"line":1226,"column":null}},"type":"if","locations":[{"start":{"line":1226,"column":6},"end":{"line":1226,"column":null}}]},"73":{"loc":{"start":{"line":1229,"column":4},"end":{"line":1234,"column":null}},"type":"if","locations":[{"start":{"line":1229,"column":4},"end":{"line":1234,"column":null}}]},"74":{"loc":{"start":{"line":1251,"column":4},"end":{"line":1262,"column":null}},"type":"if","locations":[{"start":{"line":1251,"column":4},"end":{"line":1262,"column":null}},{"start":{"line":1257,"column":11},"end":{"line":1262,"column":null}}]},"75":{"loc":{"start":{"line":1261,"column":6},"end":{"line":1261,"column":null}},"type":"if","locations":[{"start":{"line":1261,"column":6},"end":{"line":1261,"column":null}}]},"76":{"loc":{"start":{"line":1264,"column":4},"end":{"line":1269,"column":null}},"type":"if","locations":[{"start":{"line":1264,"column":4},"end":{"line":1269,"column":null}}]},"77":{"loc":{"start":{"line":1273,"column":4},"end":{"line":1460,"column":null}},"type":"if","locations":[{"start":{"line":1273,"column":4},"end":{"line":1460,"column":null}}]},"78":{"loc":{"start":{"line":1277,"column":6},"end":{"line":1288,"column":null}},"type":"if","locations":[{"start":{"line":1277,"column":6},"end":{"line":1288,"column":null}},{"start":{"line":1283,"column":13},"end":{"line":1288,"column":null}}]},"79":{"loc":{"start":{"line":1287,"column":8},"end":{"line":1287,"column":null}},"type":"if","locations":[{"start":{"line":1287,"column":8},"end":{"line":1287,"column":null}}]},"80":{"loc":{"start":{"line":1290,"column":6},"end":{"line":1295,"column":null}},"type":"if","locations":[{"start":{"line":1290,"column":6},"end":{"line":1295,"column":null}}]},"81":{"loc":{"start":{"line":1299,"column":6},"end":{"line":1459,"column":null}},"type":"if","locations":[{"start":{"line":1299,"column":6},"end":{"line":1459,"column":null}}]},"82":{"loc":{"start":{"line":1303,"column":8},"end":{"line":1314,"column":null}},"type":"if","locations":[{"start":{"line":1303,"column":8},"end":{"line":1314,"column":null}},{"start":{"line":1309,"column":15},"end":{"line":1314,"column":null}}]},"83":{"loc":{"start":{"line":1313,"column":10},"end":{"line":1313,"column":null}},"type":"if","locations":[{"start":{"line":1313,"column":10},"end":{"line":1313,"column":null}}]},"84":{"loc":{"start":{"line":1316,"column":8},"end":{"line":1321,"column":null}},"type":"if","locations":[{"start":{"line":1316,"column":8},"end":{"line":1321,"column":null}}]},"85":{"loc":{"start":{"line":1325,"column":8},"end":{"line":1458,"column":null}},"type":"if","locations":[{"start":{"line":1325,"column":8},"end":{"line":1458,"column":null}}]},"86":{"loc":{"start":{"line":1329,"column":10},"end":{"line":1340,"column":null}},"type":"if","locations":[{"start":{"line":1329,"column":10},"end":{"line":1340,"column":null}},{"start":{"line":1335,"column":17},"end":{"line":1340,"column":null}}]},"87":{"loc":{"start":{"line":1339,"column":12},"end":{"line":1339,"column":null}},"type":"if","locations":[{"start":{"line":1339,"column":12},"end":{"line":1339,"column":null}}]},"88":{"loc":{"start":{"line":1342,"column":10},"end":{"line":1347,"column":null}},"type":"if","locations":[{"start":{"line":1342,"column":10},"end":{"line":1347,"column":null}}]},"89":{"loc":{"start":{"line":1351,"column":10},"end":{"line":1457,"column":null}},"type":"if","locations":[{"start":{"line":1351,"column":10},"end":{"line":1457,"column":null}}]},"90":{"loc":{"start":{"line":1355,"column":12},"end":{"line":1366,"column":null}},"type":"if","locations":[{"start":{"line":1355,"column":12},"end":{"line":1366,"column":null}},{"start":{"line":1361,"column":19},"end":{"line":1366,"column":null}}]},"91":{"loc":{"start":{"line":1365,"column":14},"end":{"line":1365,"column":null}},"type":"if","locations":[{"start":{"line":1365,"column":14},"end":{"line":1365,"column":null}}]},"92":{"loc":{"start":{"line":1368,"column":12},"end":{"line":1373,"column":null}},"type":"if","locations":[{"start":{"line":1368,"column":12},"end":{"line":1373,"column":null}}]},"93":{"loc":{"start":{"line":1377,"column":12},"end":{"line":1456,"column":null}},"type":"if","locations":[{"start":{"line":1377,"column":12},"end":{"line":1456,"column":null}}]},"94":{"loc":{"start":{"line":1381,"column":14},"end":{"line":1392,"column":null}},"type":"if","locations":[{"start":{"line":1381,"column":14},"end":{"line":1392,"column":null}},{"start":{"line":1387,"column":21},"end":{"line":1392,"column":null}}]},"95":{"loc":{"start":{"line":1391,"column":16},"end":{"line":1391,"column":null}},"type":"if","locations":[{"start":{"line":1391,"column":16},"end":{"line":1391,"column":null}}]},"96":{"loc":{"start":{"line":1394,"column":14},"end":{"line":1399,"column":null}},"type":"if","locations":[{"start":{"line":1394,"column":14},"end":{"line":1399,"column":null}}]},"97":{"loc":{"start":{"line":1403,"column":14},"end":{"line":1455,"column":null}},"type":"if","locations":[{"start":{"line":1403,"column":14},"end":{"line":1455,"column":null}}]},"98":{"loc":{"start":{"line":1407,"column":16},"end":{"line":1418,"column":null}},"type":"if","locations":[{"start":{"line":1407,"column":16},"end":{"line":1418,"column":null}},{"start":{"line":1413,"column":23},"end":{"line":1418,"column":null}}]},"99":{"loc":{"start":{"line":1417,"column":18},"end":{"line":1417,"column":null}},"type":"if","locations":[{"start":{"line":1417,"column":18},"end":{"line":1417,"column":null}}]},"100":{"loc":{"start":{"line":1420,"column":16},"end":{"line":1425,"column":null}},"type":"if","locations":[{"start":{"line":1420,"column":16},"end":{"line":1425,"column":null}}]},"101":{"loc":{"start":{"line":1429,"column":16},"end":{"line":1454,"column":null}},"type":"if","locations":[{"start":{"line":1429,"column":16},"end":{"line":1454,"column":null}}]},"102":{"loc":{"start":{"line":1433,"column":18},"end":{"line":1444,"column":null}},"type":"if","locations":[{"start":{"line":1433,"column":18},"end":{"line":1444,"column":null}},{"start":{"line":1439,"column":25},"end":{"line":1444,"column":null}}]},"103":{"loc":{"start":{"line":1443,"column":20},"end":{"line":1443,"column":null}},"type":"if","locations":[{"start":{"line":1443,"column":20},"end":{"line":1443,"column":null}}]},"104":{"loc":{"start":{"line":1446,"column":18},"end":{"line":1451,"column":null}},"type":"if","locations":[{"start":{"line":1446,"column":18},"end":{"line":1451,"column":null}}]},"105":{"loc":{"start":{"line":1477,"column":4},"end":{"line":1480,"column":null}},"type":"if","locations":[{"start":{"line":1477,"column":4},"end":{"line":1480,"column":null}}]},"106":{"loc":{"start":{"line":1484,"column":4},"end":{"line":1528,"column":null}},"type":"if","locations":[{"start":{"line":1484,"column":4},"end":{"line":1528,"column":null}},{"start":{"line":1523,"column":11},"end":{"line":1528,"column":null}}]},"107":{"loc":{"start":{"line":1486,"column":6},"end":{"line":1497,"column":null}},"type":"if","locations":[{"start":{"line":1486,"column":6},"end":{"line":1497,"column":null}},{"start":{"line":1492,"column":13},"end":{"line":1497,"column":null}}]},"108":{"loc":{"start":{"line":1496,"column":8},"end":{"line":1496,"column":null}},"type":"if","locations":[{"start":{"line":1496,"column":8},"end":{"line":1496,"column":null}}]},"109":{"loc":{"start":{"line":1499,"column":6},"end":{"line":1521,"column":null}},"type":"if","locations":[{"start":{"line":1499,"column":6},"end":{"line":1521,"column":null}},{"start":{"line":1516,"column":13},"end":{"line":1521,"column":null}}]},"110":{"loc":{"start":{"line":1503,"column":8},"end":{"line":1514,"column":null}},"type":"if","locations":[{"start":{"line":1503,"column":8},"end":{"line":1514,"column":null}},{"start":{"line":1509,"column":15},"end":{"line":1514,"column":null}}]},"111":{"loc":{"start":{"line":1545,"column":4},"end":{"line":1666,"column":null}},"type":"if","locations":[{"start":{"line":1545,"column":4},"end":{"line":1666,"column":null}},{"start":{"line":1661,"column":11},"end":{"line":1666,"column":null}}]},"112":{"loc":{"start":{"line":1547,"column":6},"end":{"line":1558,"column":null}},"type":"if","locations":[{"start":{"line":1547,"column":6},"end":{"line":1558,"column":null}},{"start":{"line":1553,"column":13},"end":{"line":1558,"column":null}}]},"113":{"loc":{"start":{"line":1557,"column":8},"end":{"line":1557,"column":null}},"type":"if","locations":[{"start":{"line":1557,"column":8},"end":{"line":1557,"column":null}}]},"114":{"loc":{"start":{"line":1560,"column":6},"end":{"line":1659,"column":null}},"type":"if","locations":[{"start":{"line":1560,"column":6},"end":{"line":1659,"column":null}},{"start":{"line":1654,"column":13},"end":{"line":1659,"column":null}}]},"115":{"loc":{"start":{"line":1564,"column":8},"end":{"line":1652,"column":null}},"type":"if","locations":[{"start":{"line":1564,"column":8},"end":{"line":1652,"column":null}},{"start":{"line":1647,"column":15},"end":{"line":1652,"column":null}}]},"116":{"loc":{"start":{"line":1566,"column":10},"end":{"line":1577,"column":null}},"type":"if","locations":[{"start":{"line":1566,"column":10},"end":{"line":1577,"column":null}},{"start":{"line":1572,"column":17},"end":{"line":1577,"column":null}}]},"117":{"loc":{"start":{"line":1576,"column":12},"end":{"line":1576,"column":null}},"type":"if","locations":[{"start":{"line":1576,"column":12},"end":{"line":1576,"column":null}}]},"118":{"loc":{"start":{"line":1579,"column":10},"end":{"line":1645,"column":null}},"type":"if","locations":[{"start":{"line":1579,"column":10},"end":{"line":1645,"column":null}},{"start":{"line":1640,"column":17},"end":{"line":1645,"column":null}}]},"119":{"loc":{"start":{"line":1583,"column":12},"end":{"line":1638,"column":null}},"type":"if","locations":[{"start":{"line":1583,"column":12},"end":{"line":1638,"column":null}},{"start":{"line":1633,"column":19},"end":{"line":1638,"column":null}}]},"120":{"loc":{"start":{"line":1587,"column":14},"end":{"line":1598,"column":null}},"type":"if","locations":[{"start":{"line":1587,"column":14},"end":{"line":1598,"column":null}},{"start":{"line":1593,"column":21},"end":{"line":1598,"column":null}}]},"121":{"loc":{"start":{"line":1597,"column":16},"end":{"line":1597,"column":null}},"type":"if","locations":[{"start":{"line":1597,"column":16},"end":{"line":1597,"column":null}}]},"122":{"loc":{"start":{"line":1600,"column":14},"end":{"line":1622,"column":null}},"type":"if","locations":[{"start":{"line":1600,"column":14},"end":{"line":1622,"column":null}},{"start":{"line":1617,"column":21},"end":{"line":1622,"column":null}}]},"123":{"loc":{"start":{"line":1604,"column":16},"end":{"line":1615,"column":null}},"type":"if","locations":[{"start":{"line":1604,"column":16},"end":{"line":1615,"column":null}},{"start":{"line":1610,"column":23},"end":{"line":1615,"column":null}}]},"124":{"loc":{"start":{"line":1624,"column":14},"end":{"line":1627,"column":null}},"type":"if","locations":[{"start":{"line":1624,"column":14},"end":{"line":1627,"column":null}}]},"125":{"loc":{"start":{"line":1681,"column":4},"end":{"line":1692,"column":null}},"type":"if","locations":[{"start":{"line":1681,"column":4},"end":{"line":1692,"column":null}},{"start":{"line":1687,"column":11},"end":{"line":1692,"column":null}}]},"126":{"loc":{"start":{"line":1691,"column":6},"end":{"line":1691,"column":null}},"type":"if","locations":[{"start":{"line":1691,"column":6},"end":{"line":1691,"column":null}}]},"127":{"loc":{"start":{"line":1694,"column":4},"end":{"line":1738,"column":null}},"type":"if","locations":[{"start":{"line":1694,"column":4},"end":{"line":1738,"column":null}},{"start":{"line":1733,"column":11},"end":{"line":1738,"column":null}}]},"128":{"loc":{"start":{"line":1698,"column":6},"end":{"line":1731,"column":null}},"type":"if","locations":[{"start":{"line":1698,"column":6},"end":{"line":1731,"column":null}},{"start":{"line":1726,"column":13},"end":{"line":1731,"column":null}}]},"129":{"loc":{"start":{"line":1700,"column":8},"end":{"line":1711,"column":null}},"type":"if","locations":[{"start":{"line":1700,"column":8},"end":{"line":1711,"column":null}},{"start":{"line":1706,"column":15},"end":{"line":1711,"column":null}}]},"130":{"loc":{"start":{"line":1710,"column":10},"end":{"line":1710,"column":null}},"type":"if","locations":[{"start":{"line":1710,"column":10},"end":{"line":1710,"column":null}}]},"131":{"loc":{"start":{"line":1713,"column":8},"end":{"line":1724,"column":null}},"type":"if","locations":[{"start":{"line":1713,"column":8},"end":{"line":1724,"column":null}},{"start":{"line":1719,"column":15},"end":{"line":1724,"column":null}}]},"132":{"loc":{"start":{"line":1755,"column":4},"end":{"line":1766,"column":null}},"type":"if","locations":[{"start":{"line":1755,"column":4},"end":{"line":1766,"column":null}},{"start":{"line":1761,"column":11},"end":{"line":1766,"column":null}}]},"133":{"loc":{"start":{"line":1765,"column":6},"end":{"line":1765,"column":null}},"type":"if","locations":[{"start":{"line":1765,"column":6},"end":{"line":1765,"column":null}}]},"134":{"loc":{"start":{"line":1768,"column":4},"end":{"line":1791,"column":null}},"type":"if","locations":[{"start":{"line":1768,"column":4},"end":{"line":1791,"column":null}},{"start":{"line":1788,"column":11},"end":{"line":1791,"column":null}}]},"135":{"loc":{"start":{"line":1774,"column":8},"end":{"line":1785,"column":null}},"type":"if","locations":[{"start":{"line":1774,"column":8},"end":{"line":1785,"column":null}},{"start":{"line":1780,"column":15},"end":{"line":1785,"column":null}}]},"136":{"loc":{"start":{"line":1784,"column":10},"end":{"line":1784,"column":null}},"type":"if","locations":[{"start":{"line":1784,"column":10},"end":{"line":1784,"column":null}}]},"137":{"loc":{"start":{"line":1793,"column":4},"end":{"line":1798,"column":null}},"type":"if","locations":[{"start":{"line":1793,"column":4},"end":{"line":1798,"column":null}}]},"138":{"loc":{"start":{"line":1817,"column":4},"end":{"line":1828,"column":null}},"type":"if","locations":[{"start":{"line":1817,"column":4},"end":{"line":1828,"column":null}},{"start":{"line":1823,"column":11},"end":{"line":1828,"column":null}}]},"139":{"loc":{"start":{"line":1827,"column":6},"end":{"line":1827,"column":null}},"type":"if","locations":[{"start":{"line":1827,"column":6},"end":{"line":1827,"column":null}}]},"140":{"loc":{"start":{"line":1830,"column":4},"end":{"line":1853,"column":null}},"type":"if","locations":[{"start":{"line":1830,"column":4},"end":{"line":1853,"column":null}},{"start":{"line":1850,"column":11},"end":{"line":1853,"column":null}}]},"141":{"loc":{"start":{"line":1836,"column":8},"end":{"line":1847,"column":null}},"type":"if","locations":[{"start":{"line":1836,"column":8},"end":{"line":1847,"column":null}},{"start":{"line":1842,"column":15},"end":{"line":1847,"column":null}}]},"142":{"loc":{"start":{"line":1846,"column":10},"end":{"line":1846,"column":null}},"type":"if","locations":[{"start":{"line":1846,"column":10},"end":{"line":1846,"column":null}}]},"143":{"loc":{"start":{"line":1855,"column":4},"end":{"line":1860,"column":null}},"type":"if","locations":[{"start":{"line":1855,"column":4},"end":{"line":1860,"column":null}}]},"144":{"loc":{"start":{"line":1879,"column":4},"end":{"line":1897,"column":null}},"type":"if","locations":[{"start":{"line":1879,"column":4},"end":{"line":1897,"column":null}},{"start":{"line":1892,"column":11},"end":{"line":1897,"column":null}}]},"145":{"loc":{"start":{"line":1883,"column":6},"end":{"line":1886,"column":null}},"type":"if","locations":[{"start":{"line":1883,"column":6},"end":{"line":1886,"column":null}}]},"146":{"loc":{"start":{"line":1912,"column":4},"end":{"line":1923,"column":null}},"type":"if","locations":[{"start":{"line":1912,"column":4},"end":{"line":1923,"column":null}},{"start":{"line":1918,"column":11},"end":{"line":1923,"column":null}}]},"147":{"loc":{"start":{"line":1922,"column":6},"end":{"line":1922,"column":null}},"type":"if","locations":[{"start":{"line":1922,"column":6},"end":{"line":1922,"column":null}}]},"148":{"loc":{"start":{"line":1925,"column":4},"end":{"line":2032,"column":null}},"type":"if","locations":[{"start":{"line":1925,"column":4},"end":{"line":2032,"column":null}},{"start":{"line":2027,"column":11},"end":{"line":2032,"column":null}}]},"149":{"loc":{"start":{"line":1929,"column":6},"end":{"line":2025,"column":null}},"type":"if","locations":[{"start":{"line":1929,"column":6},"end":{"line":2025,"column":null}},{"start":{"line":2020,"column":13},"end":{"line":2025,"column":null}}]},"150":{"loc":{"start":{"line":1935,"column":8},"end":{"line":1946,"column":null}},"type":"if","locations":[{"start":{"line":1935,"column":8},"end":{"line":1946,"column":null}},{"start":{"line":1941,"column":15},"end":{"line":1946,"column":null}}]},"151":{"loc":{"start":{"line":1945,"column":10},"end":{"line":1945,"column":null}},"type":"if","locations":[{"start":{"line":1945,"column":10},"end":{"line":1945,"column":null}}]},"152":{"loc":{"start":{"line":1948,"column":8},"end":{"line":1970,"column":null}},"type":"if","locations":[{"start":{"line":1948,"column":8},"end":{"line":1970,"column":null}},{"start":{"line":1965,"column":15},"end":{"line":1970,"column":null}}]},"153":{"loc":{"start":{"line":1952,"column":10},"end":{"line":1963,"column":null}},"type":"if","locations":[{"start":{"line":1952,"column":10},"end":{"line":1963,"column":null}},{"start":{"line":1958,"column":17},"end":{"line":1963,"column":null}}]},"154":{"loc":{"start":{"line":1978,"column":10},"end":{"line":1989,"column":null}},"type":"if","locations":[{"start":{"line":1978,"column":10},"end":{"line":1989,"column":null}},{"start":{"line":1984,"column":17},"end":{"line":1989,"column":null}}]},"155":{"loc":{"start":{"line":1988,"column":12},"end":{"line":1988,"column":null}},"type":"if","locations":[{"start":{"line":1988,"column":12},"end":{"line":1988,"column":null}}]},"156":{"loc":{"start":{"line":1991,"column":10},"end":{"line":2013,"column":null}},"type":"if","locations":[{"start":{"line":1991,"column":10},"end":{"line":2013,"column":null}},{"start":{"line":2008,"column":17},"end":{"line":2013,"column":null}}]},"157":{"loc":{"start":{"line":1995,"column":12},"end":{"line":2006,"column":null}},"type":"if","locations":[{"start":{"line":1995,"column":12},"end":{"line":2006,"column":null}},{"start":{"line":2001,"column":19},"end":{"line":2006,"column":null}}]},"158":{"loc":{"start":{"line":2047,"column":4},"end":{"line":2058,"column":null}},"type":"if","locations":[{"start":{"line":2047,"column":4},"end":{"line":2058,"column":null}},{"start":{"line":2053,"column":11},"end":{"line":2058,"column":null}}]},"159":{"loc":{"start":{"line":2057,"column":6},"end":{"line":2057,"column":null}},"type":"if","locations":[{"start":{"line":2057,"column":6},"end":{"line":2057,"column":null}}]},"160":{"loc":{"start":{"line":2060,"column":4},"end":{"line":2063,"column":null}},"type":"if","locations":[{"start":{"line":2060,"column":4},"end":{"line":2063,"column":null}}]},"161":{"loc":{"start":{"line":2067,"column":4},"end":{"line":2070,"column":null}},"type":"if","locations":[{"start":{"line":2067,"column":4},"end":{"line":2070,"column":null}}]},"162":{"loc":{"start":{"line":2072,"column":4},"end":{"line":2083,"column":null}},"type":"if","locations":[{"start":{"line":2072,"column":4},"end":{"line":2083,"column":null}},{"start":{"line":2078,"column":11},"end":{"line":2083,"column":null}}]},"163":{"loc":{"start":{"line":2100,"column":4},"end":{"line":2196,"column":null}},"type":"if","locations":[{"start":{"line":2100,"column":4},"end":{"line":2196,"column":null}},{"start":{"line":2191,"column":11},"end":{"line":2196,"column":null}}]},"164":{"loc":{"start":{"line":2106,"column":6},"end":{"line":2117,"column":null}},"type":"if","locations":[{"start":{"line":2106,"column":6},"end":{"line":2117,"column":null}},{"start":{"line":2112,"column":13},"end":{"line":2117,"column":null}}]},"165":{"loc":{"start":{"line":2116,"column":8},"end":{"line":2116,"column":null}},"type":"if","locations":[{"start":{"line":2116,"column":8},"end":{"line":2116,"column":null}}]},"166":{"loc":{"start":{"line":2119,"column":6},"end":{"line":2141,"column":null}},"type":"if","locations":[{"start":{"line":2119,"column":6},"end":{"line":2141,"column":null}},{"start":{"line":2136,"column":13},"end":{"line":2141,"column":null}}]},"167":{"loc":{"start":{"line":2123,"column":8},"end":{"line":2134,"column":null}},"type":"if","locations":[{"start":{"line":2123,"column":8},"end":{"line":2134,"column":null}},{"start":{"line":2129,"column":15},"end":{"line":2134,"column":null}}]},"168":{"loc":{"start":{"line":2149,"column":8},"end":{"line":2160,"column":null}},"type":"if","locations":[{"start":{"line":2149,"column":8},"end":{"line":2160,"column":null}},{"start":{"line":2155,"column":15},"end":{"line":2160,"column":null}}]},"169":{"loc":{"start":{"line":2159,"column":10},"end":{"line":2159,"column":null}},"type":"if","locations":[{"start":{"line":2159,"column":10},"end":{"line":2159,"column":null}}]},"170":{"loc":{"start":{"line":2162,"column":8},"end":{"line":2184,"column":null}},"type":"if","locations":[{"start":{"line":2162,"column":8},"end":{"line":2184,"column":null}},{"start":{"line":2179,"column":15},"end":{"line":2184,"column":null}}]},"171":{"loc":{"start":{"line":2166,"column":10},"end":{"line":2177,"column":null}},"type":"if","locations":[{"start":{"line":2166,"column":10},"end":{"line":2177,"column":null}},{"start":{"line":2172,"column":17},"end":{"line":2177,"column":null}}]},"172":{"loc":{"start":{"line":2213,"column":4},"end":{"line":2224,"column":null}},"type":"if","locations":[{"start":{"line":2213,"column":4},"end":{"line":2224,"column":null}},{"start":{"line":2219,"column":11},"end":{"line":2224,"column":null}}]},"173":{"loc":{"start":{"line":2223,"column":6},"end":{"line":2223,"column":null}},"type":"if","locations":[{"start":{"line":2223,"column":6},"end":{"line":2223,"column":null}}]},"174":{"loc":{"start":{"line":2226,"column":4},"end":{"line":2249,"column":null}},"type":"if","locations":[{"start":{"line":2226,"column":4},"end":{"line":2249,"column":null}},{"start":{"line":2246,"column":11},"end":{"line":2249,"column":null}}]},"175":{"loc":{"start":{"line":2232,"column":8},"end":{"line":2243,"column":null}},"type":"if","locations":[{"start":{"line":2232,"column":8},"end":{"line":2243,"column":null}},{"start":{"line":2238,"column":15},"end":{"line":2243,"column":null}}]},"176":{"loc":{"start":{"line":2242,"column":10},"end":{"line":2242,"column":null}},"type":"if","locations":[{"start":{"line":2242,"column":10},"end":{"line":2242,"column":null}}]},"177":{"loc":{"start":{"line":2251,"column":4},"end":{"line":2256,"column":null}},"type":"if","locations":[{"start":{"line":2251,"column":4},"end":{"line":2256,"column":null}}]},"178":{"loc":{"start":{"line":2275,"column":4},"end":{"line":2286,"column":null}},"type":"if","locations":[{"start":{"line":2275,"column":4},"end":{"line":2286,"column":null}},{"start":{"line":2281,"column":11},"end":{"line":2286,"column":null}}]},"179":{"loc":{"start":{"line":2285,"column":6},"end":{"line":2285,"column":null}},"type":"if","locations":[{"start":{"line":2285,"column":6},"end":{"line":2285,"column":null}}]},"180":{"loc":{"start":{"line":2292,"column":6},"end":{"line":2303,"column":null}},"type":"if","locations":[{"start":{"line":2292,"column":6},"end":{"line":2303,"column":null}},{"start":{"line":2298,"column":13},"end":{"line":2303,"column":null}}]},"181":{"loc":{"start":{"line":2302,"column":8},"end":{"line":2302,"column":null}},"type":"if","locations":[{"start":{"line":2302,"column":8},"end":{"line":2302,"column":null}}]},"182":{"loc":{"start":{"line":2310,"column":4},"end":{"line":2310,"column":null}},"type":"if","locations":[{"start":{"line":2310,"column":4},"end":{"line":2310,"column":null}}]},"183":{"loc":{"start":{"line":2320,"column":2},"end":{"line":2344,"column":null}},"type":"if","locations":[{"start":{"line":2320,"column":2},"end":{"line":2344,"column":null}},{"start":{"line":2324,"column":9},"end":{"line":2344,"column":null}}]},"184":{"loc":{"start":{"line":2320,"column":6},"end":{"line":2320,"column":63}},"type":"binary-expr","locations":[{"start":{"line":2320,"column":6},"end":{"line":2320,"column":31}},{"start":{"line":2320,"column":35},"end":{"line":2320,"column":63}}]},"185":{"loc":{"start":{"line":2326,"column":4},"end":{"line":2329,"column":null}},"type":"if","locations":[{"start":{"line":2326,"column":4},"end":{"line":2329,"column":null}}]},"186":{"loc":{"start":{"line":2326,"column":8},"end":{"line":2326,"column":63}},"type":"binary-expr","locations":[{"start":{"line":2326,"column":8},"end":{"line":2326,"column":33}},{"start":{"line":2326,"column":37},"end":{"line":2326,"column":63}}]},"187":{"loc":{"start":{"line":2336,"column":6},"end":{"line":2336,"column":73}},"type":"cond-expr","locations":[{"start":{"line":2336,"column":38},"end":{"line":2336,"column":66}},{"start":{"line":2336,"column":69},"end":{"line":2336,"column":73}}]},"188":{"loc":{"start":{"line":2338,"column":6},"end":{"line":2342,"column":61}},"type":"cond-expr","locations":[{"start":{"line":2340,"column":10},"end":{"line":2340,"column":65}},{"start":{"line":2342,"column":10},"end":{"line":2342,"column":61}}]}},"s":{"0":6,"1":6,"2":6,"3":6,"4":3,"5":3,"6":3,"7":3,"8":3,"9":3,"10":6,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":6,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0,"36":0,"37":6,"38":3,"39":2,"40":3,"41":3,"42":3,"43":0,"44":0,"45":0,"46":0,"47":4,"48":0,"49":0,"50":6,"51":0,"52":0,"53":5,"54":3,"55":3,"56":3,"57":3,"58":2,"59":2,"60":2,"61":3,"62":3,"63":1,"64":2,"65":0,"66":3,"67":3,"68":127,"69":127,"70":127,"71":127,"72":127,"73":127,"74":127,"75":127,"76":127,"77":127,"78":127,"79":127,"80":127,"81":127,"82":127,"83":127,"84":127,"85":127,"86":127,"87":127,"88":127,"89":127,"90":127,"91":127,"92":127,"93":127,"94":127,"95":127,"96":127,"97":127,"98":127,"99":127,"100":127,"101":127,"102":127,"103":127,"104":127,"105":127,"106":127,"107":127,"108":127,"109":127,"110":127,"111":127,"112":127,"113":127,"114":127,"115":127,"116":127,"117":127,"118":127,"119":0,"120":127,"121":24,"122":127,"123":24,"124":127,"125":2,"126":127,"127":1,"128":127,"129":0,"130":127,"131":1,"132":127,"133":2,"134":127,"135":7,"136":127,"137":4,"138":127,"139":7,"140":127,"141":0,"142":127,"143":0,"144":127,"145":3,"146":127,"147":106,"148":127,"149":0,"150":127,"151":0,"152":127,"153":0,"154":127,"155":1,"156":127,"157":242,"158":127,"159":1,"160":1,"161":127,"162":2,"163":127,"164":242,"165":150,"166":127,"167":393,"168":127,"169":127,"170":127,"171":127,"172":127,"173":127,"174":127,"175":127,"176":0,"177":127,"178":394,"179":0,"180":0,"181":0,"182":0,"183":0,"184":0,"185":0,"186":2286,"187":508,"188":0,"189":0,"190":127,"191":6,"192":6,"193":3,"194":3,"195":3,"196":1,"197":3,"198":3,"199":3,"200":4,"201":0,"202":0,"203":4,"204":4,"205":3,"206":3,"207":3,"208":3,"209":3,"210":3,"211":0,"212":0,"213":3,"214":1542,"215":2,"216":1540,"217":438,"218":438,"219":1540,"220":0,"221":3,"222":18,"223":18,"224":18,"225":18,"226":18,"227":18,"228":18,"229":18,"230":18,"231":17,"232":18,"233":4,"234":4,"235":4,"236":14,"237":14,"238":18,"239":14,"240":18,"241":18,"242":4,"243":4,"244":14,"245":14,"246":18,"247":7,"248":7,"249":7,"250":7,"251":7,"252":7,"253":5,"254":7,"255":3,"256":3,"257":3,"258":4,"259":4,"260":7,"261":4,"262":7,"263":7,"264":3,"265":3,"266":4,"267":4,"268":18,"269":18,"270":0,"271":0,"272":18,"273":25,"274":3,"275":3,"276":22,"277":22,"278":22,"279":25,"280":22,"281":4,"282":4,"283":18,"284":18,"285":18,"286":22,"287":45,"288":45,"289":45,"290":45,"291":21,"292":21,"293":19,"294":19,"295":18,"296":45,"297":45,"298":45,"299":0,"300":0,"301":45,"302":45,"303":45,"304":45,"305":0,"306":0,"307":0,"308":0,"309":0,"310":0,"311":0,"312":0,"313":0,"314":0,"315":0,"316":0,"317":0,"318":0,"319":0,"320":0,"321":0,"322":45,"323":45,"324":45,"325":45,"326":45,"327":45,"328":21,"329":45,"330":45,"331":45,"332":24,"333":24,"334":21,"335":21,"336":45,"337":45,"338":45,"339":45,"340":45,"341":45,"342":45,"343":24,"344":24,"345":5,"346":5,"347":19,"348":19,"349":19,"350":24,"351":5,"352":5,"353":5,"354":5,"355":0,"356":0,"357":19,"358":19,"359":24,"360":19,"361":24,"362":24,"363":21,"364":21,"365":45,"366":21,"367":21,"368":2,"369":2,"370":19,"371":19,"372":19,"373":21,"374":2,"375":2,"376":2,"377":2,"378":2,"379":0,"380":0,"381":19,"382":19,"383":21,"384":19,"385":19,"386":1,"387":1,"388":18,"389":18,"390":18,"391":19,"392":1,"393":1,"394":19,"395":19,"396":18,"397":18,"398":0,"399":0,"400":18,"401":18,"402":18,"403":18,"404":0,"405":0,"406":18,"407":18,"408":45,"409":45,"410":1,"411":1,"412":44,"413":44,"414":44,"415":45,"416":1,"417":1,"418":45,"419":45,"420":44,"421":44,"422":2,"423":2,"424":42,"425":42,"426":42,"427":44,"428":2,"429":2,"430":44,"431":44,"432":42,"433":42,"434":7,"435":7,"436":35,"437":35,"438":35,"439":42,"440":7,"441":7,"442":42,"443":42,"444":35,"445":35,"446":4,"447":4,"448":31,"449":31,"450":31,"451":35,"452":4,"453":4,"454":35,"455":35,"456":31,"457":31,"458":7,"459":7,"460":24,"461":24,"462":24,"463":31,"464":7,"465":7,"466":31,"467":31,"468":24,"469":24,"470":0,"471":0,"472":24,"473":24,"474":24,"475":24,"476":0,"477":0,"478":24,"479":24,"480":24,"481":24,"482":0,"483":0,"484":24,"485":24,"486":24,"487":24,"488":0,"489":0,"490":24,"491":24,"492":24,"493":24,"494":3,"495":3,"496":21,"497":21,"498":21,"499":24,"500":3,"501":3,"502":24,"503":45,"504":109,"505":109,"506":109,"507":109,"508":109,"509":109,"510":107,"511":106,"512":106,"513":1,"514":1,"515":1,"516":107,"517":106,"518":106,"519":106,"520":106,"521":0,"522":0,"523":1,"524":1,"525":2,"526":2,"527":109,"528":0,"529":0,"530":0,"531":0,"532":0,"533":0,"534":0,"535":0,"536":0,"537":0,"538":0,"539":0,"540":0,"541":0,"542":0,"543":0,"544":0,"545":0,"546":0,"547":0,"548":0,"549":0,"550":0,"551":0,"552":0,"553":0,"554":0,"555":0,"556":0,"557":0,"558":0,"559":0,"560":0,"561":0,"562":0,"563":0,"564":0,"565":0,"566":0,"567":0,"568":0,"569":0,"570":0,"571":0,"572":0,"573":0,"574":0,"575":0,"576":0,"577":0,"578":0,"579":0,"580":154,"581":154,"582":0,"583":0,"584":154,"585":154,"586":154,"587":154,"588":0,"589":0,"590":0,"591":0,"592":0,"593":0,"594":0,"595":0,"596":0,"597":0,"598":0,"599":0,"600":0,"601":0,"602":0,"603":154,"604":154,"605":154,"606":0,"607":0,"608":0,"609":0,"610":0,"611":0,"612":0,"613":0,"614":0,"615":0,"616":0,"617":0,"618":0,"619":0,"620":0,"621":0,"622":0,"623":0,"624":0,"625":0,"626":0,"627":0,"628":0,"629":1,"630":1,"631":1,"632":1,"633":1,"634":0,"635":0,"636":0,"637":1,"638":1,"639":4,"640":4,"641":3,"642":3,"643":1,"644":1,"645":1,"646":0,"647":1,"648":1,"649":1,"650":1,"651":1,"652":265,"653":265,"654":265,"655":242,"656":242,"657":241,"658":242,"659":242,"660":23,"661":23,"662":265,"663":242,"664":242,"665":1,"666":1,"667":241,"668":241,"669":241,"670":242,"671":1,"672":1,"673":1,"674":1,"675":1,"676":1,"677":1,"678":0,"679":0,"680":0,"681":1,"682":1,"683":1,"684":1,"685":1,"686":0,"687":0,"688":0,"689":0,"690":1,"691":1,"692":1,"693":1,"694":0,"695":0,"696":1,"697":1,"698":1,"699":1,"700":0,"701":0,"702":0,"703":0,"704":0,"705":0,"706":1,"707":1,"708":1,"709":1,"710":0,"711":0,"712":241,"713":241,"714":242,"715":2,"716":2,"717":0,"718":0,"719":2,"720":2,"721":2,"722":2,"723":2,"724":2,"725":2,"726":1,"727":2,"728":2,"729":2,"730":0,"731":0,"732":2,"733":265,"734":265,"735":265,"736":242,"737":242,"738":242,"739":93,"740":93,"741":149,"742":149,"743":149,"744":242,"745":93,"746":93,"747":92,"748":92,"749":1,"750":1,"751":149,"752":149,"753":242,"754":150,"755":150,"756":150,"757":58,"758":58,"759":92,"760":92,"761":92,"762":150,"763":58,"764":58,"765":58,"766":58,"767":0,"768":0,"769":92,"770":92,"771":242,"772":242,"773":23,"774":23,"775":265,"776":418,"777":418,"778":418,"779":393,"780":393,"781":25,"782":25,"783":25,"784":418,"785":393,"786":395,"787":395,"788":2,"789":2,"790":393,"791":393,"792":393,"793":25,"794":418,"795":393,"796":393,"797":418,"798":418,"799":79,"800":79,"801":79,"802":14,"803":14,"804":65,"805":65,"806":0,"807":79,"808":14,"809":14,"810":0,"811":0,"812":14,"813":14,"814":0,"815":79,"816":79,"817":79,"818":79,"819":79,"820":127,"821":127,"822":124,"823":3,"824":0,"825":3,"826":6,"827":6,"828":6,"829":6},"f":{"0":6,"1":6,"2":6,"3":3,"4":0,"5":0,"6":3,"7":2,"8":3,"9":3,"10":0,"11":0,"12":0,"13":0,"14":4,"15":0,"16":0,"17":6,"18":0,"19":0,"20":5,"21":3,"22":3,"23":127,"24":0,"25":24,"26":24,"27":2,"28":1,"29":0,"30":1,"31":2,"32":7,"33":4,"34":7,"35":0,"36":0,"37":3,"38":106,"39":0,"40":0,"41":0,"42":1,"43":242,"44":1,"45":1,"46":2,"47":242,"48":150,"49":393,"50":394,"51":0,"52":0,"53":0,"54":0,"55":0,"56":2286,"57":508,"58":0,"59":0,"60":127,"61":6,"62":3,"63":1542,"64":0,"65":3,"66":18,"67":25,"68":22,"69":45,"70":45,"71":45,"72":45,"73":21,"74":19,"75":18,"76":45,"77":109,"78":0,"79":154,"80":0,"81":1,"82":265,"83":242,"84":2,"85":265,"86":418,"87":79},"b":{"0":[0,0],"1":[0],"2":[0],"3":[0],"4":[0,0],"5":[0,0],"6":[0,0],"7":[0,0],"8":[0,0],"9":[3,0],"10":[0,3],"11":[3],"12":[2],"13":[1,2,0],"14":[2,1],"15":[127,0],"16":[24,24],"17":[5,19],"18":[106,106],"19":[0,0],"20":[242,241],"21":[127],"22":[0],"23":[0,0],"24":[0,0],"25":[3,3],"26":[0,4],"27":[0],"28":[3,0,0],"29":[2],"30":[438],"31":[18,0],"32":[17],"33":[4,14],"34":[14],"35":[4,14],"36":[5],"37":[3,4],"38":[4],"39":[3,4],"40":[3,22],"41":[22],"42":[4,18],"43":[18],"44":[45],"45":[21],"46":[19],"47":[18],"48":[0,45],"49":[45],"50":[0,45],"51":[0,0],"52":[0,0],"53":[0],"54":[0,0],"55":[21],"56":[24,21],"57":[45],"58":[24,21],"59":[5,19],"60":[19],"61":[5,19],"62":[5,0],"63":[19],"64":[2,19],"65":[19],"66":[2,19],"67":[2,0],"68":[1,18],"69":[18],"70":[1],"71":[0,18],"72":[18],"73":[0],"74":[1,44],"75":[44],"76":[1],"77":[44],"78":[2,42],"79":[42],"80":[2],"81":[42],"82":[7,35],"83":[35],"84":[7],"85":[35],"86":[4,31],"87":[31],"88":[4],"89":[31],"90":[7,24],"91":[24],"92":[7],"93":[24],"94":[0,24],"95":[24],"96":[0],"97":[24],"98":[0,24],"99":[24],"100":[0],"101":[24],"102":[3,21],"103":[21],"104":[3],"105":[109],"106":[107,2],"107":[106,1],"108":[1],"109":[106,1],"110":[106,0],"111":[0,0],"112":[0,0],"113":[0],"114":[0,0],"115":[0,0],"116":[0,0],"117":[0],"118":[0,0],"119":[0,0],"120":[0,0],"121":[0],"122":[0,0],"123":[0,0],"124":[0],"125":[0,154],"126":[154],"127":[0,154],"128":[0,0],"129":[0,0],"130":[0],"131":[0,0],"132":[0,0],"133":[0],"134":[0,0],"135":[0,0],"136":[0],"137":[0],"138":[1,0],"139":[0],"140":[1,0],"141":[3,1],"142":[1],"143":[1],"144":[242,23],"145":[241],"146":[1,241],"147":[241],"148":[1,241],"149":[1,0],"150":[1,0],"151":[0],"152":[1,0],"153":[1,0],"154":[0,1],"155":[1],"156":[0,1],"157":[0,0],"158":[0,2],"159":[2],"160":[2],"161":[1],"162":[2,0],"163":[242,23],"164":[93,149],"165":[149],"166":[93,149],"167":[92,1],"168":[58,92],"169":[92],"170":[58,92],"171":[58,0],"172":[393,25],"173":[25],"174":[393,25],"175":[2,393],"176":[393],"177":[393],"178":[14,65],"179":[0],"180":[0,14],"181":[0],"182":[79],"183":[124,3],"184":[127,124],"185":[0],"186":[3,0],"187":[2,1],"188":[2,1]}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/exver/index.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/exver/index.ts","statementMap":{"0":{"start":{"line":1,"column":0},"end":{"line":1,"column":28}},"1":{"start":{"line":47,"column":29},"end":{"line":47,"column":75}},"2":{"start":{"line":50,"column":4},"end":{"line":63,"column":null}},"3":{"start":{"line":52,"column":8},"end":{"line":52,"column":null}},"4":{"start":{"line":54,"column":8},"end":{"line":54,"column":null}},"5":{"start":{"line":56,"column":8},"end":{"line":56,"column":null}},"6":{"start":{"line":58,"column":8},"end":{"line":58,"column":null}},"7":{"start":{"line":60,"column":8},"end":{"line":60,"column":null}},"8":{"start":{"line":62,"column":8},"end":{"line":62,"column":null}},"9":{"start":{"line":67,"column":4},"end":{"line":93,"column":null}},"10":{"start":{"line":69,"column":8},"end":{"line":72,"column":null}},"11":{"start":{"line":74,"column":8},"end":{"line":74,"column":null}},"12":{"start":{"line":76,"column":8},"end":{"line":90,"column":null}},"13":{"start":{"line":92,"column":8},"end":{"line":92,"column":null}},"14":{"start":{"line":97,"column":17},"end":{"line":97,"column":49}},"15":{"start":{"line":98,"column":4},"end":{"line":116,"column":null}},"16":{"start":{"line":99,"column":6},"end":{"line":115,"column":null}},"17":{"start":{"line":101,"column":10},"end":{"line":105,"column":null}},"18":{"start":{"line":106,"column":10},"end":{"line":106,"column":15}},"19":{"start":{"line":109,"column":10},"end":{"line":113,"column":null}},"20":{"start":{"line":114,"column":10},"end":{"line":114,"column":15}},"21":{"start":{"line":117,"column":4},"end":{"line":117,"column":null}},"22":{"start":{"line":121,"column":4},"end":{"line":123,"column":null}},"23":{"start":{"line":127,"column":4},"end":{"line":127,"column":null}},"24":{"start":{"line":131,"column":4},"end":{"line":131,"column":null}},"25":{"start":{"line":135,"column":4},"end":{"line":135,"column":null}},"26":{"start":{"line":139,"column":4},"end":{"line":139,"column":null}},"27":{"start":{"line":143,"column":4},"end":{"line":143,"column":null}},"28":{"start":{"line":147,"column":4},"end":{"line":147,"column":null}},"29":{"start":{"line":151,"column":4},"end":{"line":151,"column":null}},"30":{"start":{"line":46,"column":0},"end":{"line":46,"column":13}},"31":{"start":{"line":157,"column":11},"end":{"line":157,"column":27}},"32":{"start":{"line":158,"column":11},"end":{"line":158,"column":42}},"33":{"start":{"line":162,"column":4},"end":{"line":162,"column":null}},"34":{"start":{"line":166,"column":19},"end":{"line":166,"column":68}},"35":{"start":{"line":167,"column":4},"end":{"line":173,"column":null}},"36":{"start":{"line":167,"column":17},"end":{"line":167,"column":18}},"37":{"start":{"line":168,"column":6},"end":{"line":172,"column":null}},"38":{"start":{"line":169,"column":8},"end":{"line":169,"column":null}},"39":{"start":{"line":170,"column":13},"end":{"line":172,"column":null}},"40":{"start":{"line":171,"column":8},"end":{"line":171,"column":null}},"41":{"start":{"line":175,"column":4},"end":{"line":179,"column":null}},"42":{"start":{"line":176,"column":6},"end":{"line":176,"column":null}},"43":{"start":{"line":177,"column":11},"end":{"line":179,"column":null}},"44":{"start":{"line":178,"column":6},"end":{"line":178,"column":null}},"45":{"start":{"line":181,"column":26},"end":{"line":181,"column":75}},"46":{"start":{"line":182,"column":4},"end":{"line":203,"column":null}},"47":{"start":{"line":182,"column":17},"end":{"line":182,"column":18}},"48":{"start":{"line":183,"column":6},"end":{"line":202,"column":null}},"49":{"start":{"line":184,"column":8},"end":{"line":188,"column":null}},"50":{"start":{"line":185,"column":10},"end":{"line":185,"column":null}},"51":{"start":{"line":186,"column":15},"end":{"line":188,"column":null}},"52":{"start":{"line":187,"column":10},"end":{"line":187,"column":null}},"53":{"start":{"line":190,"column":8},"end":{"line":201,"column":null}},"54":{"start":{"line":192,"column":12},"end":{"line":192,"column":null}},"55":{"start":{"line":194,"column":12},"end":{"line":194,"column":null}},"56":{"start":{"line":197,"column":12},"end":{"line":197,"column":null}},"57":{"start":{"line":200,"column":12},"end":{"line":200,"column":null}},"58":{"start":{"line":205,"column":4},"end":{"line":205,"column":null}},"59":{"start":{"line":209,"column":19},"end":{"line":209,"column":61}},"60":{"start":{"line":210,"column":4},"end":{"line":210,"column":null}},"61":{"start":{"line":214,"column":4},"end":{"line":216,"column":null}},"62":{"start":{"line":155,"column":0},"end":{"line":155,"column":13}},"63":{"start":{"line":223,"column":11},"end":{"line":223,"column":32}},"64":{"start":{"line":224,"column":11},"end":{"line":224,"column":28}},"65":{"start":{"line":225,"column":11},"end":{"line":225,"column":30}},"66":{"start":{"line":229,"column":4},"end":{"line":229,"column":null}},"67":{"start":{"line":233,"column":4},"end":{"line":235,"column":null}},"68":{"start":{"line":234,"column":6},"end":{"line":234,"column":null}},"69":{"start":{"line":236,"column":24},"end":{"line":236,"column":61}},"70":{"start":{"line":237,"column":4},"end":{"line":239,"column":null}},"71":{"start":{"line":238,"column":6},"end":{"line":238,"column":null}},"72":{"start":{"line":240,"column":4},"end":{"line":240,"column":null}},"73":{"start":{"line":244,"column":4},"end":{"line":250,"column":null}},"74":{"start":{"line":245,"column":6},"end":{"line":245,"column":null}},"75":{"start":{"line":246,"column":11},"end":{"line":250,"column":null}},"76":{"start":{"line":247,"column":6},"end":{"line":247,"column":null}},"77":{"start":{"line":249,"column":6},"end":{"line":249,"column":null}},"78":{"start":{"line":254,"column":4},"end":{"line":261,"column":null}},"79":{"start":{"line":256,"column":8},"end":{"line":256,"column":null}},"80":{"start":{"line":258,"column":8},"end":{"line":258,"column":null}},"81":{"start":{"line":260,"column":8},"end":{"line":260,"column":null}},"82":{"start":{"line":265,"column":4},"end":{"line":265,"column":null}},"83":{"start":{"line":269,"column":4},"end":{"line":269,"column":null}},"84":{"start":{"line":273,"column":4},"end":{"line":273,"column":null}},"85":{"start":{"line":277,"column":4},"end":{"line":277,"column":null}},"86":{"start":{"line":281,"column":4},"end":{"line":281,"column":null}},"87":{"start":{"line":285,"column":19},"end":{"line":285,"column":77}},"88":{"start":{"line":286,"column":4},"end":{"line":290,"column":null}},"89":{"start":{"line":294,"column":19},"end":{"line":294,"column":67}},"90":{"start":{"line":295,"column":4},"end":{"line":299,"column":null}},"91":{"start":{"line":308,"column":21},"end":{"line":308,"column":79}},"92":{"start":{"line":308,"column":69},"end":{"line":308,"column":78}},"93":{"start":{"line":310,"column":24},"end":{"line":317,"column":6}},"94":{"start":{"line":311,"column":6},"end":{"line":315,"column":null}},"95":{"start":{"line":312,"column":8},"end":{"line":312,"column":null}},"96":{"start":{"line":313,"column":13},"end":{"line":315,"column":null}},"97":{"start":{"line":314,"column":8},"end":{"line":314,"column":null}},"98":{"start":{"line":316,"column":6},"end":{"line":316,"column":null}},"99":{"start":{"line":319,"column":32},"end":{"line":319,"column":60}},"100":{"start":{"line":320,"column":30},"end":{"line":320,"column":50}},"101":{"start":{"line":322,"column":4},"end":{"line":326,"column":null}},"102":{"start":{"line":335,"column":21},"end":{"line":335,"column":79}},"103":{"start":{"line":335,"column":69},"end":{"line":335,"column":78}},"104":{"start":{"line":336,"column":19},"end":{"line":336,"column":60}},"105":{"start":{"line":338,"column":24},"end":{"line":345,"column":6}},"106":{"start":{"line":339,"column":6},"end":{"line":343,"column":null}},"107":{"start":{"line":340,"column":8},"end":{"line":340,"column":null}},"108":{"start":{"line":341,"column":13},"end":{"line":343,"column":null}},"109":{"start":{"line":342,"column":8},"end":{"line":342,"column":null}},"110":{"start":{"line":344,"column":6},"end":{"line":344,"column":null}},"111":{"start":{"line":347,"column":32},"end":{"line":347,"column":60}},"112":{"start":{"line":348,"column":30},"end":{"line":348,"column":50}},"113":{"start":{"line":350,"column":4},"end":{"line":354,"column":null}},"114":{"start":{"line":362,"column":4},"end":{"line":415,"column":null}},"115":{"start":{"line":364,"column":29},"end":{"line":364,"column":54}},"116":{"start":{"line":365,"column":8},"end":{"line":398,"column":null}},"117":{"start":{"line":367,"column":12},"end":{"line":367,"column":null}},"118":{"start":{"line":369,"column":12},"end":{"line":369,"column":null}},"119":{"start":{"line":371,"column":12},"end":{"line":371,"column":null}},"120":{"start":{"line":373,"column":12},"end":{"line":373,"column":null}},"121":{"start":{"line":375,"column":12},"end":{"line":375,"column":null}},"122":{"start":{"line":377,"column":12},"end":{"line":377,"column":null}},"123":{"start":{"line":379,"column":30},"end":{"line":379,"column":72}},"124":{"start":{"line":380,"column":12},"end":{"line":387,"column":null}},"125":{"start":{"line":384,"column":14},"end":{"line":384,"column":null}},"126":{"start":{"line":386,"column":14},"end":{"line":386,"column":null}},"127":{"start":{"line":389,"column":30},"end":{"line":389,"column":72}},"128":{"start":{"line":390,"column":12},"end":{"line":397,"column":null}},"129":{"start":{"line":394,"column":14},"end":{"line":394,"column":null}},"130":{"start":{"line":396,"column":14},"end":{"line":396,"column":null}},"131":{"start":{"line":400,"column":8},"end":{"line":403,"column":null}},"132":{"start":{"line":405,"column":8},"end":{"line":408,"column":null}},"133":{"start":{"line":410,"column":8},"end":{"line":410,"column":null}},"134":{"start":{"line":412,"column":8},"end":{"line":412,"column":null}},"135":{"start":{"line":414,"column":8},"end":{"line":414,"column":null}},"136":{"start":{"line":221,"column":0},"end":{"line":221,"column":13}},"137":{"start":{"line":419,"column":29},"end":{"line":419,"column":77}},"138":{"start":{"line":419,"column":76},"end":{"line":419,"column":77}},"139":{"start":{"line":419,"column":13},"end":{"line":419,"column":29}},"140":{"start":{"line":421,"column":31},"end":{"line":422,"column":3}},"141":{"start":{"line":422,"column":2},"end":{"line":422,"column":3}},"142":{"start":{"line":421,"column":13},"end":{"line":421,"column":31}},"143":{"start":{"line":424,"column":2},"end":{"line":424,"column":null}},"144":{"start":{"line":425,"column":2},"end":{"line":425,"column":null}},"145":{"start":{"line":426,"column":2},"end":{"line":426,"column":null}},"146":{"start":{"line":427,"column":2},"end":{"line":427,"column":null}},"147":{"start":{"line":428,"column":2},"end":{"line":428,"column":null}},"148":{"start":{"line":429,"column":2},"end":{"line":429,"column":null}},"149":{"start":{"line":431,"column":2},"end":{"line":431,"column":null}},"150":{"start":{"line":433,"column":2},"end":{"line":433,"column":null}},"151":{"start":{"line":435,"column":2},"end":{"line":435,"column":null}},"152":{"start":{"line":437,"column":2},"end":{"line":437,"column":null}},"153":{"start":{"line":438,"column":2},"end":{"line":438,"column":null}},"154":{"start":{"line":439,"column":2},"end":{"line":439,"column":null}},"155":{"start":{"line":440,"column":2},"end":{"line":440,"column":null}},"156":{"start":{"line":441,"column":2},"end":{"line":441,"column":null}},"157":{"start":{"line":442,"column":2},"end":{"line":442,"column":null}},"158":{"start":{"line":443,"column":2},"end":{"line":443,"column":null}},"159":{"start":{"line":445,"column":2},"end":{"line":445,"column":null}},"160":{"start":{"line":447,"column":2},"end":{"line":447,"column":null}},"161":{"start":{"line":449,"column":2},"end":{"line":449,"column":null}},"162":{"start":{"line":451,"column":2},"end":{"line":451,"column":null}},"163":{"start":{"line":453,"column":2},"end":{"line":453,"column":null}}},"fnMap":{"0":{"name":"(anonymous_6)","decl":{"start":{"line":47,"column":2},"end":{"line":47,"column":29}},"loc":{"start":{"line":47,"column":75},"end":{"line":47,"column":79}}},"1":{"name":"(anonymous_7)","decl":{"start":{"line":49,"column":2},"end":{"line":49,"column":10}},"loc":{"start":{"line":49,"column":10},"end":{"line":64,"column":3}}},"2":{"name":"(anonymous_8)","decl":{"start":{"line":66,"column":10},"end":{"line":66,"column":16}},"loc":{"start":{"line":66,"column":51},"end":{"line":94,"column":3}}},"3":{"name":"(anonymous_9)","decl":{"start":{"line":96,"column":10},"end":{"line":96,"column":16}},"loc":{"start":{"line":96,"column":49},"end":{"line":118,"column":3}}},"4":{"name":"(anonymous_10)","decl":{"start":{"line":120,"column":2},"end":{"line":120,"column":8}},"loc":{"start":{"line":120,"column":28},"end":{"line":124,"column":3}}},"5":{"name":"(anonymous_11)","decl":{"start":{"line":126,"column":2},"end":{"line":126,"column":5}},"loc":{"start":{"line":126,"column":25},"end":{"line":128,"column":3}}},"6":{"name":"(anonymous_12)","decl":{"start":{"line":130,"column":2},"end":{"line":130,"column":4}},"loc":{"start":{"line":130,"column":24},"end":{"line":132,"column":3}}},"7":{"name":"(anonymous_13)","decl":{"start":{"line":134,"column":2},"end":{"line":134,"column":5}},"loc":{"start":{"line":134,"column":5},"end":{"line":136,"column":3}}},"8":{"name":"(anonymous_14)","decl":{"start":{"line":138,"column":2},"end":{"line":138,"column":8}},"loc":{"start":{"line":138,"column":59},"end":{"line":140,"column":3}}},"9":{"name":"(anonymous_15)","decl":{"start":{"line":142,"column":2},"end":{"line":142,"column":8}},"loc":{"start":{"line":142,"column":12},"end":{"line":144,"column":3}}},"10":{"name":"(anonymous_16)","decl":{"start":{"line":146,"column":2},"end":{"line":146,"column":8}},"loc":{"start":{"line":146,"column":13},"end":{"line":148,"column":3}}},"11":{"name":"(anonymous_17)","decl":{"start":{"line":150,"column":2},"end":{"line":150,"column":13}},"loc":{"start":{"line":150,"column":48},"end":{"line":152,"column":3}}},"12":{"name":"(anonymous_18)","decl":{"start":{"line":156,"column":2},"end":{"line":156,"column":null}},"loc":{"start":{"line":158,"column":42},"end":{"line":159,"column":6}}},"13":{"name":"(anonymous_19)","decl":{"start":{"line":161,"column":2},"end":{"line":161,"column":10}},"loc":{"start":{"line":161,"column":10},"end":{"line":163,"column":3}}},"14":{"name":"(anonymous_20)","decl":{"start":{"line":165,"column":2},"end":{"line":165,"column":9}},"loc":{"start":{"line":165,"column":24},"end":{"line":206,"column":3}}},"15":{"name":"(anonymous_21)","decl":{"start":{"line":208,"column":2},"end":{"line":208,"column":8}},"loc":{"start":{"line":208,"column":30},"end":{"line":211,"column":3}}},"16":{"name":"(anonymous_22)","decl":{"start":{"line":213,"column":2},"end":{"line":213,"column":11}},"loc":{"start":{"line":213,"column":38},"end":{"line":217,"column":3}}},"17":{"name":"(anonymous_23)","decl":{"start":{"line":222,"column":2},"end":{"line":222,"column":null}},"loc":{"start":{"line":225,"column":30},"end":{"line":226,"column":6}}},"18":{"name":"(anonymous_24)","decl":{"start":{"line":228,"column":2},"end":{"line":228,"column":10}},"loc":{"start":{"line":228,"column":10},"end":{"line":230,"column":3}}},"19":{"name":"(anonymous_25)","decl":{"start":{"line":232,"column":2},"end":{"line":232,"column":9}},"loc":{"start":{"line":232,"column":32},"end":{"line":241,"column":3}}},"20":{"name":"(anonymous_26)","decl":{"start":{"line":243,"column":2},"end":{"line":243,"column":22}},"loc":{"start":{"line":243,"column":45},"end":{"line":251,"column":3}}},"21":{"name":"(anonymous_27)","decl":{"start":{"line":253,"column":2},"end":{"line":253,"column":16}},"loc":{"start":{"line":253,"column":39},"end":{"line":262,"column":3}}},"22":{"name":"(anonymous_28)","decl":{"start":{"line":264,"column":2},"end":{"line":264,"column":13}},"loc":{"start":{"line":264,"column":36},"end":{"line":266,"column":3}}},"23":{"name":"(anonymous_29)","decl":{"start":{"line":268,"column":2},"end":{"line":268,"column":20}},"loc":{"start":{"line":268,"column":43},"end":{"line":270,"column":3}}},"24":{"name":"(anonymous_30)","decl":{"start":{"line":272,"column":2},"end":{"line":272,"column":8}},"loc":{"start":{"line":272,"column":31},"end":{"line":274,"column":3}}},"25":{"name":"(anonymous_31)","decl":{"start":{"line":276,"column":2},"end":{"line":276,"column":10}},"loc":{"start":{"line":276,"column":33},"end":{"line":278,"column":3}}},"26":{"name":"(anonymous_32)","decl":{"start":{"line":280,"column":2},"end":{"line":280,"column":17}},"loc":{"start":{"line":280,"column":40},"end":{"line":282,"column":3}}},"27":{"name":"(anonymous_33)","decl":{"start":{"line":284,"column":2},"end":{"line":284,"column":8}},"loc":{"start":{"line":284,"column":38},"end":{"line":291,"column":3}}},"28":{"name":"(anonymous_34)","decl":{"start":{"line":293,"column":2},"end":{"line":293,"column":8}},"loc":{"start":{"line":293,"column":43},"end":{"line":300,"column":3}}},"29":{"name":"(anonymous_35)","decl":{"start":{"line":307,"column":2},"end":{"line":307,"column":16}},"loc":{"start":{"line":307,"column":16},"end":{"line":327,"column":3}}},"30":{"name":"(anonymous_36)","decl":{"start":{"line":308,"column":52},"end":{"line":308,"column":53}},"loc":{"start":{"line":308,"column":69},"end":{"line":308,"column":78}}},"31":{"name":"(anonymous_37)","decl":{"start":{"line":310,"column":49},"end":{"line":310,"column":50}},"loc":{"start":{"line":310,"column":70},"end":{"line":317,"column":5}}},"32":{"name":"(anonymous_38)","decl":{"start":{"line":334,"column":2},"end":{"line":334,"column":16}},"loc":{"start":{"line":334,"column":16},"end":{"line":355,"column":3}}},"33":{"name":"(anonymous_39)","decl":{"start":{"line":335,"column":52},"end":{"line":335,"column":53}},"loc":{"start":{"line":335,"column":69},"end":{"line":335,"column":78}}},"34":{"name":"(anonymous_40)","decl":{"start":{"line":338,"column":49},"end":{"line":338,"column":50}},"loc":{"start":{"line":338,"column":70},"end":{"line":345,"column":5}}},"35":{"name":"(anonymous_41)","decl":{"start":{"line":361,"column":2},"end":{"line":361,"column":11}},"loc":{"start":{"line":361,"column":38},"end":{"line":416,"column":3}}},"36":{"name":"(anonymous_42)","decl":{"start":{"line":419,"column":29},"end":{"line":419,"column":48}},"loc":{"start":{"line":419,"column":76},"end":{"line":419,"column":77}}},"37":{"name":"(anonymous_43)","decl":{"start":{"line":421,"column":31},"end":{"line":421,"column":50}},"loc":{"start":{"line":422,"column":2},"end":{"line":422,"column":3}}},"38":{"name":"tests","decl":{"start":{"line":423,"column":9},"end":{"line":423,"column":14}},"loc":{"start":{"line":423,"column":14},"end":{"line":454,"column":1}}}},"branchMap":{"0":{"loc":{"start":{"line":50,"column":4},"end":{"line":63,"column":null}},"type":"switch","locations":[{"start":{"line":51,"column":6},"end":{"line":52,"column":null}},{"start":{"line":53,"column":6},"end":{"line":54,"column":null}},{"start":{"line":55,"column":6},"end":{"line":56,"column":null}},{"start":{"line":57,"column":6},"end":{"line":58,"column":null}},{"start":{"line":59,"column":6},"end":{"line":60,"column":null}},{"start":{"line":61,"column":6},"end":{"line":62,"column":null}}]},"1":{"loc":{"start":{"line":67,"column":4},"end":{"line":93,"column":null}},"type":"switch","locations":[{"start":{"line":68,"column":6},"end":{"line":72,"column":null}},{"start":{"line":73,"column":6},"end":{"line":74,"column":null}},{"start":{"line":75,"column":6},"end":{"line":90,"column":null}},{"start":{"line":91,"column":6},"end":{"line":92,"column":null}}]},"2":{"loc":{"start":{"line":78,"column":20},"end":{"line":78,"column":40}},"type":"binary-expr","locations":[{"start":{"line":78,"column":20},"end":{"line":78,"column":33}},{"start":{"line":78,"column":37},"end":{"line":78,"column":40}}]},"3":{"loc":{"start":{"line":99,"column":6},"end":{"line":115,"column":null}},"type":"switch","locations":[{"start":{"line":100,"column":8},"end":{"line":106,"column":15}},{"start":{"line":107,"column":8},"end":{"line":107,"column":18}},{"start":{"line":108,"column":8},"end":{"line":114,"column":15}}]},"4":{"loc":{"start":{"line":162,"column":38},"end":{"line":162,"column":103}},"type":"cond-expr","locations":[{"start":{"line":162,"column":67},"end":{"line":162,"column":98}},{"start":{"line":162,"column":101},"end":{"line":162,"column":103}}]},"5":{"loc":{"start":{"line":168,"column":6},"end":{"line":172,"column":null}},"type":"if","locations":[{"start":{"line":168,"column":6},"end":{"line":172,"column":null}},{"start":{"line":170,"column":13},"end":{"line":172,"column":null}}]},"6":{"loc":{"start":{"line":168,"column":11},"end":{"line":168,"column":30}},"type":"binary-expr","locations":[{"start":{"line":168,"column":11},"end":{"line":168,"column":25}},{"start":{"line":168,"column":29},"end":{"line":168,"column":30}}]},"7":{"loc":{"start":{"line":168,"column":35},"end":{"line":168,"column":55}},"type":"binary-expr","locations":[{"start":{"line":168,"column":35},"end":{"line":168,"column":50}},{"start":{"line":168,"column":54},"end":{"line":168,"column":55}}]},"8":{"loc":{"start":{"line":170,"column":13},"end":{"line":172,"column":null}},"type":"if","locations":[{"start":{"line":170,"column":13},"end":{"line":172,"column":null}}]},"9":{"loc":{"start":{"line":170,"column":18},"end":{"line":170,"column":37}},"type":"binary-expr","locations":[{"start":{"line":170,"column":18},"end":{"line":170,"column":32}},{"start":{"line":170,"column":36},"end":{"line":170,"column":37}}]},"10":{"loc":{"start":{"line":170,"column":42},"end":{"line":170,"column":62}},"type":"binary-expr","locations":[{"start":{"line":170,"column":42},"end":{"line":170,"column":57}},{"start":{"line":170,"column":61},"end":{"line":170,"column":62}}]},"11":{"loc":{"start":{"line":175,"column":4},"end":{"line":179,"column":null}},"type":"if","locations":[{"start":{"line":175,"column":4},"end":{"line":179,"column":null}},{"start":{"line":177,"column":11},"end":{"line":179,"column":null}}]},"12":{"loc":{"start":{"line":175,"column":8},"end":{"line":175,"column":69}},"type":"binary-expr","locations":[{"start":{"line":175,"column":8},"end":{"line":175,"column":36}},{"start":{"line":175,"column":40},"end":{"line":175,"column":69}}]},"13":{"loc":{"start":{"line":177,"column":11},"end":{"line":179,"column":null}},"type":"if","locations":[{"start":{"line":177,"column":11},"end":{"line":179,"column":null}}]},"14":{"loc":{"start":{"line":177,"column":15},"end":{"line":177,"column":76}},"type":"binary-expr","locations":[{"start":{"line":177,"column":15},"end":{"line":177,"column":43}},{"start":{"line":177,"column":47},"end":{"line":177,"column":76}}]},"15":{"loc":{"start":{"line":183,"column":6},"end":{"line":202,"column":null}},"type":"if","locations":[{"start":{"line":183,"column":6},"end":{"line":202,"column":null}},{"start":{"line":189,"column":13},"end":{"line":202,"column":null}}]},"16":{"loc":{"start":{"line":184,"column":8},"end":{"line":188,"column":null}},"type":"if","locations":[{"start":{"line":184,"column":8},"end":{"line":188,"column":null}},{"start":{"line":186,"column":15},"end":{"line":188,"column":null}}]},"17":{"loc":{"start":{"line":186,"column":15},"end":{"line":188,"column":null}},"type":"if","locations":[{"start":{"line":186,"column":15},"end":{"line":188,"column":null}}]},"18":{"loc":{"start":{"line":190,"column":8},"end":{"line":201,"column":null}},"type":"switch","locations":[{"start":{"line":191,"column":10},"end":{"line":192,"column":null}},{"start":{"line":193,"column":10},"end":{"line":194,"column":null}},{"start":{"line":195,"column":10},"end":{"line":195,"column":34}},{"start":{"line":196,"column":10},"end":{"line":197,"column":null}},{"start":{"line":198,"column":10},"end":{"line":198,"column":34}},{"start":{"line":199,"column":10},"end":{"line":200,"column":null}}]},"19":{"loc":{"start":{"line":229,"column":14},"end":{"line":229,"column":51}},"type":"cond-expr","locations":[{"start":{"line":229,"column":28},"end":{"line":229,"column":46}},{"start":{"line":229,"column":49},"end":{"line":229,"column":51}}]},"20":{"loc":{"start":{"line":233,"column":4},"end":{"line":235,"column":null}},"type":"if","locations":[{"start":{"line":233,"column":4},"end":{"line":235,"column":null}}]},"21":{"loc":{"start":{"line":237,"column":4},"end":{"line":239,"column":null}},"type":"if","locations":[{"start":{"line":237,"column":4},"end":{"line":239,"column":null}}]},"22":{"loc":{"start":{"line":244,"column":4},"end":{"line":250,"column":null}},"type":"if","locations":[{"start":{"line":244,"column":4},"end":{"line":250,"column":null}},{"start":{"line":246,"column":11},"end":{"line":250,"column":null}}]},"23":{"loc":{"start":{"line":244,"column":9},"end":{"line":244,"column":26}},"type":"binary-expr","locations":[{"start":{"line":244,"column":9},"end":{"line":244,"column":20}},{"start":{"line":244,"column":24},"end":{"line":244,"column":26}}]},"24":{"loc":{"start":{"line":244,"column":31},"end":{"line":244,"column":49}},"type":"binary-expr","locations":[{"start":{"line":244,"column":31},"end":{"line":244,"column":43}},{"start":{"line":244,"column":47},"end":{"line":244,"column":49}}]},"25":{"loc":{"start":{"line":246,"column":11},"end":{"line":250,"column":null}},"type":"if","locations":[{"start":{"line":246,"column":11},"end":{"line":250,"column":null}},{"start":{"line":248,"column":11},"end":{"line":250,"column":null}}]},"26":{"loc":{"start":{"line":246,"column":16},"end":{"line":246,"column":33}},"type":"binary-expr","locations":[{"start":{"line":246,"column":16},"end":{"line":246,"column":27}},{"start":{"line":246,"column":31},"end":{"line":246,"column":33}}]},"27":{"loc":{"start":{"line":246,"column":38},"end":{"line":246,"column":56}},"type":"binary-expr","locations":[{"start":{"line":246,"column":38},"end":{"line":246,"column":50}},{"start":{"line":246,"column":54},"end":{"line":246,"column":56}}]},"28":{"loc":{"start":{"line":254,"column":4},"end":{"line":261,"column":null}},"type":"switch","locations":[{"start":{"line":255,"column":6},"end":{"line":256,"column":null}},{"start":{"line":257,"column":6},"end":{"line":258,"column":null}},{"start":{"line":259,"column":6},"end":{"line":260,"column":null}}]},"29":{"loc":{"start":{"line":311,"column":6},"end":{"line":315,"column":null}},"type":"if","locations":[{"start":{"line":311,"column":6},"end":{"line":315,"column":null}},{"start":{"line":313,"column":13},"end":{"line":315,"column":null}}]},"30":{"loc":{"start":{"line":313,"column":13},"end":{"line":315,"column":null}},"type":"if","locations":[{"start":{"line":313,"column":13},"end":{"line":315,"column":null}}]},"31":{"loc":{"start":{"line":336,"column":19},"end":{"line":336,"column":60}},"type":"cond-expr","locations":[{"start":{"line":336,"column":37},"end":{"line":336,"column":45}},{"start":{"line":336,"column":48},"end":{"line":336,"column":60}}]},"32":{"loc":{"start":{"line":339,"column":6},"end":{"line":343,"column":null}},"type":"if","locations":[{"start":{"line":339,"column":6},"end":{"line":343,"column":null}},{"start":{"line":341,"column":13},"end":{"line":343,"column":null}}]},"33":{"loc":{"start":{"line":341,"column":13},"end":{"line":343,"column":null}},"type":"if","locations":[{"start":{"line":341,"column":13},"end":{"line":343,"column":null}}]},"34":{"loc":{"start":{"line":362,"column":4},"end":{"line":415,"column":null}},"type":"switch","locations":[{"start":{"line":363,"column":6},"end":{"line":398,"column":null}},{"start":{"line":399,"column":6},"end":{"line":403,"column":null}},{"start":{"line":404,"column":6},"end":{"line":408,"column":null}},{"start":{"line":409,"column":6},"end":{"line":410,"column":null}},{"start":{"line":411,"column":6},"end":{"line":412,"column":null}},{"start":{"line":413,"column":6},"end":{"line":414,"column":null}}]},"35":{"loc":{"start":{"line":365,"column":8},"end":{"line":398,"column":null}},"type":"switch","locations":[{"start":{"line":366,"column":10},"end":{"line":367,"column":null}},{"start":{"line":368,"column":10},"end":{"line":369,"column":null}},{"start":{"line":370,"column":10},"end":{"line":371,"column":null}},{"start":{"line":372,"column":10},"end":{"line":373,"column":null}},{"start":{"line":374,"column":10},"end":{"line":375,"column":null}},{"start":{"line":376,"column":10},"end":{"line":377,"column":null}},{"start":{"line":378,"column":10},"end":{"line":387,"column":null}},{"start":{"line":388,"column":10},"end":{"line":397,"column":null}}]},"36":{"loc":{"start":{"line":380,"column":12},"end":{"line":387,"column":null}},"type":"if","locations":[{"start":{"line":380,"column":12},"end":{"line":387,"column":null}},{"start":{"line":385,"column":19},"end":{"line":387,"column":null}}]},"37":{"loc":{"start":{"line":381,"column":14},"end":{"line":382,"column":38}},"type":"binary-expr","locations":[{"start":{"line":381,"column":14},"end":{"line":381,"column":51}},{"start":{"line":382,"column":14},"end":{"line":382,"column":38}}]},"38":{"loc":{"start":{"line":390,"column":12},"end":{"line":397,"column":null}},"type":"if","locations":[{"start":{"line":390,"column":12},"end":{"line":397,"column":null}},{"start":{"line":395,"column":19},"end":{"line":397,"column":null}}]},"39":{"loc":{"start":{"line":391,"column":14},"end":{"line":392,"column":38}},"type":"binary-expr","locations":[{"start":{"line":391,"column":14},"end":{"line":391,"column":51}},{"start":{"line":392,"column":14},"end":{"line":392,"column":38}}]},"40":{"loc":{"start":{"line":401,"column":10},"end":{"line":402,"column":49}},"type":"binary-expr","locations":[{"start":{"line":401,"column":10},"end":{"line":401,"column":48}},{"start":{"line":402,"column":10},"end":{"line":402,"column":49}}]},"41":{"loc":{"start":{"line":406,"column":10},"end":{"line":407,"column":49}},"type":"binary-expr","locations":[{"start":{"line":406,"column":10},"end":{"line":406,"column":48}},{"start":{"line":407,"column":10},"end":{"line":407,"column":49}}]}},"s":{"0":6,"1":87,"2":50,"3":20,"4":0,"5":20,"6":0,"7":0,"8":10,"9":27,"10":2,"11":0,"12":24,"13":1,"14":18,"15":18,"16":7,"17":3,"18":3,"19":4,"20":4,"21":18,"22":18,"23":1,"24":21,"25":1,"26":20,"27":0,"28":10,"29":112,"30":6,"31":308,"32":308,"33":40,"34":235,"35":235,"36":235,"37":419,"38":63,"39":356,"40":38,"41":134,"42":0,"43":134,"44":0,"45":134,"46":134,"47":134,"48":252,"49":252,"50":0,"51":252,"52":0,"53":0,"54":0,"55":0,"56":0,"57":0,"58":134,"59":0,"60":0,"61":0,"62":6,"63":154,"64":154,"65":154,"66":20,"67":160,"68":0,"69":160,"70":160,"71":85,"72":75,"73":3,"74":0,"75":3,"76":0,"77":3,"78":3,"79":1,"80":1,"81":1,"82":30,"83":30,"84":31,"85":54,"86":9,"87":109,"88":106,"89":0,"90":0,"91":0,"92":0,"93":0,"94":0,"95":0,"96":0,"97":0,"98":0,"99":0,"100":0,"101":0,"102":24,"103":24,"104":24,"105":24,"106":48,"107":0,"108":48,"109":24,"110":24,"111":24,"112":24,"113":24,"114":198,"115":129,"116":129,"117":21,"118":30,"119":39,"120":6,"121":9,"122":0,"123":0,"124":0,"125":0,"126":0,"127":24,"128":24,"129":6,"130":18,"131":21,"132":17,"133":22,"134":9,"135":0,"136":6,"137":6,"138":0,"139":6,"140":6,"141":5,"142":6,"143":0,"144":0,"145":0,"146":0,"147":0,"148":0,"149":0,"150":0,"151":0,"152":0,"153":0,"154":0,"155":0,"156":0,"157":0,"158":0,"159":0,"160":0,"161":0,"162":0,"163":0},"f":{"0":87,"1":50,"2":27,"3":18,"4":18,"5":1,"6":21,"7":1,"8":20,"9":0,"10":10,"11":112,"12":308,"13":40,"14":235,"15":0,"16":0,"17":154,"18":20,"19":160,"20":3,"21":3,"22":30,"23":30,"24":31,"25":54,"26":9,"27":109,"28":0,"29":0,"30":0,"31":0,"32":24,"33":24,"34":48,"35":198,"36":0,"37":5,"38":0},"b":{"0":[20,0,20,0,0,10],"1":[2,0,24,1],"2":[24,0],"3":[3,4,4],"4":[0,40],"5":[63,356],"6":[419,131],"7":[419,135],"8":[38],"9":[356,131],"10":[356,114],"11":[0,134],"12":[134,134],"13":[0],"14":[134,0],"15":[252,0],"16":[0,252],"17":[0],"18":[0,0,0,0,0,0],"19":[0,20],"20":[0],"21":[85],"22":[0,3],"23":[3,3],"24":[3,3],"25":[0,3],"26":[3,3],"27":[3,3],"28":[1,1,1],"29":[0,0],"30":[0],"31":[0,24],"32":[0,48],"33":[24],"34":[129,21,17,22,9,0],"35":[21,30,39,6,9,0,0,24],"36":[0,0],"37":[0,0],"38":[6,18],"39":[24,15],"40":[21,13],"41":[17,13]}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/health/HealthCheck.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/health/HealthCheck.ts","statementMap":{"0":{"start":{"line":6,"column":0},"end":{"line":6,"column":58}},"1":{"start":{"line":7,"column":0},"end":{"line":7,"column":35}},"2":{"start":{"line":9,"column":0},"end":{"line":9,"column":44}},"3":{"start":{"line":11,"column":0},"end":{"line":11,"column":41}},"4":{"start":{"line":22,"column":2},"end":{"line":60,"column":null}},"5":{"start":{"line":23,"column":37},"end":{"line":23,"column":39}},"6":{"start":{"line":24,"column":28},"end":{"line":24,"column":46}},"7":{"start":{"line":24,"column":34},"end":{"line":24,"column":46}},"8":{"start":{"line":25,"column":20},"end":{"line":25,"column":66}},"9":{"start":{"line":26,"column":32},"end":{"line":31,"column":null}},"10":{"start":{"line":27,"column":6},"end":{"line":30,"column":null}},"11":{"start":{"line":33,"column":4},"end":{"line":59,"column":null}},"12":{"start":{"line":34,"column":16},"end":{"line":34,"column":36}},"13":{"start":{"line":38,"column":6},"end":{"line":58,"column":null}},"14":{"start":{"line":39,"column":36},"end":{"line":39,"column":48}},"15":{"start":{"line":40,"column":8},"end":{"line":45,"column":null}},"16":{"start":{"line":46,"column":8},"end":{"line":46,"column":null}},"17":{"start":{"line":47,"column":8},"end":{"line":49,"column":null}},"18":{"start":{"line":48,"column":10},"end":{"line":48,"column":null}},"19":{"start":{"line":51,"column":8},"end":{"line":56,"column":null}},"20":{"start":{"line":57,"column":8},"end":{"line":57,"column":null}},"21":{"start":{"line":61,"column":2},"end":{"line":61,"column":null}},"22":{"start":{"line":21,"column":0},"end":{"line":21,"column":16}},"23":{"start":{"line":64,"column":2},"end":{"line":64,"column":null}},"24":{"start":{"line":64,"column":44},"end":{"line":64,"column":null}},"25":{"start":{"line":65,"column":16},"end":{"line":65,"column":25}},"26":{"start":{"line":66,"column":2},"end":{"line":66,"column":null}},"27":{"start":{"line":66,"column":28},"end":{"line":66,"column":null}},"28":{"start":{"line":67,"column":2},"end":{"line":67,"column":null}}},"fnMap":{"0":{"name":"healthCheck","decl":{"start":{"line":21,"column":16},"end":{"line":21,"column":27}},"loc":{"start":{"line":21,"column":48},"end":{"line":62,"column":1}}},"1":{"name":"(anonymous_1)","decl":{"start":{"line":22,"column":14},"end":{"line":22,"column":19}},"loc":{"start":{"line":22,"column":25},"end":{"line":60,"column":3}}},"2":{"name":"(anonymous_2)","decl":{"start":{"line":24,"column":28},"end":{"line":24,"column":31}},"loc":{"start":{"line":24,"column":34},"end":{"line":24,"column":46}}},"3":{"name":"(anonymous_3)","decl":{"start":{"line":26,"column":37},"end":{"line":26,"column":40}},"loc":{"start":{"line":27,"column":6},"end":{"line":30,"column":null}}},"4":{"name":"(anonymous_4)","decl":{"start":{"line":47,"column":42},"end":{"line":47,"column":43}},"loc":{"start":{"line":47,"column":50},"end":{"line":49,"column":9}}},"5":{"name":"asMessage","decl":{"start":{"line":63,"column":9},"end":{"line":63,"column":18}},"loc":{"start":{"line":63,"column":29},"end":{"line":68,"column":1}}}},"branchMap":{"0":{"loc":{"start":{"line":25,"column":21},"end":{"line":25,"column":48}},"type":"binary-expr","locations":[{"start":{"line":25,"column":21},"end":{"line":25,"column":30}},{"start":{"line":25,"column":34},"end":{"line":25,"column":48}}]},"1":{"loc":{"start":{"line":28,"column":8},"end":{"line":30,"column":21}},"type":"cond-expr","locations":[{"start":{"line":29,"column":12},"end":{"line":29,"column":30}},{"start":{"line":30,"column":12},"end":{"line":30,"column":21}}]},"2":{"loc":{"start":{"line":28,"column":8},"end":{"line":28,"column":49}},"type":"binary-expr","locations":[{"start":{"line":28,"column":8},"end":{"line":28,"column":29}},{"start":{"line":28,"column":33},"end":{"line":28,"column":49}}]},"3":{"loc":{"start":{"line":44,"column":19},"end":{"line":44,"column":32}},"type":"binary-expr","locations":[{"start":{"line":44,"column":19},"end":{"line":44,"column":26}},{"start":{"line":44,"column":30},"end":{"line":44,"column":32}}]},"4":{"loc":{"start":{"line":55,"column":19},"end":{"line":55,"column":37}},"type":"binary-expr","locations":[{"start":{"line":55,"column":19},"end":{"line":55,"column":31}},{"start":{"line":55,"column":35},"end":{"line":55,"column":37}}]},"5":{"loc":{"start":{"line":64,"column":2},"end":{"line":64,"column":null}},"type":"if","locations":[{"start":{"line":64,"column":2},"end":{"line":64,"column":null}}]},"6":{"loc":{"start":{"line":66,"column":2},"end":{"line":66,"column":null}},"type":"if","locations":[{"start":{"line":66,"column":2},"end":{"line":66,"column":null}}]}},"s":{"0":5,"1":5,"2":5,"3":5,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":5,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0},"f":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0},"b":{"0":[0,0],"1":[0,0],"2":[0,0],"3":[0,0],"4":[0,0],"5":[0],"6":[0]}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/health/checkFns/checkPortListening.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/health/checkFns/checkPortListening.ts","statementMap":{"0":{"start":{"line":2,"column":0},"end":{"line":2,"column":68}},"1":{"start":{"line":5,"column":0},"end":{"line":5,"column":37}},"2":{"start":{"line":6,"column":0},"end":{"line":6,"column":40}},"3":{"start":{"line":8,"column":15},"end":{"line":8,"column":33}},"4":{"start":{"line":9,"column":19},"end":{"line":9,"column":41}},"5":{"start":{"line":11,"column":20},"end":{"line":18,"column":28}},"6":{"start":{"line":15,"column":16},"end":{"line":15,"column":64}},"7":{"start":{"line":17,"column":16},"end":{"line":17,"column":38}},"8":{"start":{"line":19,"column":2},"end":{"line":19,"column":null}},"9":{"start":{"line":10,"column":0},"end":{"line":10,"column":16}},"10":{"start":{"line":36,"column":2},"end":{"line":66,"column":null}},"11":{"start":{"line":39,"column":8},"end":{"line":45,"column":null}},"12":{"start":{"line":47,"column":6},"end":{"line":49,"column":null}},"13":{"start":{"line":48,"column":8},"end":{"line":48,"column":null}},"14":{"start":{"line":50,"column":6},"end":{"line":53,"column":null}},"15":{"start":{"line":56,"column":6},"end":{"line":64,"column":null}},"16":{"start":{"line":58,"column":10},"end":{"line":62,"column":12}},"17":{"start":{"line":26,"column":0},"end":{"line":26,"column":7}}},"fnMap":{"0":{"name":"containsAddress","decl":{"start":{"line":10,"column":16},"end":{"line":10,"column":31}},"loc":{"start":{"line":10,"column":55},"end":{"line":20,"column":1}}},"1":{"name":"(anonymous_7)","decl":{"start":{"line":15,"column":9},"end":{"line":15,"column":10}},"loc":{"start":{"line":15,"column":16},"end":{"line":15,"column":64}}},"2":{"name":"(anonymous_8)","decl":{"start":{"line":17,"column":9},"end":{"line":17,"column":10}},"loc":{"start":{"line":17,"column":16},"end":{"line":17,"column":38}}},"3":{"name":"checkPortListening","decl":{"start":{"line":26,"column":22},"end":{"line":26,"column":40}},"loc":{"start":{"line":34,"column":3},"end":{"line":67,"column":1}}},"4":{"name":"(anonymous_10)","decl":{"start":{"line":37,"column":27},"end":{"line":37,"column":32}},"loc":{"start":{"line":37,"column":38},"end":{"line":54,"column":5}}},"5":{"name":"(anonymous_11)","decl":{"start":{"line":55,"column":16},"end":{"line":55,"column":17}},"loc":{"start":{"line":55,"column":28},"end":{"line":65,"column":5}}},"6":{"name":"(anonymous_12)","decl":{"start":{"line":57,"column":8},"end":{"line":57,"column":11}},"loc":{"start":{"line":58,"column":10},"end":{"line":62,"column":12}}}},"branchMap":{"0":{"loc":{"start":{"line":39,"column":8},"end":{"line":45,"column":null}},"type":"binary-expr","locations":[{"start":{"line":39,"column":8},"end":{"line":41,"column":null}},{"start":{"line":43,"column":8},"end":{"line":45,"column":null}}]},"1":{"loc":{"start":{"line":47,"column":6},"end":{"line":49,"column":null}},"type":"if","locations":[{"start":{"line":47,"column":6},"end":{"line":49,"column":null}}]},"2":{"loc":{"start":{"line":61,"column":14},"end":{"line":61,"column":78}},"type":"binary-expr","locations":[{"start":{"line":61,"column":14},"end":{"line":61,"column":36}},{"start":{"line":61,"column":40},"end":{"line":61,"column":78}}]},"3":{"loc":{"start":{"line":63,"column":8},"end":{"line":63,"column":32}},"type":"binary-expr","locations":[{"start":{"line":63,"column":8},"end":{"line":63,"column":23}},{"start":{"line":63,"column":27},"end":{"line":63,"column":32}}]}},"s":{"0":6,"1":6,"2":6,"3":6,"4":6,"5":2,"6":12,"7":8,"8":2,"9":6,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":6},"f":{"0":2,"1":12,"2":8,"3":0,"4":0,"5":0,"6":0},"b":{"0":[0,0],"1":[0],"2":[0,0],"3":[0,0]}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/health/checkFns/checkWebUrl.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/health/checkFns/checkWebUrl.ts","statementMap":{"0":{"start":{"line":2,"column":0},"end":{"line":2,"column":44}},"1":{"start":{"line":4,"column":0},"end":{"line":4,"column":40}},"2":{"start":{"line":5,"column":0},"end":{"line":5,"column":25}},"3":{"start":{"line":13,"column":27},"end":{"line":36,"column":1}},"4":{"start":{"line":22,"column":2},"end":{"line":35,"column":null}},"5":{"start":{"line":25,"column":9},"end":{"line":28,"column":19}},"6":{"start":{"line":31,"column":6},"end":{"line":31,"column":null}},"7":{"start":{"line":32,"column":6},"end":{"line":32,"column":null}},"8":{"start":{"line":33,"column":6},"end":{"line":33,"column":null}},"9":{"start":{"line":34,"column":6},"end":{"line":34,"column":null}},"10":{"start":{"line":13,"column":13},"end":{"line":13,"column":27}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":13,"column":27},"end":{"line":13,"column":32}},"loc":{"start":{"line":21,"column":32},"end":{"line":36,"column":1}}},"1":{"name":"(anonymous_1)","decl":{"start":{"line":24,"column":6},"end":{"line":24,"column":7}},"loc":{"start":{"line":25,"column":9},"end":{"line":28,"column":19}}},"2":{"name":"(anonymous_2)","decl":{"start":{"line":30,"column":11},"end":{"line":30,"column":12}},"loc":{"start":{"line":30,"column":17},"end":{"line":35,"column":5}}}},"branchMap":{"0":{"loc":{"start":{"line":16,"column":2},"end":{"line":20,"column":8}},"type":"default-arg","locations":[{"start":{"line":20,"column":6},"end":{"line":20,"column":8}}]},"1":{"loc":{"start":{"line":17,"column":4},"end":{"line":17,"column":18}},"type":"default-arg","locations":[{"start":{"line":17,"column":14},"end":{"line":17,"column":18}}]},"2":{"loc":{"start":{"line":18,"column":4},"end":{"line":18,"column":37}},"type":"default-arg","locations":[{"start":{"line":18,"column":21},"end":{"line":18,"column":37}}]},"3":{"loc":{"start":{"line":19,"column":4},"end":{"line":19,"column":53}},"type":"default-arg","locations":[{"start":{"line":19,"column":19},"end":{"line":19,"column":53}}]}},"s":{"0":5,"1":5,"2":5,"3":5,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":5},"f":{"0":0,"1":0,"2":0},"b":{"0":[0],"1":[0],"2":[0],"3":[0]}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/health/checkFns/index.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/health/checkFns/index.ts","statementMap":{"0":{"start":{"line":1,"column":0},"end":{"line":1,"column":9}},"1":{"start":{"line":11,"column":9},"end":{"line":1,"column":51}},"2":{"start":{"line":2,"column":0},"end":{"line":2,"column":9}},"3":{"start":{"line":2,"column":9},"end":{"line":2,"column":57}},"4":{"start":{"line":4,"column":0},"end":{"line":4,"column":9}},"5":{"start":{"line":4,"column":9},"end":{"line":4,"column":43}},"6":{"start":{"line":7,"column":2},"end":{"line":9,"column":null}},"7":{"start":{"line":8,"column":4},"end":{"line":8,"column":52}},"8":{"start":{"line":8,"column":21},"end":{"line":8,"column":47}},"9":{"start":{"line":6,"column":0},"end":{"line":6,"column":16}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":11,"column":9},"end":{"line":11,"column":24}},"loc":{"start":{"line":11,"column":9},"end":{"line":1,"column":51}}},"1":{"name":"(anonymous_1)","decl":{"start":{"line":2,"column":9},"end":{"line":2,"column":27}},"loc":{"start":{"line":2,"column":9},"end":{"line":2,"column":57}}},"2":{"name":"(anonymous_2)","decl":{"start":{"line":4,"column":9},"end":{"line":4,"column":20}},"loc":{"start":{"line":4,"column":9},"end":{"line":4,"column":43}}},"3":{"name":"timeoutPromise","decl":{"start":{"line":6,"column":16},"end":{"line":6,"column":30}},"loc":{"start":{"line":6,"column":73},"end":{"line":10,"column":1}}},"4":{"name":"(anonymous_4)","decl":{"start":{"line":7,"column":28},"end":{"line":7,"column":29}},"loc":{"start":{"line":8,"column":4},"end":{"line":8,"column":52}}},"5":{"name":"(anonymous_5)","decl":{"start":{"line":8,"column":15},"end":{"line":8,"column":18}},"loc":{"start":{"line":8,"column":21},"end":{"line":8,"column":47}}}},"branchMap":{"0":{"loc":{"start":{"line":6,"column":43},"end":{"line":6,"column":73}},"type":"default-arg","locations":[{"start":{"line":6,"column":71},"end":{"line":6,"column":73}}]},"1":{"loc":{"start":{"line":6,"column":45},"end":{"line":6,"column":66}},"type":"default-arg","locations":[{"start":{"line":6,"column":55},"end":{"line":6,"column":66}}]}},"s":{"0":5,"1":11,"2":5,"3":5,"4":5,"5":11,"6":0,"7":0,"8":0,"9":5},"f":{"0":6,"1":0,"2":6,"3":0,"4":0,"5":0},"b":{"0":[0],"1":[0]}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/health/checkFns/runHealthScript.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/health/checkFns/runHealthScript.ts","statementMap":{"0":{"start":{"line":5,"column":0},"end":{"line":5,"column":40}},"1":{"start":{"line":14,"column":31},"end":{"line":37,"column":1}},"2":{"start":{"line":21,"column":6},"end":{"line":21,"column":60}},"3":{"start":{"line":24,"column":14},"end":{"line":32,"column":4}},"4":{"start":{"line":28,"column":4},"end":{"line":28,"column":null}},"5":{"start":{"line":29,"column":4},"end":{"line":29,"column":null}},"6":{"start":{"line":30,"column":4},"end":{"line":30,"column":null}},"7":{"start":{"line":31,"column":4},"end":{"line":31,"column":null}},"8":{"start":{"line":33,"column":2},"end":{"line":36,"column":null}},"9":{"start":{"line":14,"column":13},"end":{"line":14,"column":31}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":14,"column":31},"end":{"line":14,"column":36}},"loc":{"start":{"line":23,"column":32},"end":{"line":37,"column":1}}},"1":{"name":"(anonymous_1)","decl":{"start":{"line":20,"column":14},"end":{"line":20,"column":15}},"loc":{"start":{"line":21,"column":6},"end":{"line":21,"column":60}}},"2":{"name":"(anonymous_2)","decl":{"start":{"line":27,"column":11},"end":{"line":27,"column":12}},"loc":{"start":{"line":27,"column":17},"end":{"line":32,"column":3}}}},"branchMap":{"0":{"loc":{"start":{"line":17,"column":2},"end":{"line":22,"column":8}},"type":"default-arg","locations":[{"start":{"line":22,"column":6},"end":{"line":22,"column":8}}]},"1":{"loc":{"start":{"line":18,"column":4},"end":{"line":18,"column":19}},"type":"default-arg","locations":[{"start":{"line":18,"column":14},"end":{"line":18,"column":19}}]},"2":{"loc":{"start":{"line":19,"column":4},"end":{"line":19,"column":63}},"type":"default-arg","locations":[{"start":{"line":19,"column":19},"end":{"line":19,"column":63}}]},"3":{"loc":{"start":{"line":20,"column":4},"end":{"line":21,"column":60}},"type":"default-arg","locations":[{"start":{"line":20,"column":14},"end":{"line":21,"column":60}}]}},"s":{"0":5,"1":5,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":5},"f":{"0":0,"1":0,"2":0},"b":{"0":[0],"1":[0],"2":[0],"3":[0]}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/inits/setupInit.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/inits/setupInit.ts","statementMap":{"0":{"start":{"line":2,"column":0},"end":{"line":2,"column":56}},"1":{"start":{"line":25,"column":2},"end":{"line":61,"column":null}},"2":{"start":{"line":27,"column":19},"end":{"line":27,"column":54}},"3":{"start":{"line":28,"column":6},"end":{"line":39,"column":null}},"4":{"start":{"line":29,"column":8},"end":{"line":33,"column":null}},"5":{"start":{"line":35,"column":8},"end":{"line":35,"column":null}},"6":{"start":{"line":36,"column":8},"end":{"line":38,"column":null}},"7":{"start":{"line":40,"column":6},"end":{"line":43,"column":null}},"8":{"start":{"line":44,"column":6},"end":{"line":44,"column":null}},"9":{"start":{"line":45,"column":6},"end":{"line":45,"column":null}},"10":{"start":{"line":48,"column":6},"end":{"line":59,"column":null}},"11":{"start":{"line":49,"column":21},"end":{"line":49,"column":56}},"12":{"start":{"line":50,"column":8},"end":{"line":56,"column":null}},"13":{"start":{"line":51,"column":10},"end":{"line":55,"column":null}},"14":{"start":{"line":58,"column":8},"end":{"line":58,"column":null}},"15":{"start":{"line":11,"column":0},"end":{"line":11,"column":16}}},"fnMap":{"0":{"name":"setupInit","decl":{"start":{"line":11,"column":16},"end":{"line":11,"column":25}},"loc":{"start":{"line":20,"column":33},"end":{"line":62,"column":1}}},"1":{"name":"(anonymous_1)","decl":{"start":{"line":26,"column":10},"end":{"line":26,"column":15}},"loc":{"start":{"line":26,"column":25},"end":{"line":46,"column":5}}},"2":{"name":"(anonymous_2)","decl":{"start":{"line":47,"column":12},"end":{"line":47,"column":17}},"loc":{"start":{"line":47,"column":27},"end":{"line":60,"column":5}}}},"branchMap":{"0":{"loc":{"start":{"line":28,"column":6},"end":{"line":39,"column":null}},"type":"if","locations":[{"start":{"line":28,"column":6},"end":{"line":39,"column":null}},{"start":{"line":34,"column":13},"end":{"line":39,"column":null}}]},"1":{"loc":{"start":{"line":48,"column":6},"end":{"line":59,"column":null}},"type":"if","locations":[{"start":{"line":48,"column":6},"end":{"line":59,"column":null}},{"start":{"line":57,"column":13},"end":{"line":59,"column":null}}]},"2":{"loc":{"start":{"line":50,"column":8},"end":{"line":56,"column":null}},"type":"if","locations":[{"start":{"line":50,"column":8},"end":{"line":56,"column":null}}]}},"s":{"0":5,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":5},"f":{"0":0,"1":0,"2":0},"b":{"0":[0,0],"1":[0,0],"2":[0]}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/inits/setupInstall.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/inits/setupInstall.ts","statementMap":{"0":{"start":{"line":7,"column":31},"end":{"line":7,"column":61}},"1":{"start":{"line":11,"column":4},"end":{"line":11,"column":null}},"2":{"start":{"line":15,"column":4},"end":{"line":17,"column":null}},"3":{"start":{"line":6,"column":0},"end":{"line":6,"column":13}},"4":{"start":{"line":24,"column":2},"end":{"line":24,"column":null}},"5":{"start":{"line":21,"column":0},"end":{"line":21,"column":16}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":7,"column":2},"end":{"line":7,"column":31}},"loc":{"start":{"line":7,"column":61},"end":{"line":7,"column":65}}},"1":{"name":"(anonymous_1)","decl":{"start":{"line":8,"column":2},"end":{"line":8,"column":8}},"loc":{"start":{"line":9,"column":34},"end":{"line":12,"column":3}}},"2":{"name":"(anonymous_2)","decl":{"start":{"line":14,"column":2},"end":{"line":14,"column":7}},"loc":{"start":{"line":14,"column":66},"end":{"line":18,"column":3}}},"3":{"name":"setupInstall","decl":{"start":{"line":21,"column":16},"end":{"line":21,"column":28}},"loc":{"start":{"line":22,"column":32},"end":{"line":25,"column":1}}}},"branchMap":{},"s":{"0":0,"1":0,"2":0,"3":5,"4":0,"5":5},"f":{"0":0,"1":0,"2":0,"3":0},"b":{}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/inits/setupUninstall.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/inits/setupUninstall.ts","statementMap":{"0":{"start":{"line":7,"column":31},"end":{"line":7,"column":63}},"1":{"start":{"line":11,"column":4},"end":{"line":11,"column":null}},"2":{"start":{"line":18,"column":4},"end":{"line":21,"column":null}},"3":{"start":{"line":19,"column":6},"end":{"line":21,"column":null}},"4":{"start":{"line":6,"column":0},"end":{"line":6,"column":13}},"5":{"start":{"line":28,"column":2},"end":{"line":28,"column":null}},"6":{"start":{"line":25,"column":0},"end":{"line":25,"column":16}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":7,"column":2},"end":{"line":7,"column":31}},"loc":{"start":{"line":7,"column":63},"end":{"line":7,"column":67}}},"1":{"name":"(anonymous_1)","decl":{"start":{"line":8,"column":2},"end":{"line":8,"column":8}},"loc":{"start":{"line":9,"column":36},"end":{"line":12,"column":3}}},"2":{"name":"(anonymous_2)","decl":{"start":{"line":14,"column":2},"end":{"line":14,"column":7}},"loc":{"start":{"line":17,"column":44},"end":{"line":22,"column":3}}},"3":{"name":"setupUninstall","decl":{"start":{"line":25,"column":16},"end":{"line":25,"column":30}},"loc":{"start":{"line":26,"column":34},"end":{"line":29,"column":1}}}},"branchMap":{"0":{"loc":{"start":{"line":18,"column":4},"end":{"line":21,"column":null}},"type":"if","locations":[{"start":{"line":18,"column":4},"end":{"line":21,"column":null}}]}},"s":{"0":0,"1":0,"2":0,"3":0,"4":5,"5":0,"6":5},"f":{"0":0,"1":0,"2":0,"3":0},"b":{"0":[0]}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/interfaces/Host.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/interfaces/Host.ts","statementMap":{"0":{"start":{"line":1,"column":0},"end":{"line":1,"column":51}},"1":{"start":{"line":3,"column":0},"end":{"line":3,"column":33}},"2":{"start":{"line":11,"column":13},"end":{"line":52,"column":null}},"3":{"start":{"line":84,"column":26},"end":{"line":86,"column":7}},"4":{"start":{"line":90,"column":13},"end":{"line":90,"column":null}},"5":{"start":{"line":101,"column":4},"end":{"line":105,"column":null}},"6":{"start":{"line":102,"column":6},"end":{"line":102,"column":null}},"7":{"start":{"line":104,"column":6},"end":{"line":104,"column":null}},"8":{"start":{"line":116,"column":26},"end":{"line":121,"column":null}},"9":{"start":{"line":122,"column":4},"end":{"line":122,"column":null}},"10":{"start":{"line":124,"column":4},"end":{"line":124,"column":null}},"11":{"start":{"line":131,"column":22},"end":{"line":131,"column":54}},"12":{"start":{"line":133,"column":6},"end":{"line":134,"column":50}},"13":{"start":{"line":135,"column":21},"end":{"line":135,"column":57}},"14":{"start":{"line":137,"column":6},"end":{"line":145,"column":14}},"15":{"start":{"line":147,"column":36},"end":{"line":147,"column":77}},"16":{"start":{"line":149,"column":4},"end":{"line":156,"column":null}},"17":{"start":{"line":158,"column":4},"end":{"line":158,"column":null}},"18":{"start":{"line":165,"column":4},"end":{"line":165,"column":null}},"19":{"start":{"line":165,"column":59},"end":{"line":165,"column":null}},"20":{"start":{"line":166,"column":4},"end":{"line":166,"column":null}},"21":{"start":{"line":166,"column":53},"end":{"line":166,"column":null}},"22":{"start":{"line":167,"column":4},"end":{"line":167,"column":null}},"23":{"start":{"line":88,"column":0},"end":{"line":88,"column":13}},"24":{"start":{"line":175,"column":2},"end":{"line":175,"column":null}},"25":{"start":{"line":192,"column":4},"end":{"line":192,"column":null}},"26":{"start":{"line":190,"column":0},"end":{"line":190,"column":13}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":89,"column":2},"end":{"line":89,"column":null}},"loc":{"start":{"line":94,"column":5},"end":{"line":95,"column":6}}},"1":{"name":"(anonymous_1)","decl":{"start":{"line":97,"column":2},"end":{"line":97,"column":7}},"loc":{"start":{"line":99,"column":34},"end":{"line":106,"column":3}}},"2":{"name":"(anonymous_2)","decl":{"start":{"line":108,"column":10},"end":{"line":108,"column":15}},"loc":{"start":{"line":114,"column":5},"end":{"line":125,"column":3}}},"3":{"name":"(anonymous_3)","decl":{"start":{"line":127,"column":10},"end":{"line":127,"column":15}},"loc":{"start":{"line":129,"column":24},"end":{"line":159,"column":3}}},"4":{"name":"(anonymous_4)","decl":{"start":{"line":161,"column":10},"end":{"line":161,"column":21}},"loc":{"start":{"line":163,"column":51},"end":{"line":168,"column":3}}},"5":{"name":"inObject","decl":{"start":{"line":171,"column":9},"end":{"line":171,"column":17}},"loc":{"start":{"line":173,"column":10},"end":{"line":176,"column":1}}},"6":{"name":"(anonymous_6)","decl":{"start":{"line":191,"column":2},"end":{"line":191,"column":14}},"loc":{"start":{"line":191,"column":55},"end":{"line":193,"column":3}}}},"branchMap":{"0":{"loc":{"start":{"line":101,"column":4},"end":{"line":105,"column":null}},"type":"if","locations":[{"start":{"line":101,"column":4},"end":{"line":105,"column":null}},{"start":{"line":103,"column":11},"end":{"line":105,"column":null}}]},"1":{"loc":{"start":{"line":133,"column":6},"end":{"line":134,"column":50}},"type":"binary-expr","locations":[{"start":{"line":133,"column":6},"end":{"line":133,"column":35}},{"start":{"line":134,"column":6},"end":{"line":134,"column":50}}]},"2":{"loc":{"start":{"line":137,"column":6},"end":{"line":145,"column":14}},"type":"cond-expr","locations":[{"start":{"line":138,"column":10},"end":{"line":144,"column":null}},{"start":{"line":145,"column":10},"end":{"line":145,"column":14}}]},"3":{"loc":{"start":{"line":137,"column":6},"end":{"line":137,"column":37}},"type":"binary-expr","locations":[{"start":{"line":137,"column":6},"end":{"line":137,"column":14}},{"start":{"line":137,"column":18},"end":{"line":137,"column":37}}]},"4":{"loc":{"start":{"line":143,"column":16},"end":{"line":143,"column":59}},"type":"cond-expr","locations":[{"start":{"line":143,"column":38},"end":{"line":143,"column":52}},{"start":{"line":143,"column":55},"end":{"line":143,"column":59}}]},"5":{"loc":{"start":{"line":147,"column":36},"end":{"line":147,"column":77}},"type":"cond-expr","locations":[{"start":{"line":147,"column":56},"end":{"line":147,"column":60}},{"start":{"line":147,"column":63},"end":{"line":147,"column":77}}]},"6":{"loc":{"start":{"line":165,"column":4},"end":{"line":165,"column":null}},"type":"if","locations":[{"start":{"line":165,"column":4},"end":{"line":165,"column":null}}]},"7":{"loc":{"start":{"line":165,"column":8},"end":{"line":165,"column":57}},"type":"binary-expr","locations":[{"start":{"line":165,"column":8},"end":{"line":165,"column":37}},{"start":{"line":165,"column":41},"end":{"line":165,"column":57}}]},"8":{"loc":{"start":{"line":166,"column":4},"end":{"line":166,"column":null}},"type":"if","locations":[{"start":{"line":166,"column":4},"end":{"line":166,"column":null}}]},"9":{"loc":{"start":{"line":166,"column":8},"end":{"line":166,"column":51}},"type":"binary-expr","locations":[{"start":{"line":166,"column":8},"end":{"line":166,"column":30}},{"start":{"line":166,"column":34},"end":{"line":166,"column":51}}]}},"s":{"0":6,"1":6,"2":6,"3":6,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":6,"24":0,"25":0,"26":6},"f":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0},"b":{"0":[0,0],"1":[0,0],"2":[0,0],"3":[0,0],"4":[0,0],"5":[0,0],"6":[0],"7":[0,0],"8":[0],"9":[0,0]}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/interfaces/Origin.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/interfaces/Origin.ts","statementMap":{"0":{"start":{"line":8,"column":13},"end":{"line":8,"column":20}},"1":{"start":{"line":9,"column":13},"end":{"line":9,"column":33}},"2":{"start":{"line":10,"column":13},"end":{"line":10,"column":34}},"3":{"start":{"line":11,"column":13},"end":{"line":11,"column":37}},"4":{"start":{"line":15,"column":22},"end":{"line":19,"column":16}},"5":{"start":{"line":17,"column":24},"end":{"line":17,"column":79}},"6":{"start":{"line":21,"column":15},"end":{"line":21,"column":54}},"7":{"start":{"line":23,"column":4},"end":{"line":30,"column":null}},"8":{"start":{"line":44,"column":26},"end":{"line":44,"column":28}},"9":{"start":{"line":45,"column":4},"end":{"line":77,"column":null}},"10":{"start":{"line":57,"column":10},"end":{"line":57,"column":34}},"11":{"start":{"line":59,"column":26},"end":{"line":64,"column":8}},"12":{"start":{"line":66,"column":6},"end":{"line":74,"column":null}},"13":{"start":{"line":76,"column":6},"end":{"line":76,"column":null}},"14":{"start":{"line":79,"column":4},"end":{"line":79,"column":null}},"15":{"start":{"line":6,"column":0},"end":{"line":6,"column":13}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":7,"column":2},"end":{"line":7,"column":null}},"loc":{"start":{"line":11,"column":37},"end":{"line":12,"column":6}}},"1":{"name":"(anonymous_1)","decl":{"start":{"line":14,"column":2},"end":{"line":14,"column":7}},"loc":{"start":{"line":14,"column":64},"end":{"line":31,"column":3}}},"2":{"name":"(anonymous_2)","decl":{"start":{"line":17,"column":8},"end":{"line":17,"column":9}},"loc":{"start":{"line":17,"column":24},"end":{"line":17,"column":79}}},"3":{"name":"(anonymous_3)","decl":{"start":{"line":41,"column":2},"end":{"line":41,"column":7}},"loc":{"start":{"line":42,"column":48},"end":{"line":80,"column":3}}}},"branchMap":{"0":{"loc":{"start":{"line":21,"column":15},"end":{"line":21,"column":54}},"type":"cond-expr","locations":[{"start":{"line":21,"column":34},"end":{"line":21,"column":49}},{"start":{"line":21,"column":52},"end":{"line":21,"column":54}}]},"1":{"loc":{"start":{"line":26,"column":14},"end":{"line":26,"column":65}},"type":"cond-expr","locations":[{"start":{"line":26,"column":31},"end":{"line":26,"column":51}},{"start":{"line":26,"column":54},"end":{"line":26,"column":65}}]},"2":{"loc":{"start":{"line":27,"column":17},"end":{"line":27,"column":69}},"type":"cond-expr","locations":[{"start":{"line":27,"column":34},"end":{"line":27,"column":52}},{"start":{"line":27,"column":55},"end":{"line":27,"column":69}}]}},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":6},"f":{"0":0,"1":0,"2":0,"3":0},"b":{"0":[0,0],"1":[0,0],"2":[0,0]}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/interfaces/ServiceInterfaceBuilder.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/interfaces/ServiceInterfaceBuilder.ts","statementMap":{"0":{"start":{"line":18,"column":13},"end":{"line":18,"column":null}},"1":{"start":{"line":16,"column":0},"end":{"line":16,"column":13}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":17,"column":2},"end":{"line":17,"column":null}},"loc":{"start":{"line":30,"column":5},"end":{"line":31,"column":6}}}},"branchMap":{},"s":{"0":0,"1":5},"f":{"0":0},"b":{}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/interfaces/setupInterfaces.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/interfaces/setupInterfaces.ts","statementMap":{"0":{"start":{"line":22,"column":13},"end":{"line":22,"column":null}},"1":{"start":{"line":23,"column":48},"end":{"line":23,"column":67}},"2":{"start":{"line":23,"column":65},"end":{"line":23,"column":67}},"3":{"start":{"line":23,"column":13},"end":{"line":23,"column":48}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":23,"column":48},"end":{"line":23,"column":49}},"loc":{"start":{"line":23,"column":65},"end":{"line":23,"column":67}}}},"branchMap":{},"s":{"0":5,"1":5,"2":0,"3":5},"f":{"0":0},"b":{}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/mainFn/CommandController.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/mainFn/CommandController.ts","statementMap":{"0":{"start":{"line":1,"column":0},"end":{"line":1,"column":43}},"1":{"start":{"line":2,"column":0},"end":{"line":2,"column":58}},"2":{"start":{"line":6,"column":0},"end":{"line":6,"column":null}},"3":{"start":{"line":12,"column":0},"end":{"line":12,"column":51}},"4":{"start":{"line":17,"column":13},"end":{"line":17,"column":44}},"5":{"start":{"line":18,"column":12},"end":{"line":18,"column":38}},"6":{"start":{"line":19,"column":21},"end":{"line":19,"column":47}},"7":{"start":{"line":20,"column":12},"end":{"line":20,"column":54}},"8":{"start":{"line":21,"column":13},"end":{"line":21,"column":38}},"9":{"start":{"line":24,"column":4},"end":{"line":100,"column":null}},"10":{"start":{"line":49,"column":23},"end":{"line":49,"column":44}},"11":{"start":{"line":51,"column":8},"end":{"line":59,"column":16}},"12":{"start":{"line":54,"column":27},"end":{"line":54,"column":71}},"13":{"start":{"line":55,"column":14},"end":{"line":57,"column":null}},"14":{"start":{"line":56,"column":16},"end":{"line":56,"column":null}},"15":{"start":{"line":58,"column":14},"end":{"line":58,"column":null}},"16":{"start":{"line":61,"column":6},"end":{"line":69,"column":null}},"17":{"start":{"line":62,"column":8},"end":{"line":64,"column":null}},"18":{"start":{"line":66,"column":8},"end":{"line":68,"column":null}},"19":{"start":{"line":70,"column":20},"end":{"line":70,"column":37}},"20":{"start":{"line":71,"column":21},"end":{"line":91,"column":8}},"21":{"start":{"line":72,"column":8},"end":{"line":90,"column":null}},"22":{"start":{"line":73,"column":10},"end":{"line":73,"column":null}},"23":{"start":{"line":74,"column":10},"end":{"line":80,"column":null}},"24":{"start":{"line":79,"column":12},"end":{"line":79,"column":null}},"25":{"start":{"line":81,"column":10},"end":{"line":89,"column":null}},"26":{"start":{"line":82,"column":12},"end":{"line":82,"column":null}},"27":{"start":{"line":84,"column":12},"end":{"line":88,"column":null}},"28":{"start":{"line":93,"column":6},"end":{"line":99,"column":null}},"29":{"start":{"line":103,"column":4},"end":{"line":103,"column":null}},"30":{"start":{"line":106,"column":4},"end":{"line":109,"column":null}},"31":{"start":{"line":107,"column":6},"end":{"line":109,"column":null}},"32":{"start":{"line":108,"column":8},"end":{"line":108,"column":null}},"33":{"start":{"line":110,"column":4},"end":{"line":117,"column":null}},"34":{"start":{"line":111,"column":6},"end":{"line":111,"column":null}},"35":{"start":{"line":113,"column":6},"end":{"line":115,"column":null}},"36":{"start":{"line":114,"column":8},"end":{"line":114,"column":null}},"37":{"start":{"line":116,"column":6},"end":{"line":116,"column":null}},"38":{"start":{"line":120,"column":4},"end":{"line":137,"column":null}},"39":{"start":{"line":121,"column":6},"end":{"line":127,"column":null}},"40":{"start":{"line":122,"column":8},"end":{"line":126,"column":null}},"41":{"start":{"line":123,"column":10},"end":{"line":125,"column":null}},"42":{"start":{"line":129,"column":6},"end":{"line":133,"column":null}},"43":{"start":{"line":130,"column":8},"end":{"line":132,"column":null}},"44":{"start":{"line":131,"column":10},"end":{"line":131,"column":null}},"45":{"start":{"line":134,"column":6},"end":{"line":134,"column":null}},"46":{"start":{"line":136,"column":6},"end":{"line":136,"column":null}},"47":{"start":{"line":15,"column":0},"end":{"line":15,"column":13}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":16,"column":2},"end":{"line":16,"column":null}},"loc":{"start":{"line":21,"column":61},"end":{"line":22,"column":6}}},"1":{"name":"(anonymous_1)","decl":{"start":{"line":23,"column":2},"end":{"line":23,"column":8}},"loc":{"start":{"line":23,"column":11},"end":{"line":101,"column":3}}},"2":{"name":"(anonymous_2)","decl":{"start":{"line":24,"column":11},"end":{"line":24,"column":16}},"loc":{"start":{"line":48,"column":8},"end":{"line":100,"column":5}}},"3":{"name":"(anonymous_3)","decl":{"start":{"line":53,"column":19},"end":{"line":53,"column":24}},"loc":{"start":{"line":53,"column":30},"end":{"line":59,"column":13}}},"4":{"name":"(anonymous_4)","decl":{"start":{"line":71,"column":39},"end":{"line":71,"column":40}},"loc":{"start":{"line":71,"column":59},"end":{"line":91,"column":7}}},"5":{"name":"(anonymous_5)","decl":{"start":{"line":72,"column":32},"end":{"line":72,"column":33}},"loc":{"start":{"line":72,"column":41},"end":{"line":90,"column":9}}},"6":{"name":"(anonymous_6)","decl":{"start":{"line":102,"column":2},"end":{"line":102,"column":6}},"loc":{"start":{"line":102,"column":24},"end":{"line":104,"column":3}}},"7":{"name":"(anonymous_7)","decl":{"start":{"line":105,"column":2},"end":{"line":105,"column":7}},"loc":{"start":{"line":105,"column":42},"end":{"line":118,"column":3}}},"8":{"name":"(anonymous_8)","decl":{"start":{"line":107,"column":17},"end":{"line":107,"column":20}},"loc":{"start":{"line":107,"column":22},"end":{"line":109,"column":7}}},"9":{"name":"(anonymous_9)","decl":{"start":{"line":116,"column":48},"end":{"line":116,"column":49}},"loc":{"start":{"line":116,"column":54},"end":{"line":116,"column":57}}},"10":{"name":"(anonymous_10)","decl":{"start":{"line":119,"column":2},"end":{"line":119,"column":7}},"loc":{"start":{"line":119,"column":69},"end":{"line":138,"column":3}}},"11":{"name":"(anonymous_11)","decl":{"start":{"line":130,"column":19},"end":{"line":130,"column":22}},"loc":{"start":{"line":130,"column":24},"end":{"line":132,"column":9}}}},"branchMap":{"0":{"loc":{"start":{"line":21,"column":13},"end":{"line":21,"column":61}},"type":"default-arg","locations":[{"start":{"line":21,"column":38},"end":{"line":21,"column":61}}]},"1":{"loc":{"start":{"line":51,"column":8},"end":{"line":59,"column":16}},"type":"cond-expr","locations":[{"start":{"line":52,"column":12},"end":{"line":52,"column":24}},{"start":{"line":53,"column":12},"end":{"line":59,"column":16}}]},"2":{"loc":{"start":{"line":55,"column":32},"end":{"line":55,"column":52}},"type":"binary-expr","locations":[{"start":{"line":55,"column":32},"end":{"line":55,"column":46}},{"start":{"line":55,"column":50},"end":{"line":55,"column":52}}]},"3":{"loc":{"start":{"line":61,"column":6},"end":{"line":69,"column":null}},"type":"if","locations":[{"start":{"line":61,"column":6},"end":{"line":69,"column":null}},{"start":{"line":65,"column":13},"end":{"line":69,"column":null}}]},"4":{"loc":{"start":{"line":74,"column":10},"end":{"line":80,"column":null}},"type":"if","locations":[{"start":{"line":74,"column":10},"end":{"line":80,"column":null}}]},"5":{"loc":{"start":{"line":75,"column":12},"end":{"line":77,"column":67}},"type":"binary-expr","locations":[{"start":{"line":75,"column":12},"end":{"line":75,"column":22}},{"start":{"line":76,"column":12},"end":{"line":76,"column":24}},{"start":{"line":77,"column":13},"end":{"line":77,"column":26}},{"start":{"line":77,"column":30},"end":{"line":77,"column":66}}]},"6":{"loc":{"start":{"line":81,"column":10},"end":{"line":89,"column":null}},"type":"if","locations":[{"start":{"line":81,"column":10},"end":{"line":89,"column":null}},{"start":{"line":83,"column":17},"end":{"line":89,"column":null}}]},"7":{"loc":{"start":{"line":105,"column":13},"end":{"line":105,"column":42}},"type":"default-arg","locations":[{"start":{"line":105,"column":40},"end":{"line":105,"column":42}}]},"8":{"loc":{"start":{"line":105,"column":15},"end":{"line":105,"column":35}},"type":"default-arg","locations":[{"start":{"line":105,"column":25},"end":{"line":105,"column":35}}]},"9":{"loc":{"start":{"line":106,"column":4},"end":{"line":109,"column":null}},"type":"if","locations":[{"start":{"line":106,"column":4},"end":{"line":109,"column":null}}]},"10":{"loc":{"start":{"line":113,"column":6},"end":{"line":115,"column":null}},"type":"if","locations":[{"start":{"line":113,"column":6},"end":{"line":115,"column":null}}]},"11":{"loc":{"start":{"line":119,"column":13},"end":{"line":119,"column":69}},"type":"default-arg","locations":[{"start":{"line":119,"column":67},"end":{"line":119,"column":69}}]},"12":{"loc":{"start":{"line":119,"column":15},"end":{"line":119,"column":31}},"type":"default-arg","locations":[{"start":{"line":119,"column":24},"end":{"line":119,"column":31}}]},"13":{"loc":{"start":{"line":119,"column":33},"end":{"line":119,"column":62}},"type":"default-arg","locations":[{"start":{"line":119,"column":43},"end":{"line":119,"column":62}}]},"14":{"loc":{"start":{"line":121,"column":6},"end":{"line":127,"column":null}},"type":"if","locations":[{"start":{"line":121,"column":6},"end":{"line":127,"column":null}}]},"15":{"loc":{"start":{"line":122,"column":8},"end":{"line":126,"column":null}},"type":"if","locations":[{"start":{"line":122,"column":8},"end":{"line":126,"column":null}}]},"16":{"loc":{"start":{"line":129,"column":6},"end":{"line":133,"column":null}},"type":"if","locations":[{"start":{"line":129,"column":6},"end":{"line":133,"column":null}}]}},"s":{"0":5,"1":5,"2":5,"3":5,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0,"36":0,"37":0,"38":0,"39":0,"40":0,"41":0,"42":0,"43":0,"44":0,"45":0,"46":0,"47":5},"f":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0},"b":{"0":[0],"1":[0,0],"2":[0,0],"3":[0,0],"4":[0],"5":[0,0,0,0],"6":[0,0],"7":[0],"8":[0],"9":[0],"10":[0],"11":[0],"12":[0],"13":[0],"14":[0],"15":[0],"16":[0]}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/mainFn/Daemon.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/mainFn/Daemon.ts","statementMap":{"0":{"start":{"line":2,"column":0},"end":{"line":2,"column":41}},"1":{"start":{"line":4,"column":0},"end":{"line":4,"column":55}},"2":{"start":{"line":6,"column":29},"end":{"line":6,"column":33}},"3":{"start":{"line":7,"column":23},"end":{"line":7,"column":28}},"4":{"start":{"line":14,"column":56},"end":{"line":14,"column":60}},"5":{"start":{"line":15,"column":28},"end":{"line":15,"column":33}},"6":{"start":{"line":16,"column":22},"end":{"line":16,"column":68}},"7":{"start":{"line":18,"column":4},"end":{"line":18,"column":null}},"8":{"start":{"line":21,"column":4},"end":{"line":52,"column":null}},"9":{"start":{"line":44,"column":27},"end":{"line":49,"column":null}},"10":{"start":{"line":45,"column":8},"end":{"line":49,"column":null}},"11":{"start":{"line":51,"column":6},"end":{"line":51,"column":null}},"12":{"start":{"line":55,"column":4},"end":{"line":57,"column":null}},"13":{"start":{"line":56,"column":6},"end":{"line":56,"column":12}},"14":{"start":{"line":58,"column":4},"end":{"line":58,"column":null}},"15":{"start":{"line":59,"column":25},"end":{"line":59,"column":26}},"16":{"start":{"line":60,"column":4},"end":{"line":70,"column":null}},"17":{"start":{"line":61,"column":6},"end":{"line":67,"column":null}},"18":{"start":{"line":62,"column":8},"end":{"line":62,"column":null}},"19":{"start":{"line":63,"column":8},"end":{"line":63,"column":null}},"20":{"start":{"line":63,"column":59},"end":{"line":63,"column":77}},"21":{"start":{"line":64,"column":8},"end":{"line":64,"column":null}},"22":{"start":{"line":64,"column":39},"end":{"line":64,"column":74}},"23":{"start":{"line":65,"column":8},"end":{"line":65,"column":null}},"24":{"start":{"line":66,"column":8},"end":{"line":66,"column":null}},"25":{"start":{"line":69,"column":6},"end":{"line":69,"column":null}},"26":{"start":{"line":76,"column":4},"end":{"line":76,"column":null}},"27":{"start":{"line":82,"column":4},"end":{"line":82,"column":null}},"28":{"start":{"line":83,"column":4},"end":{"line":85,"column":null}},"29":{"start":{"line":85,"column":20},"end":{"line":85,"column":45}},"30":{"start":{"line":86,"column":4},"end":{"line":86,"column":null}},"31":{"start":{"line":13,"column":0},"end":{"line":13,"column":13}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":16,"column":2},"end":{"line":16,"column":22}},"loc":{"start":{"line":16,"column":68},"end":{"line":16,"column":72}}},"1":{"name":"(anonymous_1)","decl":{"start":{"line":17,"column":2},"end":{"line":17,"column":6}},"loc":{"start":{"line":17,"column":24},"end":{"line":19,"column":3}}},"2":{"name":"(anonymous_2)","decl":{"start":{"line":20,"column":2},"end":{"line":20,"column":8}},"loc":{"start":{"line":20,"column":11},"end":{"line":53,"column":3}}},"3":{"name":"(anonymous_3)","decl":{"start":{"line":21,"column":11},"end":{"line":21,"column":16}},"loc":{"start":{"line":43,"column":8},"end":{"line":52,"column":5}}},"4":{"name":"(anonymous_4)","decl":{"start":{"line":44,"column":27},"end":{"line":44,"column":30}},"loc":{"start":{"line":45,"column":8},"end":{"line":49,"column":null}}},"5":{"name":"(anonymous_5)","decl":{"start":{"line":54,"column":2},"end":{"line":54,"column":7}},"loc":{"start":{"line":54,"column":13},"end":{"line":71,"column":3}}},"6":{"name":"(anonymous_6)","decl":{"start":{"line":60,"column":16},"end":{"line":60,"column":21}},"loc":{"start":{"line":60,"column":27},"end":{"line":68,"column":5}}},"7":{"name":"(anonymous_7)","decl":{"start":{"line":63,"column":50},"end":{"line":63,"column":51}},"loc":{"start":{"line":63,"column":59},"end":{"line":63,"column":77}}},"8":{"name":"(anonymous_8)","decl":{"start":{"line":64,"column":26},"end":{"line":64,"column":27}},"loc":{"start":{"line":64,"column":39},"end":{"line":64,"column":74}}},"9":{"name":"(anonymous_9)","decl":{"start":{"line":68,"column":13},"end":{"line":68,"column":14}},"loc":{"start":{"line":68,"column":21},"end":{"line":70,"column":5}}},"10":{"name":"(anonymous_10)","decl":{"start":{"line":72,"column":2},"end":{"line":72,"column":7}},"loc":{"start":{"line":75,"column":3},"end":{"line":77,"column":3}}},"11":{"name":"(anonymous_11)","decl":{"start":{"line":78,"column":2},"end":{"line":78,"column":7}},"loc":{"start":{"line":81,"column":3},"end":{"line":87,"column":3}}},"12":{"name":"(anonymous_12)","decl":{"start":{"line":85,"column":13},"end":{"line":85,"column":14}},"loc":{"start":{"line":85,"column":20},"end":{"line":85,"column":45}}}},"branchMap":{"0":{"loc":{"start":{"line":55,"column":4},"end":{"line":57,"column":null}},"type":"if","locations":[{"start":{"line":55,"column":4},"end":{"line":57,"column":null}}]}},"s":{"0":5,"1":5,"2":5,"3":5,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":5},"f":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0},"b":{"0":[0]}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/mainFn/Daemons.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/mainFn/Daemons.ts","statementMap":{"0":{"start":{"line":18,"column":0},"end":{"line":18,"column":37}},"1":{"start":{"line":19,"column":0},"end":{"line":19,"column":40}},"2":{"start":{"line":21,"column":0},"end":{"line":21,"column":9}},"3":{"start":{"line":21,"column":9},"end":{"line":21,"column":33}},"4":{"start":{"line":22,"column":0},"end":{"line":22,"column":9}},"5":{"start":{"line":22,"column":9},"end":{"line":22,"column":55}},"6":{"start":{"line":23,"column":0},"end":{"line":23,"column":45}},"7":{"start":{"line":24,"column":0},"end":{"line":24,"column":33}},"8":{"start":{"line":25,"column":0},"end":{"line":25,"column":55}},"9":{"start":{"line":27,"column":13},"end":{"line":27,"column":null}},"10":{"start":{"line":28,"column":13},"end":{"line":28,"column":null}},"11":{"start":{"line":54,"column":26},"end":{"line":55,"column":34}},"12":{"start":{"line":55,"column":2},"end":{"line":55,"column":34}},"13":{"start":{"line":54,"column":13},"end":{"line":54,"column":26}},"14":{"start":{"line":82,"column":13},"end":{"line":82,"column":31}},"15":{"start":{"line":83,"column":13},"end":{"line":83,"column":76}},"16":{"start":{"line":84,"column":13},"end":{"line":84,"column":39}},"17":{"start":{"line":85,"column":13},"end":{"line":85,"column":23}},"18":{"start":{"line":86,"column":13},"end":{"line":86,"column":42}},"19":{"start":{"line":103,"column":4},"end":{"line":109,"column":null}},"20":{"start":{"line":126,"column":24},"end":{"line":126,"column":43}},"21":{"start":{"line":127,"column":19},"end":{"line":130,"column":6}},"22":{"start":{"line":131,"column":25},"end":{"line":142,"column":null}},"23":{"start":{"line":135,"column":20},"end":{"line":135,"column":47}},"24":{"start":{"line":136,"column":23},"end":{"line":136,"column":29}},"25":{"start":{"line":137,"column":21},"end":{"line":137,"column":43}},"26":{"start":{"line":144,"column":20},"end":{"line":144,"column":47}},"27":{"start":{"line":145,"column":16},"end":{"line":145,"column":49}},"28":{"start":{"line":146,"column":26},"end":{"line":146,"column":63}},"29":{"start":{"line":147,"column":4},"end":{"line":153,"column":null}},"30":{"start":{"line":157,"column":4},"end":{"line":157,"column":null}},"31":{"start":{"line":158,"column":4},"end":{"line":160,"column":null}},"32":{"start":{"line":159,"column":6},"end":{"line":159,"column":49}},"33":{"start":{"line":159,"column":25},"end":{"line":159,"column":48}},"34":{"start":{"line":161,"column":18},"end":{"line":169,"column":null}},"35":{"start":{"line":163,"column":8},"end":{"line":167,"column":null}},"36":{"start":{"line":164,"column":10},"end":{"line":164,"column":null}},"37":{"start":{"line":164,"column":58},"end":{"line":164,"column":73}},"38":{"start":{"line":166,"column":10},"end":{"line":166,"column":null}},"39":{"start":{"line":170,"column":4},"end":{"line":170,"column":null}},"40":{"start":{"line":170,"column":23},"end":{"line":170,"column":35}},"41":{"start":{"line":171,"column":4},"end":{"line":171,"column":null}},"42":{"start":{"line":175,"column":4},"end":{"line":175,"column":null}},"43":{"start":{"line":80,"column":0},"end":{"line":80,"column":13}}},"fnMap":{"0":{"name":"(anonymous_6)","decl":{"start":{"line":21,"column":9},"end":{"line":21,"column":15}},"loc":{"start":{"line":21,"column":9},"end":{"line":21,"column":33}}},"1":{"name":"(anonymous_7)","decl":{"start":{"line":22,"column":9},"end":{"line":22,"column":26}},"loc":{"start":{"line":22,"column":9},"end":{"line":22,"column":55}}},"2":{"name":"(anonymous_8)","decl":{"start":{"line":54,"column":26},"end":{"line":54,"column":58}},"loc":{"start":{"line":55,"column":2},"end":{"line":55,"column":34}}},"3":{"name":"(anonymous_9)","decl":{"start":{"line":81,"column":2},"end":{"line":81,"column":null}},"loc":{"start":{"line":86,"column":42},"end":{"line":87,"column":6}}},"4":{"name":"(anonymous_10)","decl":{"start":{"line":98,"column":2},"end":{"line":98,"column":8}},"loc":{"start":{"line":102,"column":3},"end":{"line":110,"column":3}}},"5":{"name":"(anonymous_11)","decl":{"start":{"line":117,"column":2},"end":{"line":117,"column":11}},"loc":{"start":{"line":124,"column":54},"end":{"line":154,"column":3}}},"6":{"name":"(anonymous_12)","decl":{"start":{"line":135,"column":13},"end":{"line":135,"column":14}},"loc":{"start":{"line":135,"column":20},"end":{"line":135,"column":47}}},"7":{"name":"(anonymous_13)","decl":{"start":{"line":136,"column":16},"end":{"line":136,"column":17}},"loc":{"start":{"line":136,"column":23},"end":{"line":136,"column":29}}},"8":{"name":"(anonymous_14)","decl":{"start":{"line":137,"column":13},"end":{"line":137,"column":14}},"loc":{"start":{"line":137,"column":21},"end":{"line":137,"column":43}}},"9":{"name":"(anonymous_15)","decl":{"start":{"line":156,"column":2},"end":{"line":156,"column":7}},"loc":{"start":{"line":156,"column":13},"end":{"line":172,"column":3}}},"10":{"name":"(anonymous_16)","decl":{"start":{"line":158,"column":31},"end":{"line":158,"column":32}},"loc":{"start":{"line":159,"column":6},"end":{"line":159,"column":49}}},"11":{"name":"(anonymous_17)","decl":{"start":{"line":159,"column":19},"end":{"line":159,"column":22}},"loc":{"start":{"line":159,"column":25},"end":{"line":159,"column":48}}},"12":{"name":"(anonymous_18)","decl":{"start":{"line":162,"column":12},"end":{"line":162,"column":17}},"loc":{"start":{"line":162,"column":71},"end":{"line":168,"column":7}}},"13":{"name":"(anonymous_19)","decl":{"start":{"line":164,"column":51},"end":{"line":164,"column":52}},"loc":{"start":{"line":164,"column":58},"end":{"line":164,"column":73}}},"14":{"name":"(anonymous_20)","decl":{"start":{"line":170,"column":17},"end":{"line":170,"column":20}},"loc":{"start":{"line":170,"column":23},"end":{"line":170,"column":35}}},"15":{"name":"(anonymous_21)","decl":{"start":{"line":174,"column":10},"end":{"line":174,"column":26}},"loc":{"start":{"line":174,"column":26},"end":{"line":176,"column":3}}}},"branchMap":{},"s":{"0":5,"1":5,"2":5,"3":5,"4":5,"5":5,"6":5,"7":5,"8":5,"9":5,"10":5,"11":5,"12":0,"13":5,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0,"36":0,"37":0,"38":0,"39":0,"40":0,"41":0,"42":0,"43":5},"f":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0},"b":{}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/mainFn/HealthDaemon.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/mainFn/HealthDaemon.ts","statementMap":{"0":{"start":{"line":2,"column":0},"end":{"line":2,"column":58}},"1":{"start":{"line":6,"column":0},"end":{"line":6,"column":43}},"2":{"start":{"line":7,"column":0},"end":{"line":7,"column":41}},"3":{"start":{"line":9,"column":20},"end":{"line":15,"column":1}},"4":{"start":{"line":11,"column":18},"end":{"line":13,"column":4}},"5":{"start":{"line":12,"column":4},"end":{"line":12,"column":null}},"6":{"start":{"line":14,"column":2},"end":{"line":14,"column":null}},"7":{"start":{"line":25,"column":39},"end":{"line":25,"column":76}},"8":{"start":{"line":26,"column":49},"end":{"line":26,"column":51}},"9":{"start":{"line":27,"column":20},"end":{"line":27,"column":25}},"10":{"start":{"line":29,"column":21},"end":{"line":29,"column":44}},"11":{"start":{"line":30,"column":13},"end":{"line":30,"column":32}},"12":{"start":{"line":31,"column":21},"end":{"line":31,"column":49}},"13":{"start":{"line":32,"column":13},"end":{"line":32,"column":23}},"14":{"start":{"line":33,"column":13},"end":{"line":33,"column":26}},"15":{"start":{"line":34,"column":13},"end":{"line":34,"column":25}},"16":{"start":{"line":35,"column":13},"end":{"line":35,"column":29}},"17":{"start":{"line":36,"column":13},"end":{"line":36,"column":38}},"18":{"start":{"line":38,"column":4},"end":{"line":38,"column":null}},"19":{"start":{"line":39,"column":4},"end":{"line":39,"column":null}},"20":{"start":{"line":39,"column":37},"end":{"line":39,"column":76}},"21":{"start":{"line":39,"column":56},"end":{"line":39,"column":75}},"22":{"start":{"line":47,"column":4},"end":{"line":47,"column":null}},"23":{"start":{"line":48,"column":4},"end":{"line":48,"column":null}},"24":{"start":{"line":49,"column":4},"end":{"line":49,"column":null}},"25":{"start":{"line":51,"column":4},"end":{"line":56,"column":null}},"26":{"start":{"line":52,"column":6},"end":{"line":55,"column":8}},"27":{"start":{"line":61,"column":4},"end":{"line":61,"column":null}},"28":{"start":{"line":65,"column":4},"end":{"line":65,"column":null}},"29":{"start":{"line":69,"column":4},"end":{"line":69,"column":42}},"30":{"start":{"line":69,"column":36},"end":{"line":69,"column":42}},"31":{"start":{"line":71,"column":4},"end":{"line":71,"column":null}},"32":{"start":{"line":73,"column":4},"end":{"line":81,"column":null}},"33":{"start":{"line":74,"column":7},"end":{"line":74,"column":null}},"34":{"start":{"line":75,"column":6},"end":{"line":75,"column":null}},"35":{"start":{"line":77,"column":7},"end":{"line":77,"column":null}},"36":{"start":{"line":78,"column":6},"end":{"line":78,"column":null}},"37":{"start":{"line":80,"column":6},"end":{"line":80,"column":null}},"38":{"start":{"line":84,"column":52},"end":{"line":84,"column":56}},"39":{"start":{"line":86,"column":4},"end":{"line":86,"column":null}},"40":{"start":{"line":89,"column":4},"end":{"line":89,"column":39}},"41":{"start":{"line":89,"column":33},"end":{"line":89,"column":39}},"42":{"start":{"line":90,"column":20},"end":{"line":92,"column":7}},"43":{"start":{"line":90,"column":66},"end":{"line":92,"column":6}},"44":{"start":{"line":94,"column":52},"end":{"line":94,"column":null}},"45":{"start":{"line":97,"column":4},"end":{"line":123,"column":null}},"46":{"start":{"line":98,"column":6},"end":{"line":122,"column":null}},"47":{"start":{"line":99,"column":18},"end":{"line":99,"column":62}},"48":{"start":{"line":103,"column":23},"end":{"line":103,"column":61}},"49":{"start":{"line":105,"column":8},"end":{"line":121,"column":null}},"50":{"start":{"line":106,"column":46},"end":{"line":114,"column":12}},"51":{"start":{"line":109,"column":12},"end":{"line":109,"column":null}},"52":{"start":{"line":110,"column":12},"end":{"line":113,"column":null}},"53":{"start":{"line":115,"column":10},"end":{"line":115,"column":null}},"54":{"start":{"line":117,"column":10},"end":{"line":120,"column":null}},"55":{"start":{"line":123,"column":22},"end":{"line":123,"column":71}},"56":{"start":{"line":125,"column":4},"end":{"line":128,"column":null}},"57":{"start":{"line":126,"column":6},"end":{"line":126,"column":null}},"58":{"start":{"line":127,"column":6},"end":{"line":127,"column":null}},"59":{"start":{"line":132,"column":4},"end":{"line":132,"column":null}},"60":{"start":{"line":133,"column":4},"end":{"line":133,"column":null}},"61":{"start":{"line":133,"column":45},"end":{"line":133,"column":54}},"62":{"start":{"line":134,"column":20},"end":{"line":134,"column":38}},"63":{"start":{"line":135,"column":19},"end":{"line":135,"column":32}},"64":{"start":{"line":136,"column":4},"end":{"line":138,"column":null}},"65":{"start":{"line":137,"column":6},"end":{"line":137,"column":12}},"66":{"start":{"line":139,"column":4},"end":{"line":143,"column":null}},"67":{"start":{"line":147,"column":20},"end":{"line":147,"column":59}},"68":{"start":{"line":147,"column":49},"end":{"line":147,"column":58}},"69":{"start":{"line":148,"column":4},"end":{"line":148,"column":null}},"70":{"start":{"line":148,"column":44},"end":{"line":148,"column":66}},"71":{"start":{"line":24,"column":0},"end":{"line":24,"column":13}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":9,"column":20},"end":{"line":9,"column":26}},"loc":{"start":{"line":9,"column":28},"end":{"line":15,"column":1}}},"1":{"name":"(anonymous_1)","decl":{"start":{"line":11,"column":33},"end":{"line":11,"column":34}},"loc":{"start":{"line":11,"column":41},"end":{"line":13,"column":3}}},"2":{"name":"(anonymous_2)","decl":{"start":{"line":28,"column":2},"end":{"line":28,"column":null}},"loc":{"start":{"line":36,"column":61},"end":{"line":40,"column":3}}},"3":{"name":"(anonymous_3)","decl":{"start":{"line":39,"column":30},"end":{"line":39,"column":31}},"loc":{"start":{"line":39,"column":37},"end":{"line":39,"column":76}}},"4":{"name":"(anonymous_4)","decl":{"start":{"line":39,"column":50},"end":{"line":39,"column":53}},"loc":{"start":{"line":39,"column":56},"end":{"line":39,"column":75}}},"5":{"name":"(anonymous_5)","decl":{"start":{"line":43,"column":2},"end":{"line":43,"column":7}},"loc":{"start":{"line":46,"column":3},"end":{"line":57,"column":3}}},"6":{"name":"(anonymous_6)","decl":{"start":{"line":51,"column":27},"end":{"line":51,"column":28}},"loc":{"start":{"line":52,"column":6},"end":{"line":55,"column":8}}},"7":{"name":"(anonymous_7)","decl":{"start":{"line":60,"column":2},"end":{"line":60,"column":12}},"loc":{"start":{"line":60,"column":35},"end":{"line":62,"column":3}}},"8":{"name":"(anonymous_8)","decl":{"start":{"line":64,"column":2},"end":{"line":64,"column":6}},"loc":{"start":{"line":64,"column":12},"end":{"line":66,"column":3}}},"9":{"name":"(anonymous_9)","decl":{"start":{"line":68,"column":10},"end":{"line":68,"column":15}},"loc":{"start":{"line":68,"column":48},"end":{"line":82,"column":3}}},"10":{"name":"(anonymous_10)","decl":{"start":{"line":85,"column":10},"end":{"line":85,"column":28}},"loc":{"start":{"line":85,"column":28},"end":{"line":87,"column":3}}},"11":{"name":"(anonymous_11)","decl":{"start":{"line":88,"column":10},"end":{"line":88,"column":15}},"loc":{"start":{"line":88,"column":32},"end":{"line":129,"column":3}}},"12":{"name":"(anonymous_12)","decl":{"start":{"line":90,"column":59},"end":{"line":90,"column":62}},"loc":{"start":{"line":90,"column":66},"end":{"line":92,"column":6}}},"13":{"name":"(anonymous_13)","decl":{"start":{"line":97,"column":16},"end":{"line":97,"column":21}},"loc":{"start":{"line":97,"column":27},"end":{"line":123,"column":5}}},"14":{"name":"(anonymous_14)","decl":{"start":{"line":108,"column":18},"end":{"line":108,"column":19}},"loc":{"start":{"line":108,"column":26},"end":{"line":114,"column":11}}},"15":{"name":"(anonymous_15)","decl":{"start":{"line":123,"column":13},"end":{"line":123,"column":14}},"loc":{"start":{"line":123,"column":22},"end":{"line":123,"column":71}}},"16":{"name":"(anonymous_16)","decl":{"start":{"line":125,"column":30},"end":{"line":125,"column":33}},"loc":{"start":{"line":125,"column":35},"end":{"line":128,"column":5}}},"17":{"name":"(anonymous_17)","decl":{"start":{"line":131,"column":10},"end":{"line":131,"column":15}},"loc":{"start":{"line":131,"column":51},"end":{"line":144,"column":3}}},"18":{"name":"(anonymous_18)","decl":{"start":{"line":133,"column":32},"end":{"line":133,"column":33}},"loc":{"start":{"line":133,"column":45},"end":{"line":133,"column":54}}},"19":{"name":"(anonymous_19)","decl":{"start":{"line":146,"column":10},"end":{"line":146,"column":15}},"loc":{"start":{"line":146,"column":28},"end":{"line":149,"column":3}}},"20":{"name":"(anonymous_20)","decl":{"start":{"line":147,"column":42},"end":{"line":147,"column":43}},"loc":{"start":{"line":147,"column":49},"end":{"line":147,"column":58}}},"21":{"name":"(anonymous_21)","decl":{"start":{"line":148,"column":37},"end":{"line":148,"column":38}},"loc":{"start":{"line":148,"column":44},"end":{"line":148,"column":66}}}},"branchMap":{"0":{"loc":{"start":{"line":36,"column":13},"end":{"line":36,"column":61}},"type":"default-arg","locations":[{"start":{"line":36,"column":38},"end":{"line":36,"column":61}}]},"1":{"loc":{"start":{"line":69,"column":4},"end":{"line":69,"column":42}},"type":"if","locations":[{"start":{"line":69,"column":4},"end":{"line":69,"column":42}}]},"2":{"loc":{"start":{"line":73,"column":4},"end":{"line":81,"column":null}},"type":"if","locations":[{"start":{"line":73,"column":4},"end":{"line":81,"column":null}},{"start":{"line":76,"column":11},"end":{"line":81,"column":null}}]},"3":{"loc":{"start":{"line":89,"column":4},"end":{"line":89,"column":39}},"type":"if","locations":[{"start":{"line":89,"column":4},"end":{"line":89,"column":39}}]},"4":{"loc":{"start":{"line":90,"column":21},"end":{"line":90,"column":57}},"type":"binary-expr","locations":[{"start":{"line":90,"column":21},"end":{"line":90,"column":39}},{"start":{"line":90,"column":43},"end":{"line":90,"column":57}}]},"5":{"loc":{"start":{"line":105,"column":8},"end":{"line":121,"column":null}},"type":"if","locations":[{"start":{"line":105,"column":8},"end":{"line":121,"column":null}},{"start":{"line":116,"column":15},"end":{"line":121,"column":null}}]},"6":{"loc":{"start":{"line":112,"column":23},"end":{"line":112,"column":67}},"type":"cond-expr","locations":[{"start":{"line":112,"column":42},"end":{"line":112,"column":53}},{"start":{"line":112,"column":56},"end":{"line":112,"column":67}}]},"7":{"loc":{"start":{"line":136,"column":4},"end":{"line":138,"column":null}},"type":"if","locations":[{"start":{"line":136,"column":4},"end":{"line":138,"column":null}}]}},"s":{"0":5,"1":5,"2":5,"3":5,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0,"36":0,"37":0,"38":0,"39":0,"40":0,"41":0,"42":0,"43":0,"44":0,"45":0,"46":0,"47":0,"48":0,"49":0,"50":0,"51":0,"52":0,"53":0,"54":0,"55":0,"56":0,"57":0,"58":0,"59":0,"60":0,"61":0,"62":0,"63":0,"64":0,"65":0,"66":0,"67":0,"68":0,"69":0,"70":0,"71":5},"f":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0},"b":{"0":[0],"1":[0],"2":[0,0],"3":[0],"4":[0,0],"5":[0,0],"6":[0,0],"7":[0]}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/mainFn/Mounts.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/mainFn/Mounts.ts","statementMap":{"0":{"start":{"line":8,"column":13},"end":{"line":8,"column":null}},"1":{"start":{"line":14,"column":13},"end":{"line":14,"column":null}},"2":{"start":{"line":19,"column":13},"end":{"line":19,"column":null}},"3":{"start":{"line":29,"column":4},"end":{"line":29,"column":null}},"4":{"start":{"line":38,"column":4},"end":{"line":43,"column":null}},"5":{"start":{"line":44,"column":4},"end":{"line":44,"column":null}},"6":{"start":{"line":52,"column":4},"end":{"line":56,"column":null}},"7":{"start":{"line":57,"column":4},"end":{"line":57,"column":null}},"8":{"start":{"line":67,"column":4},"end":{"line":73,"column":null}},"9":{"start":{"line":74,"column":4},"end":{"line":74,"column":null}},"10":{"start":{"line":78,"column":24},"end":{"line":78,"column":33}},"11":{"start":{"line":79,"column":4},"end":{"line":89,"column":null}},"12":{"start":{"line":80,"column":18},"end":{"line":80,"column":30}},"13":{"start":{"line":81,"column":37},"end":{"line":81,"column":49}},"14":{"start":{"line":82,"column":43},"end":{"line":82,"column":55}},"15":{"start":{"line":83,"column":6},"end":{"line":87,"column":null}},"16":{"start":{"line":84,"column":8},"end":{"line":86,"column":null}},"17":{"start":{"line":88,"column":6},"end":{"line":88,"column":null}},"18":{"start":{"line":90,"column":4},"end":{"line":123,"column":null}},"19":{"start":{"line":92,"column":33},"end":{"line":100,"column":10}},"20":{"start":{"line":103,"column":32},"end":{"line":110,"column":10}},"21":{"start":{"line":113,"column":38},"end":{"line":122,"column":10}},"22":{"start":{"line":6,"column":0},"end":{"line":6,"column":13}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":7,"column":2},"end":{"line":7,"column":null}},"loc":{"start":{"line":25,"column":7},"end":{"line":26,"column":6}}},"1":{"name":"(anonymous_1)","decl":{"start":{"line":28,"column":2},"end":{"line":28,"column":8}},"loc":{"start":{"line":28,"column":11},"end":{"line":30,"column":3}}},"2":{"name":"(anonymous_2)","decl":{"start":{"line":32,"column":2},"end":{"line":32,"column":11}},"loc":{"start":{"line":36,"column":21},"end":{"line":45,"column":3}}},"3":{"name":"(anonymous_3)","decl":{"start":{"line":47,"column":2},"end":{"line":47,"column":11}},"loc":{"start":{"line":50,"column":22},"end":{"line":58,"column":3}}},"4":{"name":"(anonymous_4)","decl":{"start":{"line":60,"column":2},"end":{"line":60,"column":15}},"loc":{"start":{"line":65,"column":21},"end":{"line":75,"column":3}}},"5":{"name":"(anonymous_5)","decl":{"start":{"line":77,"column":2},"end":{"line":77,"column":7}},"loc":{"start":{"line":77,"column":7},"end":{"line":124,"column":3}}},"6":{"name":"(anonymous_6)","decl":{"start":{"line":80,"column":11},"end":{"line":80,"column":12}},"loc":{"start":{"line":80,"column":18},"end":{"line":80,"column":30}}},"7":{"name":"(anonymous_7)","decl":{"start":{"line":81,"column":30},"end":{"line":81,"column":31}},"loc":{"start":{"line":81,"column":37},"end":{"line":81,"column":49}}},"8":{"name":"(anonymous_8)","decl":{"start":{"line":82,"column":36},"end":{"line":82,"column":37}},"loc":{"start":{"line":82,"column":43},"end":{"line":82,"column":55}}},"9":{"name":"(anonymous_9)","decl":{"start":{"line":92,"column":25},"end":{"line":92,"column":26}},"loc":{"start":{"line":92,"column":33},"end":{"line":100,"column":10}}},"10":{"name":"(anonymous_10)","decl":{"start":{"line":103,"column":24},"end":{"line":103,"column":25}},"loc":{"start":{"line":103,"column":32},"end":{"line":110,"column":10}}},"11":{"name":"(anonymous_11)","decl":{"start":{"line":113,"column":30},"end":{"line":113,"column":31}},"loc":{"start":{"line":113,"column":38},"end":{"line":122,"column":10}}}},"branchMap":{"0":{"loc":{"start":{"line":83,"column":6},"end":{"line":87,"column":null}},"type":"if","locations":[{"start":{"line":83,"column":6},"end":{"line":87,"column":null}}]}},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":5},"f":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0},"b":{"0":[0]}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/mainFn/index.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/mainFn/index.ts","statementMap":{"0":{"start":{"line":3,"column":0},"end":{"line":3,"column":46}},"1":{"start":{"line":4,"column":0},"end":{"line":4,"column":29}},"2":{"start":{"line":6,"column":0},"end":{"line":6,"column":18}},"3":{"start":{"line":10,"column":13},"end":{"line":10,"column":null}},"4":{"start":{"line":21,"column":25},"end":{"line":31,"column":1}},"5":{"start":{"line":27,"column":2},"end":{"line":30,"column":null}},"6":{"start":{"line":28,"column":19},"end":{"line":28,"column":36}},"7":{"start":{"line":29,"column":4},"end":{"line":29,"column":null}},"8":{"start":{"line":21,"column":13},"end":{"line":21,"column":25}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":21,"column":25},"end":{"line":21,"column":null}},"loc":{"start":{"line":26,"column":28},"end":{"line":31,"column":1}}},"1":{"name":"(anonymous_1)","decl":{"start":{"line":27,"column":9},"end":{"line":27,"column":14}},"loc":{"start":{"line":27,"column":27},"end":{"line":30,"column":3}}}},"branchMap":{},"s":{"0":5,"1":5,"2":5,"3":5,"4":5,"5":0,"6":0,"7":0,"8":5},"f":{"0":0,"1":0},"b":{}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/manifest/setupManifest.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/manifest/setupManifest.ts","statementMap":{"0":{"start":{"line":4,"column":0},"end":{"line":4,"column":40}},"1":{"start":{"line":31,"column":17},"end":{"line":39,"column":null}},"2":{"start":{"line":33,"column":6},"end":{"line":33,"column":null}},"3":{"start":{"line":34,"column":6},"end":{"line":35,"column":null}},"4":{"start":{"line":35,"column":8},"end":{"line":35,"column":null}},"5":{"start":{"line":36,"column":6},"end":{"line":36,"column":null}},"6":{"start":{"line":37,"column":6},"end":{"line":37,"column":null}},"7":{"start":{"line":41,"column":2},"end":{"line":83,"column":null}},"8":{"start":{"line":63,"column":22},"end":{"line":63,"column":35}},"9":{"start":{"line":71,"column":16},"end":{"line":73,"column":null}},"10":{"start":{"line":72,"column":18},"end":{"line":72,"column":null}},"11":{"start":{"line":74,"column":16},"end":{"line":76,"column":null}},"12":{"start":{"line":75,"column":18},"end":{"line":75,"column":null}},"13":{"start":{"line":77,"column":16},"end":{"line":77,"column":null}},"14":{"start":{"line":77,"column":42},"end":{"line":77,"column":65}},"15":{"start":{"line":12,"column":0},"end":{"line":12,"column":16}}},"fnMap":{"0":{"name":"setupManifest","decl":{"start":{"line":12,"column":16},"end":{"line":12,"column":29}},"loc":{"start":{"line":29,"column":34},"end":{"line":84,"column":1}}},"1":{"name":"(anonymous_1)","decl":{"start":{"line":32,"column":4},"end":{"line":32,"column":5}},"loc":{"start":{"line":32,"column":23},"end":{"line":38,"column":5}}},"2":{"name":"(anonymous_2)","decl":{"start":{"line":63,"column":10},"end":{"line":63,"column":11}},"loc":{"start":{"line":63,"column":22},"end":{"line":63,"column":35}}},"3":{"name":"(anonymous_3)","decl":{"start":{"line":70,"column":14},"end":{"line":70,"column":15}},"loc":{"start":{"line":70,"column":31},"end":{"line":78,"column":15}}},"4":{"name":"(anonymous_4)","decl":{"start":{"line":77,"column":35},"end":{"line":77,"column":36}},"loc":{"start":{"line":77,"column":42},"end":{"line":77,"column":65}}}},"branchMap":{"0":{"loc":{"start":{"line":33,"column":15},"end":{"line":33,"column":46}},"type":"binary-expr","locations":[{"start":{"line":33,"column":15},"end":{"line":33,"column":21}},{"start":{"line":33,"column":25},"end":{"line":33,"column":46}}]},"1":{"loc":{"start":{"line":34,"column":6},"end":{"line":35,"column":null}},"type":"if","locations":[{"start":{"line":34,"column":6},"end":{"line":35,"column":null}}]},"2":{"loc":{"start":{"line":35,"column":29},"end":{"line":35,"column":46}},"type":"binary-expr","locations":[{"start":{"line":35,"column":29},"end":{"line":35,"column":38}},{"start":{"line":35,"column":42},"end":{"line":35,"column":46}}]},"3":{"loc":{"start":{"line":47,"column":15},"end":{"line":47,"column":55}},"type":"binary-expr","locations":[{"start":{"line":47,"column":15},"end":{"line":47,"column":49}},{"start":{"line":47,"column":53},"end":{"line":47,"column":55}}]},"4":{"loc":{"start":{"line":52,"column":15},"end":{"line":52,"column":47}},"type":"binary-expr","locations":[{"start":{"line":52,"column":15},"end":{"line":52,"column":39}},{"start":{"line":52,"column":43},"end":{"line":52,"column":47}}]},"5":{"loc":{"start":{"line":53,"column":14},"end":{"line":53,"column":45}},"type":"binary-expr","locations":[{"start":{"line":53,"column":14},"end":{"line":53,"column":37}},{"start":{"line":53,"column":41},"end":{"line":53,"column":45}}]},"6":{"loc":{"start":{"line":54,"column":17},"end":{"line":54,"column":51}},"type":"binary-expr","locations":[{"start":{"line":54,"column":17},"end":{"line":54,"column":43}},{"start":{"line":54,"column":47},"end":{"line":54,"column":51}}]},"7":{"loc":{"start":{"line":55,"column":15},"end":{"line":55,"column":47}},"type":"binary-expr","locations":[{"start":{"line":55,"column":15},"end":{"line":55,"column":39}},{"start":{"line":55,"column":43},"end":{"line":55,"column":47}}]},"8":{"loc":{"start":{"line":56,"column":13},"end":{"line":56,"column":43}},"type":"binary-expr","locations":[{"start":{"line":56,"column":13},"end":{"line":56,"column":35}},{"start":{"line":56,"column":39},"end":{"line":56,"column":43}}]},"9":{"loc":{"start":{"line":57,"column":12},"end":{"line":57,"column":41}},"type":"binary-expr","locations":[{"start":{"line":57,"column":12},"end":{"line":57,"column":33}},{"start":{"line":57,"column":37},"end":{"line":57,"column":41}}]},"10":{"loc":{"start":{"line":59,"column":15},"end":{"line":59,"column":75}},"type":"cond-expr","locations":[{"start":{"line":59,"column":50},"end":{"line":59,"column":54}},{"start":{"line":59,"column":57},"end":{"line":59,"column":75}}]},"11":{"loc":{"start":{"line":62,"column":23},"end":{"line":62,"column":66}},"type":"binary-expr","locations":[{"start":{"line":62,"column":23},"end":{"line":62,"column":60}},{"start":{"line":62,"column":64},"end":{"line":62,"column":66}}]},"12":{"loc":{"start":{"line":66,"column":11},"end":{"line":66,"column":53}},"type":"binary-expr","locations":[{"start":{"line":66,"column":11},"end":{"line":66,"column":45}},{"start":{"line":66,"column":49},"end":{"line":66,"column":53}}]},"13":{"loc":{"start":{"line":68,"column":8},"end":{"line":81,"column":47}},"type":"cond-expr","locations":[{"start":{"line":69,"column":12},"end":{"line":79,"column":null}},{"start":{"line":81,"column":12},"end":{"line":81,"column":47}}]},"14":{"loc":{"start":{"line":71,"column":16},"end":{"line":73,"column":null}},"type":"if","locations":[{"start":{"line":71,"column":16},"end":{"line":73,"column":null}}]},"15":{"loc":{"start":{"line":74,"column":16},"end":{"line":76,"column":null}},"type":"if","locations":[{"start":{"line":74,"column":16},"end":{"line":76,"column":null}}]}},"s":{"0":4,"1":5,"2":0,"3":0,"4":0,"5":0,"6":0,"7":5,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":4},"f":{"0":5,"1":0,"2":0,"3":0,"4":0},"b":{"0":[0,0],"1":[0],"2":[0,0],"3":[5,0],"4":[5,5],"5":[5,5],"6":[5,5],"7":[5,5],"8":[5,5],"9":[5,5],"10":[5,0],"11":[5,5],"12":[5,5],"13":[5,0],"14":[0],"15":[0]}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/store/PathBuilder.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/store/PathBuilder.ts","statementMap":{"0":{"start":{"line":3,"column":18},"end":{"line":3,"column":37}},"1":{"start":{"line":21,"column":22},"end":{"line":21,"column":40}},"2":{"start":{"line":22,"column":31},"end":{"line":24,"column":1}},"3":{"start":{"line":23,"column":2},"end":{"line":23,"column":null}},"4":{"start":{"line":22,"column":13},"end":{"line":22,"column":31}},"5":{"start":{"line":26,"column":27},"end":{"line":38,"column":1}},"6":{"start":{"line":29,"column":2},"end":{"line":37,"column":null}},"7":{"start":{"line":31,"column":6},"end":{"line":34,"column":null}},"8":{"start":{"line":32,"column":8},"end":{"line":32,"column":null}},"9":{"start":{"line":32,"column":32},"end":{"line":32,"column":null}},"10":{"start":{"line":33,"column":8},"end":{"line":33,"column":null}},"11":{"start":{"line":35,"column":6},"end":{"line":35,"column":null}},"12":{"start":{"line":26,"column":13},"end":{"line":26,"column":27}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":22,"column":31},"end":{"line":22,"column":32}},"loc":{"start":{"line":22,"column":65},"end":{"line":24,"column":1}}},"1":{"name":"(anonymous_1)","decl":{"start":{"line":26,"column":27},"end":{"line":26,"column":null}},"loc":{"start":{"line":28,"column":35},"end":{"line":38,"column":1}}},"2":{"name":"(anonymous_2)","decl":{"start":{"line":30,"column":4},"end":{"line":30,"column":7}},"loc":{"start":{"line":30,"column":20},"end":{"line":36,"column":5}}}},"branchMap":{"0":{"loc":{"start":{"line":27,"column":2},"end":{"line":27,"column":22}},"type":"default-arg","locations":[{"start":{"line":27,"column":20},"end":{"line":27,"column":22}}]},"1":{"loc":{"start":{"line":31,"column":6},"end":{"line":34,"column":null}},"type":"if","locations":[{"start":{"line":31,"column":6},"end":{"line":34,"column":null}}]},"2":{"loc":{"start":{"line":32,"column":8},"end":{"line":32,"column":null}},"type":"if","locations":[{"start":{"line":32,"column":8},"end":{"line":32,"column":null}}]}},"s":{"0":5,"1":5,"2":5,"3":0,"4":5,"5":5,"6":6,"7":0,"8":0,"9":0,"10":0,"11":0,"12":5},"f":{"0":0,"1":6,"2":0},"b":{"0":[6],"1":[0],"2":[0]}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/store/getStore.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/store/getStore.ts","statementMap":{"0":{"start":{"line":2,"column":0},"end":{"line":2,"column":60}},"1":{"start":{"line":6,"column":13},"end":{"line":6,"column":29}},"2":{"start":{"line":7,"column":13},"end":{"line":7,"column":49}},"3":{"start":{"line":8,"column":13},"end":{"line":8,"column":null}},"4":{"start":{"line":18,"column":4},"end":{"line":22,"column":null}},"5":{"start":{"line":28,"column":4},"end":{"line":31,"column":null}},"6":{"start":{"line":38,"column":4},"end":{"line":49,"column":null}},"7":{"start":{"line":40,"column":26},"end":{"line":42,"column":8}},"8":{"start":{"line":41,"column":8},"end":{"line":41,"column":null}},"9":{"start":{"line":43,"column":6},"end":{"line":47,"column":null}},"10":{"start":{"line":46,"column":24},"end":{"line":46,"column":34}},"11":{"start":{"line":48,"column":6},"end":{"line":48,"column":null}},"12":{"start":{"line":4,"column":0},"end":{"line":4,"column":13}},"13":{"start":{"line":60,"column":2},"end":{"line":60,"column":null}},"14":{"start":{"line":52,"column":0},"end":{"line":52,"column":16}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":5,"column":2},"end":{"line":5,"column":null}},"loc":{"start":{"line":11,"column":10},"end":{"line":12,"column":6}}},"1":{"name":"(anonymous_1)","decl":{"start":{"line":17,"column":2},"end":{"line":17,"column":7}},"loc":{"start":{"line":17,"column":7},"end":{"line":23,"column":3}}},"2":{"name":"(anonymous_2)","decl":{"start":{"line":27,"column":2},"end":{"line":27,"column":6}},"loc":{"start":{"line":27,"column":6},"end":{"line":32,"column":3}}},"3":{"name":"(anonymous_3)","decl":{"start":{"line":37,"column":2},"end":{"line":37,"column":7}},"loc":{"start":{"line":37,"column":14},"end":{"line":50,"column":3}}},"4":{"name":"(anonymous_4)","decl":{"start":{"line":40,"column":44},"end":{"line":40,"column":45}},"loc":{"start":{"line":40,"column":56},"end":{"line":42,"column":7}}},"5":{"name":"(anonymous_5)","decl":{"start":{"line":46,"column":18},"end":{"line":46,"column":21}},"loc":{"start":{"line":46,"column":24},"end":{"line":46,"column":34}}},"6":{"name":"getStore","decl":{"start":{"line":52,"column":16},"end":{"line":52,"column":24}},"loc":{"start":{"line":58,"column":8},"end":{"line":61,"column":1}}}},"branchMap":{"0":{"loc":{"start":{"line":8,"column":13},"end":{"line":11,"column":10}},"type":"default-arg","locations":[{"start":{"line":11,"column":8},"end":{"line":11,"column":10}}]},"1":{"loc":{"start":{"line":55,"column":2},"end":{"line":58,"column":8}},"type":"default-arg","locations":[{"start":{"line":58,"column":6},"end":{"line":58,"column":8}}]}},"s":{"0":5,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":5,"13":0,"14":5},"f":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0},"b":{"0":[0],"1":[0]}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/test/output.sdk.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/test/output.sdk.ts","statementMap":{"0":{"start":{"line":1,"column":0},"end":{"line":1,"column":38}},"1":{"start":{"line":2,"column":0},"end":{"line":2,"column":57}},"2":{"start":{"line":3,"column":0},"end":{"line":3,"column":52}},"3":{"start":{"line":4,"column":0},"end":{"line":4,"column":54}},"4":{"start":{"line":7,"column":13},"end":{"line":56,"column":null}}},"fnMap":{},"branchMap":{},"s":{"0":4,"1":4,"2":4,"3":4,"4":4},"f":{},"b":{}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/test/output.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/test/output.ts","statementMap":{"0":{"start":{"line":2,"column":0},"end":{"line":2,"column":34}},"1":{"start":{"line":3,"column":40},"end":{"line":3,"column":43}},"2":{"start":{"line":5,"column":13},"end":{"line":375,"column":14}},"3":{"start":{"line":376,"column":13},"end":{"line":376,"column":52}}},"fnMap":{},"branchMap":{},"s":{"0":2,"1":2,"2":2,"3":2},"f":{},"b":{}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/trigger/changeOnFirstSuccess.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/trigger/changeOnFirstSuccess.ts","statementMap":{"0":{"start":{"line":7,"column":2},"end":{"line":31,"column":null}},"1":{"start":{"line":8,"column":23},"end":{"line":8,"column":33}},"2":{"start":{"line":9,"column":4},"end":{"line":12,"column":null}},"3":{"start":{"line":10,"column":6},"end":{"line":10,"column":null}},"4":{"start":{"line":11,"column":6},"end":{"line":11,"column":null}},"5":{"start":{"line":13,"column":31},"end":{"line":13,"column":61}},"6":{"start":{"line":14,"column":4},"end":{"line":21,"column":null}},"7":{"start":{"line":15,"column":16},"end":{"line":15,"column":47}},"8":{"start":{"line":19,"column":6},"end":{"line":19,"column":null}},"9":{"start":{"line":20,"column":6},"end":{"line":20,"column":null}},"10":{"start":{"line":22,"column":30},"end":{"line":22,"column":59}},"11":{"start":{"line":23,"column":4},"end":{"line":30,"column":null}},"12":{"start":{"line":24,"column":16},"end":{"line":24,"column":46}},"13":{"start":{"line":28,"column":6},"end":{"line":28,"column":null}},"14":{"start":{"line":29,"column":6},"end":{"line":29,"column":null}},"15":{"start":{"line":3,"column":0},"end":{"line":3,"column":16}}},"fnMap":{"0":{"name":"changeOnFirstSuccess","decl":{"start":{"line":3,"column":16},"end":{"line":3,"column":36}},"loc":{"start":{"line":6,"column":1},"end":{"line":32,"column":1}}},"1":{"name":"(anonymous_1)","decl":{"start":{"line":7,"column":9},"end":{"line":7,"column":14}},"loc":{"start":{"line":7,"column":34},"end":{"line":31,"column":3}}}},"branchMap":{"0":{"loc":{"start":{"line":16,"column":6},"end":{"line":16,"column":57}},"type":"binary-expr","locations":[{"start":{"line":16,"column":6},"end":{"line":16,"column":44}},{"start":{"line":16,"column":48},"end":{"line":16,"column":57}}]}},"s":{"0":5,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":5},"f":{"0":5,"1":0},"b":{"0":[0,0]}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/trigger/cooldownTrigger.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/trigger/cooldownTrigger.ts","statementMap":{"0":{"start":{"line":2,"column":2},"end":{"line":7,"column":null}},"1":{"start":{"line":3,"column":4},"end":{"line":6,"column":null}},"2":{"start":{"line":4,"column":6},"end":{"line":4,"column":null}},"3":{"start":{"line":4,"column":37},"end":{"line":4,"column":64}},"4":{"start":{"line":5,"column":6},"end":{"line":5,"column":null}},"5":{"start":{"line":1,"column":0},"end":{"line":1,"column":16}}},"fnMap":{"0":{"name":"cooldownTrigger","decl":{"start":{"line":1,"column":16},"end":{"line":1,"column":31}},"loc":{"start":{"line":1,"column":46},"end":{"line":8,"column":1}}},"1":{"name":"(anonymous_1)","decl":{"start":{"line":2,"column":9},"end":{"line":2,"column":14}},"loc":{"start":{"line":2,"column":24},"end":{"line":7,"column":3}}},"2":{"name":"(anonymous_2)","decl":{"start":{"line":4,"column":24},"end":{"line":4,"column":25}},"loc":{"start":{"line":4,"column":37},"end":{"line":4,"column":64}}}},"branchMap":{},"s":{"0":10,"1":0,"2":0,"3":0,"4":0,"5":5},"f":{"0":10,"1":0,"2":0},"b":{}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/trigger/defaultTrigger.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/trigger/defaultTrigger.ts","statementMap":{"0":{"start":{"line":1,"column":0},"end":{"line":1,"column":51}},"1":{"start":{"line":2,"column":0},"end":{"line":2,"column":61}},"2":{"start":{"line":5,"column":13},"end":{"line":8,"column":null}}},"fnMap":{},"branchMap":{},"s":{"0":5,"1":5,"2":5},"f":{},"b":{}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/trigger/index.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/trigger/index.ts","statementMap":{"0":{"start":{"line":3,"column":0},"end":{"line":3,"column":9}},"1":{"start":{"line":3,"column":9},"end":{"line":3,"column":61}},"2":{"start":{"line":4,"column":0},"end":{"line":4,"column":9}},"3":{"start":{"line":4,"column":9},"end":{"line":4,"column":51}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":3,"column":9},"end":{"line":3,"column":29}},"loc":{"start":{"line":3,"column":9},"end":{"line":3,"column":61}}},"1":{"name":"(anonymous_1)","decl":{"start":{"line":4,"column":9},"end":{"line":4,"column":24}},"loc":{"start":{"line":4,"column":9},"end":{"line":4,"column":51}}}},"branchMap":{},"s":{"0":5,"1":11,"2":5,"3":11},"f":{"0":6,"1":6},"b":{}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/trigger/lastStatus.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/trigger/lastStatus.ts","statementMap":{"0":{"start":{"line":9,"column":2},"end":{"line":32,"column":null}},"1":{"start":{"line":10,"column":18},"end":{"line":10,"column":37}},"2":{"start":{"line":13,"column":62},"end":{"line":15,"column":null}},"3":{"start":{"line":16,"column":4},"end":{"line":31,"column":null}},"4":{"start":{"line":17,"column":25},"end":{"line":17,"column":35}},"5":{"start":{"line":18,"column":55},"end":{"line":18,"column":78}},"6":{"start":{"line":19,"column":6},"end":{"line":22,"column":null}},"7":{"start":{"line":20,"column":8},"end":{"line":20,"column":null}},"8":{"start":{"line":21,"column":8},"end":{"line":21,"column":16}},"9":{"start":{"line":23,"column":6},"end":{"line":25,"column":null}},"10":{"start":{"line":24,"column":8},"end":{"line":24,"column":null}},"11":{"start":{"line":26,"column":6},"end":{"line":28,"column":null}},"12":{"start":{"line":27,"column":8},"end":{"line":27,"column":null}},"13":{"start":{"line":29,"column":6},"end":{"line":29,"column":null}},"14":{"start":{"line":30,"column":6},"end":{"line":30,"column":null}},"15":{"start":{"line":8,"column":0},"end":{"line":8,"column":16}}},"fnMap":{"0":{"name":"lastStatus","decl":{"start":{"line":8,"column":16},"end":{"line":8,"column":26}},"loc":{"start":{"line":8,"column":53},"end":{"line":33,"column":1}}},"1":{"name":"(anonymous_1)","decl":{"start":{"line":9,"column":9},"end":{"line":9,"column":14}},"loc":{"start":{"line":9,"column":34},"end":{"line":32,"column":3}}}},"branchMap":{"0":{"loc":{"start":{"line":19,"column":6},"end":{"line":22,"column":null}},"type":"if","locations":[{"start":{"line":19,"column":6},"end":{"line":22,"column":null}}]},"1":{"loc":{"start":{"line":23,"column":6},"end":{"line":25,"column":null}},"type":"if","locations":[{"start":{"line":23,"column":6},"end":{"line":25,"column":null}}]},"2":{"loc":{"start":{"line":26,"column":6},"end":{"line":28,"column":null}},"type":"if","locations":[{"start":{"line":26,"column":6},"end":{"line":28,"column":null}}]}},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":5},"f":{"0":0,"1":0},"b":{"0":[0],"1":[0],"2":[0]}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/trigger/successFailure.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/trigger/successFailure.ts","statementMap":{"0":{"start":{"line":2,"column":0},"end":{"line":2,"column":41}},"1":{"start":{"line":4,"column":30},"end":{"line":7,"column":70}},"2":{"start":{"line":7,"column":6},"end":{"line":7,"column":70}},"3":{"start":{"line":4,"column":13},"end":{"line":4,"column":30}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":4,"column":30},"end":{"line":4,"column":31}},"loc":{"start":{"line":7,"column":6},"end":{"line":7,"column":70}}}},"branchMap":{},"s":{"0":5,"1":5,"2":0,"3":5},"f":{"0":0},"b":{}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/util/GetSslCertificate.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/util/GetSslCertificate.ts","statementMap":{"0":{"start":{"line":6,"column":13},"end":{"line":6,"column":29}},"1":{"start":{"line":7,"column":13},"end":{"line":7,"column":32}},"2":{"start":{"line":8,"column":13},"end":{"line":8,"column":36}},"3":{"start":{"line":15,"column":4},"end":{"line":19,"column":null}},"4":{"start":{"line":25,"column":4},"end":{"line":28,"column":null}},"5":{"start":{"line":34,"column":4},"end":{"line":45,"column":null}},"6":{"start":{"line":36,"column":26},"end":{"line":38,"column":8}},"7":{"start":{"line":37,"column":8},"end":{"line":37,"column":null}},"8":{"start":{"line":39,"column":6},"end":{"line":43,"column":null}},"9":{"start":{"line":42,"column":24},"end":{"line":42,"column":34}},"10":{"start":{"line":44,"column":6},"end":{"line":44,"column":null}},"11":{"start":{"line":4,"column":0},"end":{"line":4,"column":13}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":5,"column":2},"end":{"line":5,"column":null}},"loc":{"start":{"line":8,"column":36},"end":{"line":9,"column":6}}},"1":{"name":"(anonymous_1)","decl":{"start":{"line":14,"column":2},"end":{"line":14,"column":7}},"loc":{"start":{"line":14,"column":7},"end":{"line":20,"column":3}}},"2":{"name":"(anonymous_2)","decl":{"start":{"line":24,"column":2},"end":{"line":24,"column":6}},"loc":{"start":{"line":24,"column":6},"end":{"line":29,"column":3}}},"3":{"name":"(anonymous_3)","decl":{"start":{"line":33,"column":2},"end":{"line":33,"column":7}},"loc":{"start":{"line":33,"column":14},"end":{"line":46,"column":3}}},"4":{"name":"(anonymous_4)","decl":{"start":{"line":36,"column":44},"end":{"line":36,"column":45}},"loc":{"start":{"line":36,"column":56},"end":{"line":38,"column":7}}},"5":{"name":"(anonymous_5)","decl":{"start":{"line":42,"column":18},"end":{"line":42,"column":21}},"loc":{"start":{"line":42,"column":24},"end":{"line":42,"column":34}}}},"branchMap":{},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":5},"f":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0},"b":{}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/util/GetSystemSmtp.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/util/GetSystemSmtp.ts","statementMap":{"0":{"start":{"line":4,"column":23},"end":{"line":4,"column":39}},"1":{"start":{"line":10,"column":4},"end":{"line":12,"column":null}},"2":{"start":{"line":18,"column":4},"end":{"line":18,"column":null}},"3":{"start":{"line":24,"column":4},"end":{"line":33,"column":null}},"4":{"start":{"line":26,"column":26},"end":{"line":28,"column":8}},"5":{"start":{"line":27,"column":8},"end":{"line":27,"column":null}},"6":{"start":{"line":29,"column":6},"end":{"line":31,"column":null}},"7":{"start":{"line":30,"column":24},"end":{"line":30,"column":34}},"8":{"start":{"line":32,"column":6},"end":{"line":32,"column":null}},"9":{"start":{"line":3,"column":0},"end":{"line":3,"column":13}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":4,"column":2},"end":{"line":4,"column":23}},"loc":{"start":{"line":4,"column":39},"end":{"line":4,"column":43}}},"1":{"name":"(anonymous_1)","decl":{"start":{"line":9,"column":2},"end":{"line":9,"column":7}},"loc":{"start":{"line":9,"column":7},"end":{"line":13,"column":3}}},"2":{"name":"(anonymous_2)","decl":{"start":{"line":17,"column":2},"end":{"line":17,"column":6}},"loc":{"start":{"line":17,"column":6},"end":{"line":19,"column":3}}},"3":{"name":"(anonymous_3)","decl":{"start":{"line":23,"column":2},"end":{"line":23,"column":7}},"loc":{"start":{"line":23,"column":14},"end":{"line":34,"column":3}}},"4":{"name":"(anonymous_4)","decl":{"start":{"line":26,"column":44},"end":{"line":26,"column":45}},"loc":{"start":{"line":26,"column":56},"end":{"line":28,"column":7}}},"5":{"name":"(anonymous_5)","decl":{"start":{"line":30,"column":18},"end":{"line":30,"column":21}},"loc":{"start":{"line":30,"column":24},"end":{"line":30,"column":34}}}},"branchMap":{},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":5},"f":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0},"b":{}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/util/Hostname.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/util/Hostname.ts","statementMap":{"0":{"start":{"line":4,"column":2},"end":{"line":6,"column":null}},"1":{"start":{"line":5,"column":4},"end":{"line":5,"column":null}},"2":{"start":{"line":7,"column":2},"end":{"line":9,"column":null}},"3":{"start":{"line":8,"column":4},"end":{"line":8,"column":null}},"4":{"start":{"line":10,"column":19},"end":{"line":10,"column":36}},"5":{"start":{"line":11,"column":2},"end":{"line":13,"column":null}},"6":{"start":{"line":12,"column":4},"end":{"line":12,"column":null}},"7":{"start":{"line":14,"column":15},"end":{"line":14,"column":48}},"8":{"start":{"line":15,"column":21},"end":{"line":15,"column":43}},"9":{"start":{"line":16,"column":2},"end":{"line":18,"column":null}},"10":{"start":{"line":17,"column":4},"end":{"line":17,"column":null}},"11":{"start":{"line":19,"column":2},"end":{"line":21,"column":null}},"12":{"start":{"line":20,"column":4},"end":{"line":20,"column":null}},"13":{"start":{"line":22,"column":2},"end":{"line":24,"column":null}},"14":{"start":{"line":3,"column":0},"end":{"line":3,"column":16}}},"fnMap":{"0":{"name":"hostnameInfoToAddress","decl":{"start":{"line":3,"column":16},"end":{"line":3,"column":37}},"loc":{"start":{"line":3,"column":60},"end":{"line":25,"column":1}}}},"branchMap":{"0":{"loc":{"start":{"line":4,"column":2},"end":{"line":6,"column":null}},"type":"if","locations":[{"start":{"line":4,"column":2},"end":{"line":6,"column":null}}]},"1":{"loc":{"start":{"line":7,"column":2},"end":{"line":9,"column":null}},"type":"if","locations":[{"start":{"line":7,"column":2},"end":{"line":9,"column":null}}]},"2":{"loc":{"start":{"line":11,"column":2},"end":{"line":13,"column":null}},"type":"if","locations":[{"start":{"line":11,"column":2},"end":{"line":13,"column":null}}]},"3":{"loc":{"start":{"line":12,"column":14},"end":{"line":12,"column":64}},"type":"cond-expr","locations":[{"start":{"line":12,"column":35},"end":{"line":12,"column":59}},{"start":{"line":12,"column":62},"end":{"line":12,"column":64}}]},"4":{"loc":{"start":{"line":14,"column":15},"end":{"line":14,"column":48}},"type":"binary-expr","locations":[{"start":{"line":14,"column":15},"end":{"line":14,"column":31}},{"start":{"line":14,"column":35},"end":{"line":14,"column":48}}]},"5":{"loc":{"start":{"line":15,"column":21},"end":{"line":15,"column":43}},"type":"cond-expr","locations":[{"start":{"line":15,"column":28},"end":{"line":15,"column":38}},{"start":{"line":15,"column":41},"end":{"line":15,"column":43}}]},"6":{"loc":{"start":{"line":16,"column":2},"end":{"line":18,"column":null}},"type":"if","locations":[{"start":{"line":16,"column":2},"end":{"line":18,"column":null}}]},"7":{"loc":{"start":{"line":16,"column":6},"end":{"line":16,"column":58}},"type":"binary-expr","locations":[{"start":{"line":16,"column":6},"end":{"line":16,"column":30}},{"start":{"line":16,"column":34},"end":{"line":16,"column":58}}]},"8":{"loc":{"start":{"line":19,"column":2},"end":{"line":21,"column":null}},"type":"if","locations":[{"start":{"line":19,"column":2},"end":{"line":21,"column":null}}]}},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":5},"f":{"0":0},"b":{"0":[0],"1":[0],"2":[0],"3":[0,0],"4":[0,0],"5":[0,0],"6":[0],"7":[0,0],"8":[0]}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/util/SubContainer.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/util/SubContainer.ts","statementMap":{"0":{"start":{"line":1,"column":0},"end":{"line":1,"column":33}},"1":{"start":{"line":3,"column":0},"end":{"line":3,"column":35}},"2":{"start":{"line":4,"column":0},"end":{"line":4,"column":32}},"3":{"start":{"line":5,"column":0},"end":{"line":5,"column":36}},"4":{"start":{"line":6,"column":0},"end":{"line":6,"column":29}},"5":{"start":{"line":7,"column":13},"end":{"line":7,"column":null}},"6":{"start":{"line":8,"column":16},"end":{"line":8,"column":72}},"7":{"start":{"line":8,"column":37},"end":{"line":8,"column":72}},"8":{"start":{"line":9,"column":14},"end":{"line":9,"column":25}},"9":{"start":{"line":9,"column":20},"end":{"line":9,"column":25}},"10":{"start":{"line":21,"column":31},"end":{"line":21,"column":34}},"11":{"start":{"line":49,"column":34},"end":{"line":49,"column":39}},"12":{"start":{"line":52,"column":13},"end":{"line":52,"column":31}},"13":{"start":{"line":53,"column":13},"end":{"line":53,"column":31}},"14":{"start":{"line":54,"column":13},"end":{"line":54,"column":27}},"15":{"start":{"line":55,"column":13},"end":{"line":55,"column":25}},"16":{"start":{"line":57,"column":4},"end":{"line":57,"column":null}},"17":{"start":{"line":58,"column":4},"end":{"line":61,"column":null}},"18":{"start":{"line":62,"column":4},"end":{"line":64,"column":null}},"19":{"start":{"line":63,"column":6},"end":{"line":63,"column":null}},"20":{"start":{"line":65,"column":4},"end":{"line":84,"column":null}},"21":{"start":{"line":67,"column":8},"end":{"line":83,"column":10}},"22":{"start":{"line":68,"column":22},"end":{"line":68,"column":23}},"23":{"start":{"line":69,"column":10},"end":{"line":81,"column":null}},"24":{"start":{"line":70,"column":65},"end":{"line":70,"column":68}},"25":{"start":{"line":72,"column":12},"end":{"line":79,"column":null}},"26":{"start":{"line":73,"column":14},"end":{"line":77,"column":null}},"27":{"start":{"line":78,"column":14},"end":{"line":78,"column":null}},"28":{"start":{"line":80,"column":12},"end":{"line":80,"column":null}},"29":{"start":{"line":82,"column":10},"end":{"line":82,"column":null}},"30":{"start":{"line":90,"column":30},"end":{"line":90,"column":35}},"31":{"start":{"line":91,"column":27},"end":{"line":93,"column":6}},"32":{"start":{"line":95,"column":19},"end":{"line":95,"column":33}},"33":{"start":{"line":96,"column":4},"end":{"line":98,"column":null}},"34":{"start":{"line":97,"column":6},"end":{"line":97,"column":null}},"35":{"start":{"line":100,"column":4},"end":{"line":100,"column":null}},"36":{"start":{"line":102,"column":4},"end":{"line":108,"column":null}},"37":{"start":{"line":103,"column":19},"end":{"line":103,"column":32}},"38":{"start":{"line":104,"column":17},"end":{"line":104,"column":39}},"39":{"start":{"line":105,"column":6},"end":{"line":105,"column":null}},"40":{"start":{"line":106,"column":6},"end":{"line":106,"column":null}},"41":{"start":{"line":107,"column":6},"end":{"line":107,"column":null}},"42":{"start":{"line":110,"column":4},"end":{"line":110,"column":null}},"43":{"start":{"line":119,"column":25},"end":{"line":119,"column":62}},"44":{"start":{"line":120,"column":4},"end":{"line":127,"column":null}},"45":{"start":{"line":121,"column":6},"end":{"line":123,"column":null}},"46":{"start":{"line":122,"column":8},"end":{"line":122,"column":null}},"47":{"start":{"line":124,"column":6},"end":{"line":124,"column":null}},"48":{"start":{"line":126,"column":6},"end":{"line":126,"column":null}},"49":{"start":{"line":131,"column":4},"end":{"line":133,"column":null}},"50":{"start":{"line":134,"column":4},"end":{"line":171,"column":null}},"51":{"start":{"line":135,"column":22},"end":{"line":139,"column":13}},"52":{"start":{"line":140,"column":19},"end":{"line":140,"column":67}},"53":{"start":{"line":142,"column":6},"end":{"line":142,"column":null}},"54":{"start":{"line":143,"column":6},"end":{"line":143,"column":null}},"55":{"start":{"line":144,"column":6},"end":{"line":144,"column":null}},"56":{"start":{"line":145,"column":11},"end":{"line":171,"column":null}},"57":{"start":{"line":146,"column":22},"end":{"line":150,"column":13}},"58":{"start":{"line":151,"column":19},"end":{"line":151,"column":66}},"59":{"start":{"line":153,"column":6},"end":{"line":153,"column":null}},"60":{"start":{"line":154,"column":6},"end":{"line":154,"column":null}},"61":{"start":{"line":155,"column":6},"end":{"line":155,"column":null}},"62":{"start":{"line":156,"column":11},"end":{"line":171,"column":null}},"63":{"start":{"line":157,"column":6},"end":{"line":157,"column":null}},"64":{"start":{"line":158,"column":11},"end":{"line":171,"column":null}},"65":{"start":{"line":159,"column":22},"end":{"line":163,"column":13}},"66":{"start":{"line":164,"column":19},"end":{"line":164,"column":52}},"67":{"start":{"line":166,"column":6},"end":{"line":166,"column":null}},"68":{"start":{"line":167,"column":6},"end":{"line":167,"column":null}},"69":{"start":{"line":168,"column":6},"end":{"line":168,"column":null}},"70":{"start":{"line":170,"column":6},"end":{"line":170,"column":null}},"71":{"start":{"line":172,"column":4},"end":{"line":172,"column":null}},"72":{"start":{"line":176,"column":4},"end":{"line":178,"column":null}},"73":{"start":{"line":177,"column":6},"end":{"line":177,"column":12}},"74":{"start":{"line":179,"column":4},"end":{"line":190,"column":null}},"75":{"start":{"line":180,"column":6},"end":{"line":189,"column":null}},"76":{"start":{"line":181,"column":8},"end":{"line":183,"column":null}},"77":{"start":{"line":182,"column":10},"end":{"line":182,"column":null}},"78":{"start":{"line":184,"column":8},"end":{"line":186,"column":null}},"79":{"start":{"line":185,"column":10},"end":{"line":185,"column":null}},"80":{"start":{"line":188,"column":8},"end":{"line":188,"column":null}},"81":{"start":{"line":194,"column":4},"end":{"line":198,"column":null}},"82":{"start":{"line":195,"column":19},"end":{"line":195,"column":28}},"83":{"start":{"line":196,"column":6},"end":{"line":196,"column":null}},"84":{"start":{"line":197,"column":6},"end":{"line":197,"column":null}},"85":{"start":{"line":211,"column":4},"end":{"line":211,"column":null}},"86":{"start":{"line":212,"column":39},"end":{"line":217,"column":23}},"87":{"start":{"line":216,"column":19},"end":{"line":216,"column":23}},"88":{"start":{"line":218,"column":26},"end":{"line":218,"column":28}},"89":{"start":{"line":219,"column":4},"end":{"line":222,"column":null}},"90":{"start":{"line":220,"column":6},"end":{"line":220,"column":null}},"91":{"start":{"line":221,"column":6},"end":{"line":221,"column":null}},"92":{"start":{"line":223,"column":18},"end":{"line":223,"column":42}},"93":{"start":{"line":224,"column":4},"end":{"line":227,"column":null}},"94":{"start":{"line":225,"column":6},"end":{"line":225,"column":null}},"95":{"start":{"line":226,"column":6},"end":{"line":226,"column":null}},"96":{"start":{"line":228,"column":18},"end":{"line":239,"column":null}},"97":{"start":{"line":241,"column":4},"end":{"line":252,"column":null}},"98":{"start":{"line":242,"column":6},"end":{"line":250,"column":null}},"99":{"start":{"line":243,"column":8},"end":{"line":249,"column":10}},"100":{"start":{"line":244,"column":10},"end":{"line":248,"column":null}},"101":{"start":{"line":245,"column":12},"end":{"line":245,"column":null}},"102":{"start":{"line":247,"column":12},"end":{"line":247,"column":null}},"103":{"start":{"line":251,"column":6},"end":{"line":251,"column":null}},"104":{"start":{"line":251,"column":43},"end":{"line":251,"column":67}},"105":{"start":{"line":253,"column":16},"end":{"line":253,"column":25}},"106":{"start":{"line":254,"column":19},"end":{"line":254,"column":50}},"107":{"start":{"line":255,"column":19},"end":{"line":255,"column":50}},"108":{"start":{"line":257,"column":6},"end":{"line":269,"column":7}},"109":{"start":{"line":258,"column":6},"end":{"line":269,"column":7}},"110":{"start":{"line":259,"column":8},"end":{"line":268,"column":null}},"111":{"start":{"line":260,"column":10},"end":{"line":260,"column":null}},"112":{"start":{"line":261,"column":15},"end":{"line":268,"column":null}},"113":{"start":{"line":262,"column":10},"end":{"line":265,"column":null}},"114":{"start":{"line":267,"column":10},"end":{"line":267,"column":null}},"115":{"start":{"line":270,"column":4},"end":{"line":287,"column":null}},"116":{"start":{"line":271,"column":6},"end":{"line":271,"column":null}},"117":{"start":{"line":273,"column":6},"end":{"line":275,"column":null}},"118":{"start":{"line":274,"column":8},"end":{"line":274,"column":null}},"119":{"start":{"line":274,"column":39},"end":{"line":274,"column":60}},"120":{"start":{"line":276,"column":6},"end":{"line":276,"column":null}},"121":{"start":{"line":277,"column":6},"end":{"line":277,"column":null}},"122":{"start":{"line":278,"column":6},"end":{"line":286,"column":null}},"123":{"start":{"line":279,"column":8},"end":{"line":279,"column":null}},"124":{"start":{"line":280,"column":8},"end":{"line":285,"column":null}},"125":{"start":{"line":294,"column":4},"end":{"line":294,"column":null}},"126":{"start":{"line":295,"column":27},"end":{"line":300,"column":23}},"127":{"start":{"line":299,"column":19},"end":{"line":299,"column":23}},"128":{"start":{"line":301,"column":26},"end":{"line":301,"column":28}},"129":{"start":{"line":302,"column":4},"end":{"line":305,"column":null}},"130":{"start":{"line":303,"column":6},"end":{"line":303,"column":null}},"131":{"start":{"line":304,"column":6},"end":{"line":304,"column":null}},"132":{"start":{"line":306,"column":18},"end":{"line":306,"column":42}},"133":{"start":{"line":307,"column":4},"end":{"line":310,"column":null}},"134":{"start":{"line":308,"column":6},"end":{"line":308,"column":null}},"135":{"start":{"line":309,"column":6},"end":{"line":309,"column":null}},"136":{"start":{"line":311,"column":4},"end":{"line":311,"column":null}},"137":{"start":{"line":312,"column":4},"end":{"line":312,"column":null}},"138":{"start":{"line":313,"column":4},"end":{"line":325,"column":null}},"139":{"start":{"line":326,"column":4},"end":{"line":328,"column":null}},"140":{"start":{"line":327,"column":6},"end":{"line":327,"column":null}},"141":{"start":{"line":329,"column":4},"end":{"line":329,"column":null}},"142":{"start":{"line":336,"column":4},"end":{"line":336,"column":null}},"143":{"start":{"line":337,"column":27},"end":{"line":342,"column":23}},"144":{"start":{"line":341,"column":19},"end":{"line":341,"column":23}},"145":{"start":{"line":343,"column":26},"end":{"line":343,"column":28}},"146":{"start":{"line":344,"column":4},"end":{"line":347,"column":null}},"147":{"start":{"line":345,"column":6},"end":{"line":345,"column":null}},"148":{"start":{"line":346,"column":6},"end":{"line":346,"column":null}},"149":{"start":{"line":348,"column":18},"end":{"line":348,"column":42}},"150":{"start":{"line":349,"column":4},"end":{"line":352,"column":null}},"151":{"start":{"line":350,"column":6},"end":{"line":350,"column":null}},"152":{"start":{"line":351,"column":6},"end":{"line":351,"column":null}},"153":{"start":{"line":353,"column":4},"end":{"line":365,"column":null}},"154":{"start":{"line":47,"column":0},"end":{"line":47,"column":13}},"155":{"start":{"line":375,"column":22},"end":{"line":375,"column":49}},"156":{"start":{"line":377,"column":4},"end":{"line":377,"column":null}},"157":{"start":{"line":385,"column":4},"end":{"line":385,"column":null}},"158":{"start":{"line":391,"column":4},"end":{"line":391,"column":null}},"159":{"start":{"line":374,"column":0},"end":{"line":374,"column":13}},"160":{"start":{"line":433,"column":2},"end":{"line":433,"column":null}},"161":{"start":{"line":433,"column":34},"end":{"line":433,"column":59}}},"fnMap":{"0":{"name":"(anonymous_6)","decl":{"start":{"line":8,"column":16},"end":{"line":8,"column":17}},"loc":{"start":{"line":8,"column":37},"end":{"line":8,"column":72}}},"1":{"name":"(anonymous_7)","decl":{"start":{"line":9,"column":14},"end":{"line":9,"column":17}},"loc":{"start":{"line":9,"column":20},"end":{"line":9,"column":25}}},"2":{"name":"(anonymous_8)","decl":{"start":{"line":51,"column":2},"end":{"line":51,"column":null}},"loc":{"start":{"line":55,"column":25},"end":{"line":85,"column":3}}},"3":{"name":"(anonymous_9)","decl":{"start":{"line":62,"column":27},"end":{"line":62,"column":30}},"loc":{"start":{"line":62,"column":32},"end":{"line":64,"column":5}}},"4":{"name":"(anonymous_10)","decl":{"start":{"line":66,"column":6},"end":{"line":66,"column":9}},"loc":{"start":{"line":67,"column":8},"end":{"line":83,"column":10}}},"5":{"name":"(anonymous_11)","decl":{"start":{"line":67,"column":20},"end":{"line":67,"column":25}},"loc":{"start":{"line":67,"column":46},"end":{"line":83,"column":9}}},"6":{"name":"(anonymous_12)","decl":{"start":{"line":70,"column":58},"end":{"line":70,"column":59}},"loc":{"start":{"line":70,"column":65},"end":{"line":70,"column":68}}},"7":{"name":"(anonymous_13)","decl":{"start":{"line":86,"column":2},"end":{"line":86,"column":8}},"loc":{"start":{"line":88,"column":49},"end":{"line":111,"column":3}}},"8":{"name":"(anonymous_14)","decl":{"start":{"line":113,"column":2},"end":{"line":113,"column":8}},"loc":{"start":{"line":117,"column":50},"end":{"line":128,"column":3}}},"9":{"name":"(anonymous_15)","decl":{"start":{"line":130,"column":2},"end":{"line":130,"column":7}},"loc":{"start":{"line":130,"column":49},"end":{"line":173,"column":3}}},"10":{"name":"(anonymous_16)","decl":{"start":{"line":175,"column":10},"end":{"line":175,"column":15}},"loc":{"start":{"line":175,"column":26},"end":{"line":191,"column":3}}},"11":{"name":"(anonymous_17)","decl":{"start":{"line":179,"column":29},"end":{"line":179,"column":30}},"loc":{"start":{"line":179,"column":49},"end":{"line":190,"column":5}}},"12":{"name":"(anonymous_18)","decl":{"start":{"line":181,"column":31},"end":{"line":181,"column":34}},"loc":{"start":{"line":181,"column":36},"end":{"line":183,"column":9}}},"13":{"name":"(anonymous_19)","decl":{"start":{"line":193,"column":2},"end":{"line":193,"column":6}},"loc":{"start":{"line":193,"column":13},"end":{"line":199,"column":3}}},"14":{"name":"(anonymous_20)","decl":{"start":{"line":194,"column":11},"end":{"line":194,"column":16}},"loc":{"start":{"line":194,"column":22},"end":{"line":198,"column":5}}},"15":{"name":"(anonymous_21)","decl":{"start":{"line":201,"column":2},"end":{"line":201,"column":7}},"loc":{"start":{"line":204,"column":36},"end":{"line":288,"column":3}}},"16":{"name":"(anonymous_22)","decl":{"start":{"line":216,"column":13},"end":{"line":216,"column":16}},"loc":{"start":{"line":216,"column":19},"end":{"line":216,"column":23}}},"17":{"name":"(anonymous_23)","decl":{"start":{"line":242,"column":30},"end":{"line":242,"column":31}},"loc":{"start":{"line":243,"column":8},"end":{"line":249,"column":10}}},"18":{"name":"(anonymous_24)","decl":{"start":{"line":243,"column":41},"end":{"line":243,"column":42}},"loc":{"start":{"line":243,"column":47},"end":{"line":249,"column":9}}},"19":{"name":"(anonymous_25)","decl":{"start":{"line":251,"column":30},"end":{"line":251,"column":31}},"loc":{"start":{"line":251,"column":43},"end":{"line":251,"column":67}}},"20":{"name":"(anonymous_26)","decl":{"start":{"line":257,"column":6},"end":{"line":257,"column":7}},"loc":{"start":{"line":258,"column":6},"end":{"line":269,"column":7}}},"21":{"name":"(anonymous_27)","decl":{"start":{"line":258,"column":6},"end":{"line":258,"column":7}},"loc":{"start":{"line":258,"column":39},"end":{"line":269,"column":7}}},"22":{"name":"(anonymous_28)","decl":{"start":{"line":270,"column":23},"end":{"line":270,"column":24}},"loc":{"start":{"line":270,"column":43},"end":{"line":287,"column":5}}},"23":{"name":"(anonymous_29)","decl":{"start":{"line":274,"column":33},"end":{"line":274,"column":36}},"loc":{"start":{"line":274,"column":39},"end":{"line":274,"column":60}}},"24":{"name":"(anonymous_30)","decl":{"start":{"line":278,"column":23},"end":{"line":278,"column":24}},"loc":{"start":{"line":278,"column":40},"end":{"line":286,"column":7}}},"25":{"name":"(anonymous_31)","decl":{"start":{"line":290,"column":2},"end":{"line":290,"column":7}},"loc":{"start":{"line":292,"column":28},"end":{"line":330,"column":3}}},"26":{"name":"(anonymous_32)","decl":{"start":{"line":299,"column":13},"end":{"line":299,"column":16}},"loc":{"start":{"line":299,"column":19},"end":{"line":299,"column":23}}},"27":{"name":"(anonymous_33)","decl":{"start":{"line":326,"column":27},"end":{"line":326,"column":30}},"loc":{"start":{"line":326,"column":32},"end":{"line":328,"column":5}}},"28":{"name":"(anonymous_34)","decl":{"start":{"line":332,"column":2},"end":{"line":332,"column":7}},"loc":{"start":{"line":334,"column":28},"end":{"line":366,"column":3}}},"29":{"name":"(anonymous_35)","decl":{"start":{"line":341,"column":13},"end":{"line":341,"column":16}},"loc":{"start":{"line":341,"column":19},"end":{"line":341,"column":23}}},"30":{"name":"(anonymous_36)","decl":{"start":{"line":375,"column":2},"end":{"line":375,"column":22}},"loc":{"start":{"line":375,"column":49},"end":{"line":375,"column":53}}},"31":{"name":"(anonymous_37)","decl":{"start":{"line":376,"column":2},"end":{"line":376,"column":6}},"loc":{"start":{"line":376,"column":13},"end":{"line":378,"column":3}}},"32":{"name":"(anonymous_38)","decl":{"start":{"line":380,"column":2},"end":{"line":380,"column":6}},"loc":{"start":{"line":383,"column":29},"end":{"line":386,"column":3}}},"33":{"name":"(anonymous_39)","decl":{"start":{"line":387,"column":2},"end":{"line":387,"column":7}},"loc":{"start":{"line":389,"column":28},"end":{"line":392,"column":3}}},"34":{"name":"wait","decl":{"start":{"line":432,"column":9},"end":{"line":432,"column":13}},"loc":{"start":{"line":432,"column":26},"end":{"line":434,"column":1}}},"35":{"name":"(anonymous_41)","decl":{"start":{"line":433,"column":21},"end":{"line":433,"column":22}},"loc":{"start":{"line":433,"column":34},"end":{"line":433,"column":59}}}},"branchMap":{"0":{"loc":{"start":{"line":72,"column":12},"end":{"line":79,"column":null}},"type":"if","locations":[{"start":{"line":72,"column":12},"end":{"line":79,"column":null}}]},"1":{"loc":{"start":{"line":96,"column":4},"end":{"line":98,"column":null}},"type":"if","locations":[{"start":{"line":96,"column":4},"end":{"line":98,"column":null}}]},"2":{"loc":{"start":{"line":131,"column":11},"end":{"line":133,"column":32}},"type":"cond-expr","locations":[{"start":{"line":132,"column":8},"end":{"line":132,"column":31}},{"start":{"line":133,"column":8},"end":{"line":133,"column":32}}]},"3":{"loc":{"start":{"line":134,"column":4},"end":{"line":171,"column":null}},"type":"if","locations":[{"start":{"line":134,"column":4},"end":{"line":171,"column":null}},{"start":{"line":145,"column":11},"end":{"line":171,"column":null}}]},"4":{"loc":{"start":{"line":135,"column":22},"end":{"line":139,"column":13}},"type":"cond-expr","locations":[{"start":{"line":136,"column":10},"end":{"line":138,"column":33}},{"start":{"line":139,"column":10},"end":{"line":139,"column":13}}]},"5":{"loc":{"start":{"line":136,"column":10},"end":{"line":138,"column":33}},"type":"cond-expr","locations":[{"start":{"line":137,"column":12},"end":{"line":137,"column":27}},{"start":{"line":138,"column":12},"end":{"line":138,"column":33}}]},"6":{"loc":{"start":{"line":145,"column":11},"end":{"line":171,"column":null}},"type":"if","locations":[{"start":{"line":145,"column":11},"end":{"line":171,"column":null}},{"start":{"line":156,"column":11},"end":{"line":171,"column":null}}]},"7":{"loc":{"start":{"line":146,"column":22},"end":{"line":150,"column":13}},"type":"cond-expr","locations":[{"start":{"line":147,"column":10},"end":{"line":149,"column":33}},{"start":{"line":150,"column":10},"end":{"line":150,"column":13}}]},"8":{"loc":{"start":{"line":147,"column":10},"end":{"line":149,"column":33}},"type":"cond-expr","locations":[{"start":{"line":148,"column":12},"end":{"line":148,"column":27}},{"start":{"line":149,"column":12},"end":{"line":149,"column":33}}]},"9":{"loc":{"start":{"line":156,"column":11},"end":{"line":171,"column":null}},"type":"if","locations":[{"start":{"line":156,"column":11},"end":{"line":171,"column":null}},{"start":{"line":158,"column":11},"end":{"line":171,"column":null}}]},"10":{"loc":{"start":{"line":158,"column":11},"end":{"line":171,"column":null}},"type":"if","locations":[{"start":{"line":158,"column":11},"end":{"line":171,"column":null}},{"start":{"line":169,"column":11},"end":{"line":171,"column":null}}]},"11":{"loc":{"start":{"line":159,"column":22},"end":{"line":163,"column":13}},"type":"cond-expr","locations":[{"start":{"line":160,"column":10},"end":{"line":162,"column":33}},{"start":{"line":163,"column":10},"end":{"line":163,"column":13}}]},"12":{"loc":{"start":{"line":160,"column":10},"end":{"line":162,"column":33}},"type":"cond-expr","locations":[{"start":{"line":161,"column":12},"end":{"line":161,"column":27}},{"start":{"line":162,"column":12},"end":{"line":162,"column":33}}]},"13":{"loc":{"start":{"line":176,"column":4},"end":{"line":178,"column":null}},"type":"if","locations":[{"start":{"line":176,"column":4},"end":{"line":178,"column":null}}]},"14":{"loc":{"start":{"line":184,"column":8},"end":{"line":186,"column":null}},"type":"if","locations":[{"start":{"line":184,"column":8},"end":{"line":186,"column":null}}]},"15":{"loc":{"start":{"line":204,"column":4},"end":{"line":204,"column":36}},"type":"default-arg","locations":[{"start":{"line":204,"column":31},"end":{"line":204,"column":36}}]},"16":{"loc":{"start":{"line":219,"column":4},"end":{"line":222,"column":null}},"type":"if","locations":[{"start":{"line":219,"column":4},"end":{"line":222,"column":null}}]},"17":{"loc":{"start":{"line":223,"column":18},"end":{"line":223,"column":42}},"type":"binary-expr","locations":[{"start":{"line":223,"column":18},"end":{"line":223,"column":35}},{"start":{"line":223,"column":39},"end":{"line":223,"column":42}}]},"18":{"loc":{"start":{"line":224,"column":4},"end":{"line":227,"column":null}},"type":"if","locations":[{"start":{"line":224,"column":4},"end":{"line":227,"column":null}}]},"19":{"loc":{"start":{"line":239,"column":6},"end":{"line":239,"column":19}},"type":"binary-expr","locations":[{"start":{"line":239,"column":6},"end":{"line":239,"column":13}},{"start":{"line":239,"column":17},"end":{"line":239,"column":19}}]},"20":{"loc":{"start":{"line":241,"column":4},"end":{"line":252,"column":null}},"type":"if","locations":[{"start":{"line":241,"column":4},"end":{"line":252,"column":null}}]},"21":{"loc":{"start":{"line":244,"column":10},"end":{"line":248,"column":null}},"type":"if","locations":[{"start":{"line":244,"column":10},"end":{"line":248,"column":null}},{"start":{"line":246,"column":17},"end":{"line":248,"column":null}}]},"22":{"loc":{"start":{"line":259,"column":8},"end":{"line":268,"column":null}},"type":"if","locations":[{"start":{"line":259,"column":8},"end":{"line":268,"column":null}},{"start":{"line":261,"column":15},"end":{"line":268,"column":null}}]},"23":{"loc":{"start":{"line":259,"column":12},"end":{"line":259,"column":74}},"type":"binary-expr","locations":[{"start":{"line":259,"column":12},"end":{"line":259,"column":45}},{"start":{"line":259,"column":49},"end":{"line":259,"column":74}}]},"24":{"loc":{"start":{"line":261,"column":15},"end":{"line":268,"column":null}},"type":"if","locations":[{"start":{"line":261,"column":15},"end":{"line":268,"column":null}},{"start":{"line":266,"column":15},"end":{"line":268,"column":null}}]},"25":{"loc":{"start":{"line":261,"column":19},"end":{"line":261,"column":71}},"type":"binary-expr","locations":[{"start":{"line":261,"column":19},"end":{"line":261,"column":44}},{"start":{"line":261,"column":48},"end":{"line":261,"column":71}}]},"26":{"loc":{"start":{"line":273,"column":6},"end":{"line":275,"column":null}},"type":"if","locations":[{"start":{"line":273,"column":6},"end":{"line":275,"column":null}}]},"27":{"loc":{"start":{"line":273,"column":10},"end":{"line":273,"column":41}},"type":"binary-expr","locations":[{"start":{"line":273,"column":10},"end":{"line":273,"column":28}},{"start":{"line":273,"column":32},"end":{"line":273,"column":41}}]},"28":{"loc":{"start":{"line":302,"column":4},"end":{"line":305,"column":null}},"type":"if","locations":[{"start":{"line":302,"column":4},"end":{"line":305,"column":null}}]},"29":{"loc":{"start":{"line":306,"column":18},"end":{"line":306,"column":42}},"type":"binary-expr","locations":[{"start":{"line":306,"column":18},"end":{"line":306,"column":35}},{"start":{"line":306,"column":39},"end":{"line":306,"column":42}}]},"30":{"loc":{"start":{"line":307,"column":4},"end":{"line":310,"column":null}},"type":"if","locations":[{"start":{"line":307,"column":4},"end":{"line":310,"column":null}}]},"31":{"loc":{"start":{"line":344,"column":4},"end":{"line":347,"column":null}},"type":"if","locations":[{"start":{"line":344,"column":4},"end":{"line":347,"column":null}}]},"32":{"loc":{"start":{"line":348,"column":18},"end":{"line":348,"column":42}},"type":"binary-expr","locations":[{"start":{"line":348,"column":18},"end":{"line":348,"column":35}},{"start":{"line":348,"column":39},"end":{"line":348,"column":42}}]},"33":{"loc":{"start":{"line":349,"column":4},"end":{"line":352,"column":null}},"type":"if","locations":[{"start":{"line":349,"column":4},"end":{"line":352,"column":null}}]}},"s":{"0":5,"1":5,"2":5,"3":5,"4":5,"5":5,"6":5,"7":0,"8":5,"9":0,"10":5,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0,"36":0,"37":0,"38":0,"39":0,"40":0,"41":0,"42":0,"43":0,"44":0,"45":0,"46":0,"47":0,"48":0,"49":0,"50":0,"51":0,"52":0,"53":0,"54":0,"55":0,"56":0,"57":0,"58":0,"59":0,"60":0,"61":0,"62":0,"63":0,"64":0,"65":0,"66":0,"67":0,"68":0,"69":0,"70":0,"71":0,"72":0,"73":0,"74":0,"75":0,"76":0,"77":0,"78":0,"79":0,"80":0,"81":0,"82":0,"83":0,"84":0,"85":0,"86":0,"87":0,"88":0,"89":0,"90":0,"91":0,"92":0,"93":0,"94":0,"95":0,"96":0,"97":0,"98":0,"99":0,"100":0,"101":0,"102":0,"103":0,"104":0,"105":0,"106":0,"107":0,"108":0,"109":0,"110":0,"111":0,"112":0,"113":0,"114":0,"115":0,"116":0,"117":0,"118":0,"119":0,"120":0,"121":0,"122":0,"123":0,"124":0,"125":0,"126":0,"127":0,"128":0,"129":0,"130":0,"131":0,"132":0,"133":0,"134":0,"135":0,"136":0,"137":0,"138":0,"139":0,"140":0,"141":0,"142":0,"143":0,"144":0,"145":0,"146":0,"147":0,"148":0,"149":0,"150":0,"151":0,"152":0,"153":0,"154":5,"155":0,"156":0,"157":0,"158":0,"159":5,"160":0,"161":0},"f":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0},"b":{"0":[0],"1":[0],"2":[0,0],"3":[0,0],"4":[0,0],"5":[0,0],"6":[0,0],"7":[0,0],"8":[0,0],"9":[0,0],"10":[0,0],"11":[0,0],"12":[0,0],"13":[0],"14":[0],"15":[0],"16":[0],"17":[0,0],"18":[0],"19":[0,0],"20":[0],"21":[0,0],"22":[0,0],"23":[0,0],"24":[0,0],"25":[0,0],"26":[0],"27":[0,0],"28":[0],"29":[0,0],"30":[0],"31":[0],"32":[0,0],"33":[0]}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/util/asError.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/util/asError.ts","statementMap":{"0":{"start":{"line":1,"column":23},"end":{"line":6,"column":1}},"1":{"start":{"line":2,"column":2},"end":{"line":4,"column":null}},"2":{"start":{"line":3,"column":4},"end":{"line":3,"column":null}},"3":{"start":{"line":5,"column":2},"end":{"line":5,"column":null}},"4":{"start":{"line":1,"column":13},"end":{"line":1,"column":23}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":1,"column":23},"end":{"line":1,"column":24}},"loc":{"start":{"line":1,"column":38},"end":{"line":6,"column":1}}}},"branchMap":{"0":{"loc":{"start":{"line":2,"column":2},"end":{"line":4,"column":null}},"type":"if","locations":[{"start":{"line":2,"column":2},"end":{"line":4,"column":null}}]}},"s":{"0":5,"1":0,"2":0,"3":0,"4":5},"f":{"0":0},"b":{"0":[0]}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/util/deepEqual.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/util/deepEqual.ts","statementMap":{"0":{"start":{"line":1,"column":0},"end":{"line":1,"column":35}},"1":{"start":{"line":4,"column":2},"end":{"line":4,"column":null}},"2":{"start":{"line":4,"column":43},"end":{"line":4,"column":null}},"3":{"start":{"line":5,"column":18},"end":{"line":5,"column":42}},"4":{"start":{"line":6,"column":2},"end":{"line":9,"column":null}},"5":{"start":{"line":7,"column":4},"end":{"line":7,"column":null}},"6":{"start":{"line":7,"column":26},"end":{"line":7,"column":null}},"7":{"start":{"line":7,"column":45},"end":{"line":7,"column":null}},"8":{"start":{"line":8,"column":4},"end":{"line":8,"column":null}},"9":{"start":{"line":10,"column":2},"end":{"line":10,"column":null}},"10":{"start":{"line":10,"column":38},"end":{"line":10,"column":null}},"11":{"start":{"line":11,"column":18},"end":{"line":11,"column":65}},"12":{"start":{"line":11,"column":49},"end":{"line":11,"column":63}},"13":{"start":{"line":12,"column":2},"end":{"line":17,"column":null}},"14":{"start":{"line":13,"column":4},"end":{"line":16,"column":null}},"15":{"start":{"line":14,"column":6},"end":{"line":14,"column":null}},"16":{"start":{"line":14,"column":23},"end":{"line":14,"column":null}},"17":{"start":{"line":15,"column":6},"end":{"line":15,"column":null}},"18":{"start":{"line":15,"column":65},"end":{"line":15,"column":null}},"19":{"start":{"line":18,"column":2},"end":{"line":18,"column":null}},"20":{"start":{"line":3,"column":0},"end":{"line":3,"column":16}}},"fnMap":{"0":{"name":"deepEqual","decl":{"start":{"line":3,"column":16},"end":{"line":3,"column":25}},"loc":{"start":{"line":3,"column":44},"end":{"line":19,"column":1}}},"1":{"name":"(anonymous_1)","decl":{"start":{"line":11,"column":42},"end":{"line":11,"column":43}},"loc":{"start":{"line":11,"column":49},"end":{"line":11,"column":63}}}},"branchMap":{"0":{"loc":{"start":{"line":4,"column":2},"end":{"line":4,"column":null}},"type":"if","locations":[{"start":{"line":4,"column":2},"end":{"line":4,"column":null}}]},"1":{"loc":{"start":{"line":6,"column":2},"end":{"line":9,"column":null}},"type":"if","locations":[{"start":{"line":6,"column":2},"end":{"line":9,"column":null}}]},"2":{"loc":{"start":{"line":7,"column":26},"end":{"line":7,"column":null}},"type":"if","locations":[{"start":{"line":7,"column":26},"end":{"line":7,"column":null}}]},"3":{"loc":{"start":{"line":10,"column":2},"end":{"line":10,"column":null}},"type":"if","locations":[{"start":{"line":10,"column":2},"end":{"line":10,"column":null}}]},"4":{"loc":{"start":{"line":14,"column":6},"end":{"line":14,"column":null}},"type":"if","locations":[{"start":{"line":14,"column":6},"end":{"line":14,"column":null}}]},"5":{"loc":{"start":{"line":15,"column":6},"end":{"line":15,"column":null}},"type":"if","locations":[{"start":{"line":15,"column":6},"end":{"line":15,"column":null}}]}},"s":{"0":6,"1":11,"2":8,"3":3,"4":3,"5":0,"6":0,"7":0,"8":0,"9":3,"10":0,"11":3,"12":6,"13":3,"14":5,"15":10,"16":0,"17":10,"18":0,"19":3,"20":6},"f":{"0":11,"1":6},"b":{"0":[8],"1":[0],"2":[0],"3":[0],"4":[0],"5":[0]}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/util/deepMerge.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/util/deepMerge.ts","statementMap":{"0":{"start":{"line":1,"column":0},"end":{"line":1,"column":35}},"1":{"start":{"line":4,"column":20},"end":{"line":4,"column":49}},"2":{"start":{"line":5,"column":2},"end":{"line":5,"column":null}},"3":{"start":{"line":5,"column":30},"end":{"line":5,"column":null}},"4":{"start":{"line":6,"column":18},"end":{"line":6,"column":75}},"5":{"start":{"line":6,"column":57},"end":{"line":6,"column":74}},"6":{"start":{"line":7,"column":2},"end":{"line":7,"column":null}},"7":{"start":{"line":7,"column":28},"end":{"line":7,"column":null}},"8":{"start":{"line":8,"column":2},"end":{"line":8,"column":null}},"9":{"start":{"line":8,"column":28},"end":{"line":8,"column":null}},"10":{"start":{"line":9,"column":18},"end":{"line":9,"column":65}},"11":{"start":{"line":9,"column":49},"end":{"line":9,"column":63}},"12":{"start":{"line":10,"column":2},"end":{"line":15,"column":null}},"13":{"start":{"line":11,"column":27},"end":{"line":12,"column":null}},"14":{"start":{"line":12,"column":6},"end":{"line":12,"column":39}},"15":{"start":{"line":14,"column":6},"end":{"line":14,"column":null}},"16":{"start":{"line":16,"column":2},"end":{"line":16,"column":null}},"17":{"start":{"line":3,"column":0},"end":{"line":3,"column":16}}},"fnMap":{"0":{"name":"deepMerge","decl":{"start":{"line":3,"column":16},"end":{"line":3,"column":25}},"loc":{"start":{"line":3,"column":44},"end":{"line":17,"column":1}}},"1":{"name":"(anonymous_1)","decl":{"start":{"line":6,"column":50},"end":{"line":6,"column":51}},"loc":{"start":{"line":6,"column":57},"end":{"line":6,"column":74}}},"2":{"name":"(anonymous_2)","decl":{"start":{"line":9,"column":42},"end":{"line":9,"column":43}},"loc":{"start":{"line":9,"column":49},"end":{"line":9,"column":63}}},"3":{"name":"(anonymous_3)","decl":{"start":{"line":11,"column":43},"end":{"line":11,"column":44}},"loc":{"start":{"line":12,"column":6},"end":{"line":12,"column":39}}}},"branchMap":{"0":{"loc":{"start":{"line":5,"column":2},"end":{"line":5,"column":null}},"type":"if","locations":[{"start":{"line":5,"column":2},"end":{"line":5,"column":null}}]},"1":{"loc":{"start":{"line":7,"column":2},"end":{"line":7,"column":null}},"type":"if","locations":[{"start":{"line":7,"column":2},"end":{"line":7,"column":null}}]},"2":{"loc":{"start":{"line":8,"column":2},"end":{"line":8,"column":null}},"type":"if","locations":[{"start":{"line":8,"column":2},"end":{"line":8,"column":null}}]},"3":{"loc":{"start":{"line":12,"column":6},"end":{"line":12,"column":39}},"type":"cond-expr","locations":[{"start":{"line":12,"column":17},"end":{"line":12,"column":34}},{"start":{"line":12,"column":37},"end":{"line":12,"column":39}}]}},"s":{"0":6,"1":253,"2":253,"3":156,"4":97,"5":126,"6":97,"7":26,"8":71,"9":50,"10":71,"11":149,"12":71,"13":242,"14":528,"15":242,"16":71,"17":6},"f":{"0":253,"1":126,"2":149,"3":528},"b":{"0":[156],"1":[26],"2":[50],"3":[262,266]}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/util/fileHelper.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/util/fileHelper.ts","statementMap":{"0":{"start":{"line":2,"column":0},"end":{"line":2,"column":28}},"1":{"start":{"line":3,"column":0},"end":{"line":3,"column":35}},"2":{"start":{"line":4,"column":0},"end":{"line":4,"column":32}},"3":{"start":{"line":6,"column":0},"end":{"line":6,"column":38}},"4":{"start":{"line":8,"column":21},"end":{"line":8,"column":38}},"5":{"start":{"line":57,"column":13},"end":{"line":57,"column":25}},"6":{"start":{"line":58,"column":13},"end":{"line":58,"column":45}},"7":{"start":{"line":59,"column":13},"end":{"line":59,"column":49}},"8":{"start":{"line":62,"column":19},"end":{"line":62,"column":47}},"9":{"start":{"line":63,"column":4},"end":{"line":65,"column":null}},"10":{"start":{"line":64,"column":6},"end":{"line":64,"column":null}},"11":{"start":{"line":67,"column":4},"end":{"line":67,"column":null}},"12":{"start":{"line":70,"column":4},"end":{"line":77,"column":null}},"13":{"start":{"line":72,"column":14},"end":{"line":72,"column":18}},"14":{"start":{"line":73,"column":14},"end":{"line":73,"column":19}},"15":{"start":{"line":76,"column":6},"end":{"line":76,"column":null}},"16":{"start":{"line":78,"column":4},"end":{"line":80,"column":null}},"17":{"start":{"line":79,"column":50},"end":{"line":79,"column":72}},"18":{"start":{"line":84,"column":21},"end":{"line":84,"column":71}},"19":{"start":{"line":84,"column":60},"end":{"line":84,"column":62}},"20":{"start":{"line":85,"column":22},"end":{"line":85,"column":47}},"21":{"start":{"line":86,"column":4},"end":{"line":86,"column":null}},"22":{"start":{"line":98,"column":4},"end":{"line":98,"column":null}},"23":{"start":{"line":104,"column":4},"end":{"line":112,"column":null}},"24":{"start":{"line":107,"column":8},"end":{"line":107,"column":null}},"25":{"start":{"line":110,"column":8},"end":{"line":110,"column":null}},"26":{"start":{"line":121,"column":4},"end":{"line":129,"column":null}},"27":{"start":{"line":124,"column":8},"end":{"line":124,"column":null}},"28":{"start":{"line":127,"column":8},"end":{"line":127,"column":null}},"29":{"start":{"line":138,"column":4},"end":{"line":146,"column":null}},"30":{"start":{"line":141,"column":8},"end":{"line":141,"column":null}},"31":{"start":{"line":144,"column":8},"end":{"line":144,"column":null}},"32":{"start":{"line":55,"column":0},"end":{"line":55,"column":13}},"33":{"start":{"line":150,"column":0},"end":{"line":150,"column":null}}},"fnMap":{"0":{"name":"(anonymous_7)","decl":{"start":{"line":56,"column":2},"end":{"line":56,"column":null}},"loc":{"start":{"line":59,"column":49},"end":{"line":60,"column":6}}},"1":{"name":"(anonymous_8)","decl":{"start":{"line":61,"column":2},"end":{"line":61,"column":7}},"loc":{"start":{"line":61,"column":41},"end":{"line":68,"column":3}}},"2":{"name":"(anonymous_9)","decl":{"start":{"line":69,"column":2},"end":{"line":69,"column":7}},"loc":{"start":{"line":69,"column":31},"end":{"line":81,"column":3}}},"3":{"name":"(anonymous_10)","decl":{"start":{"line":72,"column":8},"end":{"line":72,"column":11}},"loc":{"start":{"line":72,"column":14},"end":{"line":72,"column":18}}},"4":{"name":"(anonymous_11)","decl":{"start":{"line":73,"column":8},"end":{"line":73,"column":11}},"loc":{"start":{"line":73,"column":14},"end":{"line":73,"column":19}}},"5":{"name":"(anonymous_12)","decl":{"start":{"line":79,"column":40},"end":{"line":79,"column":41}},"loc":{"start":{"line":79,"column":50},"end":{"line":79,"column":72}}},"6":{"name":"(anonymous_13)","decl":{"start":{"line":83,"column":2},"end":{"line":83,"column":7}},"loc":{"start":{"line":83,"column":41},"end":{"line":87,"column":3}}},"7":{"name":"(anonymous_14)","decl":{"start":{"line":84,"column":53},"end":{"line":84,"column":56}},"loc":{"start":{"line":84,"column":60},"end":{"line":84,"column":62}}},"8":{"name":"(anonymous_15)","decl":{"start":{"line":93,"column":2},"end":{"line":93,"column":8}},"loc":{"start":{"line":96,"column":36},"end":{"line":99,"column":3}}},"9":{"name":"(anonymous_16)","decl":{"start":{"line":103,"column":2},"end":{"line":103,"column":8}},"loc":{"start":{"line":103,"column":67},"end":{"line":113,"column":3}}},"10":{"name":"(anonymous_17)","decl":{"start":{"line":106,"column":6},"end":{"line":106,"column":7}},"loc":{"start":{"line":106,"column":17},"end":{"line":108,"column":7}}},"11":{"name":"(anonymous_18)","decl":{"start":{"line":109,"column":6},"end":{"line":109,"column":7}},"loc":{"start":{"line":109,"column":19},"end":{"line":111,"column":7}}},"12":{"name":"(anonymous_19)","decl":{"start":{"line":117,"column":2},"end":{"line":117,"column":8}},"loc":{"start":{"line":119,"column":40},"end":{"line":130,"column":3}}},"13":{"name":"(anonymous_20)","decl":{"start":{"line":123,"column":6},"end":{"line":123,"column":7}},"loc":{"start":{"line":123,"column":17},"end":{"line":125,"column":7}}},"14":{"name":"(anonymous_21)","decl":{"start":{"line":126,"column":6},"end":{"line":126,"column":7}},"loc":{"start":{"line":126,"column":19},"end":{"line":128,"column":7}}},"15":{"name":"(anonymous_22)","decl":{"start":{"line":134,"column":2},"end":{"line":134,"column":8}},"loc":{"start":{"line":136,"column":40},"end":{"line":147,"column":3}}},"16":{"name":"(anonymous_23)","decl":{"start":{"line":140,"column":6},"end":{"line":140,"column":7}},"loc":{"start":{"line":140,"column":17},"end":{"line":142,"column":7}}},"17":{"name":"(anonymous_24)","decl":{"start":{"line":143,"column":6},"end":{"line":143,"column":7}},"loc":{"start":{"line":143,"column":19},"end":{"line":145,"column":7}}}},"branchMap":{"0":{"loc":{"start":{"line":63,"column":4},"end":{"line":65,"column":null}},"type":"if","locations":[{"start":{"line":63,"column":4},"end":{"line":65,"column":null}}]},"1":{"loc":{"start":{"line":70,"column":4},"end":{"line":77,"column":null}},"type":"if","locations":[{"start":{"line":70,"column":4},"end":{"line":77,"column":null}}]},"2":{"loc":{"start":{"line":84,"column":21},"end":{"line":84,"column":71}},"type":"binary-expr","locations":[{"start":{"line":84,"column":22},"end":{"line":84,"column":64}},{"start":{"line":84,"column":69},"end":{"line":84,"column":71}}]}},"s":{"0":5,"1":5,"2":5,"3":5,"4":5,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":0,"32":5,"33":5},"f":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0},"b":{"0":[0],"1":[0],"2":[0,0]}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/util/getDefaultString.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/util/getDefaultString.ts","statementMap":{"0":{"start":{"line":2,"column":0},"end":{"line":2,"column":51}},"1":{"start":{"line":5,"column":2},"end":{"line":9,"column":null}},"2":{"start":{"line":6,"column":4},"end":{"line":6,"column":null}},"3":{"start":{"line":8,"column":4},"end":{"line":8,"column":null}},"4":{"start":{"line":4,"column":0},"end":{"line":4,"column":16}}},"fnMap":{"0":{"name":"getDefaultString","decl":{"start":{"line":4,"column":16},"end":{"line":4,"column":32}},"loc":{"start":{"line":4,"column":59},"end":{"line":10,"column":1}}}},"branchMap":{"0":{"loc":{"start":{"line":5,"column":2},"end":{"line":9,"column":null}},"type":"if","locations":[{"start":{"line":5,"column":2},"end":{"line":9,"column":null}},{"start":{"line":7,"column":9},"end":{"line":9,"column":null}}]}},"s":{"0":5,"1":0,"2":0,"3":0,"4":5},"f":{"0":0},"b":{"0":[0,0]}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/util/getRandomCharInSet.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/util/getRandomCharInSet.ts","statementMap":{"0":{"start":{"line":4,"column":14},"end":{"line":4,"column":38}},"1":{"start":{"line":5,"column":16},"end":{"line":6,"column":null}},"2":{"start":{"line":8,"column":2},"end":{"line":13,"column":null}},"3":{"start":{"line":9,"column":4},"end":{"line":11,"column":null}},"4":{"start":{"line":10,"column":6},"end":{"line":10,"column":null}},"5":{"start":{"line":12,"column":4},"end":{"line":12,"column":null}},"6":{"start":{"line":14,"column":2},"end":{"line":14,"column":null}},"7":{"start":{"line":3,"column":0},"end":{"line":3,"column":16}},"8":{"start":{"line":17,"column":21},"end":{"line":17,"column":43}},"9":{"start":{"line":18,"column":29},"end":{"line":18,"column":33}},"10":{"start":{"line":19,"column":27},"end":{"line":19,"column":31}},"11":{"start":{"line":20,"column":17},"end":{"line":20,"column":22}},"12":{"start":{"line":21,"column":2},"end":{"line":70,"column":null}},"13":{"start":{"line":22,"column":4},"end":{"line":69,"column":null}},"14":{"start":{"line":24,"column":8},"end":{"line":48,"column":null}},"15":{"start":{"line":25,"column":10},"end":{"line":27,"column":null}},"16":{"start":{"line":26,"column":12},"end":{"line":26,"column":null}},"17":{"start":{"line":28,"column":22},"end":{"line":28,"column":65}},"18":{"start":{"line":29,"column":10},"end":{"line":33,"column":null}},"19":{"start":{"line":34,"column":10},"end":{"line":34,"column":null}},"20":{"start":{"line":35,"column":10},"end":{"line":35,"column":null}},"21":{"start":{"line":36,"column":10},"end":{"line":36,"column":null}},"22":{"start":{"line":37,"column":10},"end":{"line":37,"column":null}},"23":{"start":{"line":38,"column":15},"end":{"line":48,"column":null}},"24":{"start":{"line":39,"column":10},"end":{"line":39,"column":null}},"25":{"start":{"line":40,"column":10},"end":{"line":40,"column":null}},"26":{"start":{"line":41,"column":10},"end":{"line":41,"column":null}},"27":{"start":{"line":42,"column":15},"end":{"line":48,"column":null}},"28":{"start":{"line":43,"column":10},"end":{"line":43,"column":null}},"29":{"start":{"line":44,"column":15},"end":{"line":48,"column":null}},"30":{"start":{"line":45,"column":10},"end":{"line":45,"column":null}},"31":{"start":{"line":47,"column":10},"end":{"line":47,"column":null}},"32":{"start":{"line":49,"column":8},"end":{"line":49,"column":13}},"33":{"start":{"line":51,"column":8},"end":{"line":59,"column":null}},"34":{"start":{"line":52,"column":10},"end":{"line":52,"column":null}},"35":{"start":{"line":53,"column":15},"end":{"line":59,"column":null}},"36":{"start":{"line":54,"column":10},"end":{"line":54,"column":null}},"37":{"start":{"line":55,"column":15},"end":{"line":59,"column":null}},"38":{"start":{"line":56,"column":10},"end":{"line":56,"column":null}},"39":{"start":{"line":58,"column":10},"end":{"line":58,"column":null}},"40":{"start":{"line":60,"column":8},"end":{"line":60,"column":13}},"41":{"start":{"line":62,"column":8},"end":{"line":68,"column":null}},"42":{"start":{"line":63,"column":10},"end":{"line":63,"column":null}},"43":{"start":{"line":64,"column":15},"end":{"line":68,"column":null}},"44":{"start":{"line":65,"column":10},"end":{"line":65,"column":null}},"45":{"start":{"line":67,"column":10},"end":{"line":67,"column":null}},"46":{"start":{"line":71,"column":2},"end":{"line":89,"column":null}},"47":{"start":{"line":72,"column":4},"end":{"line":74,"column":null}},"48":{"start":{"line":73,"column":6},"end":{"line":73,"column":null}},"49":{"start":{"line":75,"column":16},"end":{"line":75,"column":59}},"50":{"start":{"line":76,"column":4},"end":{"line":80,"column":null}},"51":{"start":{"line":81,"column":4},"end":{"line":81,"column":null}},"52":{"start":{"line":82,"column":9},"end":{"line":89,"column":null}},"53":{"start":{"line":83,"column":4},"end":{"line":83,"column":null}},"54":{"start":{"line":84,"column":4},"end":{"line":88,"column":null}},"55":{"start":{"line":90,"column":2},"end":{"line":90,"column":null}}},"fnMap":{"0":{"name":"getRandomCharInSet","decl":{"start":{"line":3,"column":16},"end":{"line":3,"column":34}},"loc":{"start":{"line":3,"column":50},"end":{"line":15,"column":1}}},"1":{"name":"stringToCharSet","decl":{"start":{"line":16,"column":9},"end":{"line":16,"column":24}},"loc":{"start":{"line":16,"column":40},"end":{"line":91,"column":1}}}},"branchMap":{"0":{"loc":{"start":{"line":9,"column":4},"end":{"line":11,"column":null}},"type":"if","locations":[{"start":{"line":9,"column":4},"end":{"line":11,"column":null}}]},"1":{"loc":{"start":{"line":22,"column":4},"end":{"line":69,"column":null}},"type":"switch","locations":[{"start":{"line":23,"column":6},"end":{"line":49,"column":13}},{"start":{"line":50,"column":6},"end":{"line":60,"column":13}},{"start":{"line":61,"column":6},"end":{"line":68,"column":null}}]},"2":{"loc":{"start":{"line":24,"column":8},"end":{"line":48,"column":null}},"type":"if","locations":[{"start":{"line":24,"column":8},"end":{"line":48,"column":null}},{"start":{"line":38,"column":15},"end":{"line":48,"column":null}}]},"3":{"loc":{"start":{"line":24,"column":12},"end":{"line":24,"column":42}},"type":"binary-expr","locations":[{"start":{"line":24,"column":12},"end":{"line":24,"column":26}},{"start":{"line":24,"column":30},"end":{"line":24,"column":42}}]},"4":{"loc":{"start":{"line":25,"column":10},"end":{"line":27,"column":null}},"type":"if","locations":[{"start":{"line":25,"column":10},"end":{"line":27,"column":null}}]},"5":{"loc":{"start":{"line":38,"column":15},"end":{"line":48,"column":null}},"type":"if","locations":[{"start":{"line":38,"column":15},"end":{"line":48,"column":null}},{"start":{"line":42,"column":15},"end":{"line":48,"column":null}}]},"6":{"loc":{"start":{"line":38,"column":19},"end":{"line":38,"column":46}},"type":"binary-expr","locations":[{"start":{"line":38,"column":19},"end":{"line":38,"column":33}},{"start":{"line":38,"column":37},"end":{"line":38,"column":46}}]},"7":{"loc":{"start":{"line":42,"column":15},"end":{"line":48,"column":null}},"type":"if","locations":[{"start":{"line":42,"column":15},"end":{"line":48,"column":null}},{"start":{"line":44,"column":15},"end":{"line":48,"column":null}}]},"8":{"loc":{"start":{"line":42,"column":19},"end":{"line":42,"column":45}},"type":"binary-expr","locations":[{"start":{"line":42,"column":19},"end":{"line":42,"column":33}},{"start":{"line":42,"column":37},"end":{"line":42,"column":45}}]},"9":{"loc":{"start":{"line":44,"column":15},"end":{"line":48,"column":null}},"type":"if","locations":[{"start":{"line":44,"column":15},"end":{"line":48,"column":null}},{"start":{"line":46,"column":15},"end":{"line":48,"column":null}}]},"10":{"loc":{"start":{"line":44,"column":19},"end":{"line":44,"column":62}},"type":"binary-expr","locations":[{"start":{"line":44,"column":19},"end":{"line":44,"column":33}},{"start":{"line":44,"column":37},"end":{"line":44,"column":49}},{"start":{"line":44,"column":53},"end":{"line":44,"column":62}}]},"11":{"loc":{"start":{"line":51,"column":8},"end":{"line":59,"column":null}},"type":"if","locations":[{"start":{"line":51,"column":8},"end":{"line":59,"column":null}},{"start":{"line":53,"column":15},"end":{"line":59,"column":null}}]},"12":{"loc":{"start":{"line":53,"column":15},"end":{"line":59,"column":null}},"type":"if","locations":[{"start":{"line":53,"column":15},"end":{"line":59,"column":null}},{"start":{"line":55,"column":15},"end":{"line":59,"column":null}}]},"13":{"loc":{"start":{"line":55,"column":15},"end":{"line":59,"column":null}},"type":"if","locations":[{"start":{"line":55,"column":15},"end":{"line":59,"column":null}},{"start":{"line":57,"column":15},"end":{"line":59,"column":null}}]},"14":{"loc":{"start":{"line":55,"column":19},"end":{"line":55,"column":43}},"type":"binary-expr","locations":[{"start":{"line":55,"column":19},"end":{"line":55,"column":27}},{"start":{"line":55,"column":31},"end":{"line":55,"column":43}}]},"15":{"loc":{"start":{"line":62,"column":8},"end":{"line":68,"column":null}},"type":"if","locations":[{"start":{"line":62,"column":8},"end":{"line":68,"column":null}},{"start":{"line":64,"column":15},"end":{"line":68,"column":null}}]},"16":{"loc":{"start":{"line":64,"column":15},"end":{"line":68,"column":null}},"type":"if","locations":[{"start":{"line":64,"column":15},"end":{"line":68,"column":null}},{"start":{"line":66,"column":15},"end":{"line":68,"column":null}}]},"17":{"loc":{"start":{"line":64,"column":19},"end":{"line":64,"column":43}},"type":"binary-expr","locations":[{"start":{"line":64,"column":19},"end":{"line":64,"column":27}},{"start":{"line":64,"column":31},"end":{"line":64,"column":43}}]},"18":{"loc":{"start":{"line":71,"column":2},"end":{"line":89,"column":null}},"type":"if","locations":[{"start":{"line":71,"column":2},"end":{"line":89,"column":null}},{"start":{"line":82,"column":9},"end":{"line":89,"column":null}}]},"19":{"loc":{"start":{"line":71,"column":6},"end":{"line":71,"column":36}},"type":"binary-expr","locations":[{"start":{"line":71,"column":6},"end":{"line":71,"column":20}},{"start":{"line":71,"column":24},"end":{"line":71,"column":36}}]},"20":{"loc":{"start":{"line":72,"column":4},"end":{"line":74,"column":null}},"type":"if","locations":[{"start":{"line":72,"column":4},"end":{"line":74,"column":null}}]},"21":{"loc":{"start":{"line":82,"column":9},"end":{"line":89,"column":null}},"type":"if","locations":[{"start":{"line":82,"column":9},"end":{"line":89,"column":null}}]}},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":5,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0,"36":0,"37":0,"38":0,"39":0,"40":0,"41":0,"42":0,"43":0,"44":0,"45":0,"46":0,"47":0,"48":0,"49":0,"50":0,"51":0,"52":0,"53":0,"54":0,"55":0},"f":{"0":0,"1":0},"b":{"0":[0],"1":[0,0,0],"2":[0,0],"3":[0,0],"4":[0],"5":[0,0],"6":[0,0],"7":[0,0],"8":[0,0],"9":[0,0],"10":[0,0,0],"11":[0,0],"12":[0,0],"13":[0,0],"14":[0,0],"15":[0,0],"16":[0,0],"17":[0,0],"18":[0,0],"19":[0,0],"20":[0],"21":[0]}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/util/getRandomString.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/util/getRandomString.ts","statementMap":{"0":{"start":{"line":2,"column":0},"end":{"line":2,"column":57}},"1":{"start":{"line":5,"column":10},"end":{"line":5,"column":12}},"2":{"start":{"line":6,"column":2},"end":{"line":8,"column":null}},"3":{"start":{"line":6,"column":15},"end":{"line":6,"column":16}},"4":{"start":{"line":7,"column":4},"end":{"line":7,"column":null}},"5":{"start":{"line":10,"column":2},"end":{"line":10,"column":null}},"6":{"start":{"line":4,"column":0},"end":{"line":4,"column":16}}},"fnMap":{"0":{"name":"getRandomString","decl":{"start":{"line":4,"column":16},"end":{"line":4,"column":31}},"loc":{"start":{"line":4,"column":55},"end":{"line":11,"column":1}}}},"branchMap":{},"s":{"0":5,"1":0,"2":0,"3":0,"4":0,"5":0,"6":5},"f":{"0":0},"b":{}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/util/getServiceInterface.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/util/getServiceInterface.ts","statementMap":{"0":{"start":{"line":2,"column":0},"end":{"line":2,"column":51}},"1":{"start":{"line":18,"column":25},"end":{"line":18,"column":65}},"2":{"start":{"line":19,"column":27},"end":{"line":25,"column":1}},"3":{"start":{"line":20,"column":17},"end":{"line":20,"column":49}},"4":{"start":{"line":21,"column":2},"end":{"line":21,"column":null}},"5":{"start":{"line":21,"column":15},"end":{"line":21,"column":null}},"6":{"start":{"line":22,"column":16},"end":{"line":22,"column":33}},"7":{"start":{"line":23,"column":15},"end":{"line":23,"column":57}},"8":{"start":{"line":24,"column":2},"end":{"line":24,"column":null}},"9":{"start":{"line":19,"column":13},"end":{"line":19,"column":27}},"10":{"start":{"line":67,"column":2},"end":{"line":69,"column":26}},"11":{"start":{"line":68,"column":2},"end":{"line":69,"column":26}},"12":{"start":{"line":69,"column":4},"end":{"line":69,"column":26}},"13":{"start":{"line":69,"column":21},"end":{"line":69,"column":25}},"14":{"start":{"line":71,"column":2},"end":{"line":73,"column":10}},"15":{"start":{"line":72,"column":2},"end":{"line":73,"column":10}},"16":{"start":{"line":73,"column":4},"end":{"line":73,"column":10}},"17":{"start":{"line":74,"column":15},"end":{"line":74,"column":62}},"18":{"start":{"line":74,"column":35},"end":{"line":74,"column":62}},"19":{"start":{"line":75,"column":32},"end":{"line":109,"column":1}},"20":{"start":{"line":79,"column":14},"end":{"line":79,"column":16}},"21":{"start":{"line":80,"column":14},"end":{"line":100,"column":3}},"22":{"start":{"line":82,"column":6},"end":{"line":84,"column":80}},"23":{"start":{"line":86,"column":4},"end":{"line":96,"column":null}},"24":{"start":{"line":87,"column":6},"end":{"line":87,"column":null}},"25":{"start":{"line":88,"column":11},"end":{"line":96,"column":null}},"26":{"start":{"line":89,"column":6},"end":{"line":95,"column":null}},"27":{"start":{"line":90,"column":8},"end":{"line":90,"column":null}},"28":{"start":{"line":91,"column":13},"end":{"line":95,"column":null}},"29":{"start":{"line":92,"column":8},"end":{"line":92,"column":null}},"30":{"start":{"line":94,"column":8},"end":{"line":94,"column":null}},"31":{"start":{"line":97,"column":4},"end":{"line":99,"column":null}},"32":{"start":{"line":101,"column":2},"end":{"line":103,"column":null}},"33":{"start":{"line":102,"column":4},"end":{"line":102,"column":null}},"34":{"start":{"line":104,"column":2},"end":{"line":106,"column":null}},"35":{"start":{"line":105,"column":4},"end":{"line":105,"column":null}},"36":{"start":{"line":108,"column":2},"end":{"line":108,"column":null}},"37":{"start":{"line":75,"column":13},"end":{"line":75,"column":32}},"38":{"start":{"line":111,"column":29},"end":{"line":176,"column":1}},"39":{"start":{"line":115,"column":16},"end":{"line":115,"column":56}},"40":{"start":{"line":116,"column":20},"end":{"line":116,"column":63}},"41":{"start":{"line":118,"column":2},"end":{"line":175,"column":null}},"42":{"start":{"line":122,"column":6},"end":{"line":122,"column":null}},"43":{"start":{"line":122,"column":37},"end":{"line":122,"column":55}},"44":{"start":{"line":125,"column":6},"end":{"line":127,"column":null}},"45":{"start":{"line":126,"column":15},"end":{"line":126,"column":61}},"46":{"start":{"line":130,"column":6},"end":{"line":134,"column":null}},"47":{"start":{"line":132,"column":10},"end":{"line":133,"column":68}},"48":{"start":{"line":137,"column":6},"end":{"line":139,"column":null}},"49":{"start":{"line":138,"column":15},"end":{"line":138,"column":60}},"50":{"start":{"line":142,"column":6},"end":{"line":144,"column":null}},"51":{"start":{"line":143,"column":15},"end":{"line":143,"column":60}},"52":{"start":{"line":147,"column":6},"end":{"line":152,"column":null}},"53":{"start":{"line":149,"column":10},"end":{"line":151,"column":36}},"54":{"start":{"line":155,"column":6},"end":{"line":155,"column":null}},"55":{"start":{"line":158,"column":6},"end":{"line":158,"column":null}},"56":{"start":{"line":161,"column":6},"end":{"line":161,"column":null}},"57":{"start":{"line":164,"column":6},"end":{"line":164,"column":null}},"58":{"start":{"line":167,"column":6},"end":{"line":167,"column":null}},"59":{"start":{"line":170,"column":6},"end":{"line":170,"column":null}},"60":{"start":{"line":173,"column":6},"end":{"line":173,"column":null}},"61":{"start":{"line":111,"column":13},"end":{"line":111,"column":29}},"62":{"start":{"line":178,"column":28},"end":{"line":222,"column":1}},"63":{"start":{"line":189,"column":32},"end":{"line":193,"column":4}},"64":{"start":{"line":194,"column":2},"end":{"line":196,"column":null}},"65":{"start":{"line":195,"column":4},"end":{"line":195,"column":null}},"66":{"start":{"line":197,"column":17},"end":{"line":197,"column":57}},"67":{"start":{"line":198,"column":15},"end":{"line":202,"column":4}},"68":{"start":{"line":203,"column":21},"end":{"line":207,"column":4}},"69":{"start":{"line":209,"column":50},"end":{"line":220,"column":null}},"70":{"start":{"line":217,"column":6},"end":{"line":217,"column":null}},"71":{"start":{"line":217,"column":30},"end":{"line":217,"column":null}},"72":{"start":{"line":218,"column":6},"end":{"line":218,"column":null}},"73":{"start":{"line":221,"column":2},"end":{"line":221,"column":null}},"74":{"start":{"line":226,"column":13},"end":{"line":226,"column":29}},"75":{"start":{"line":227,"column":13},"end":{"line":227,"column":53}},"76":{"start":{"line":234,"column":30},"end":{"line":234,"column":39}},"77":{"start":{"line":235,"column":21},"end":{"line":235,"column":41}},"78":{"start":{"line":236,"column":28},"end":{"line":241,"column":6}},"79":{"start":{"line":243,"column":4},"end":{"line":243,"column":null}},"80":{"start":{"line":249,"column":30},"end":{"line":249,"column":39}},"81":{"start":{"line":250,"column":28},"end":{"line":254,"column":6}},"82":{"start":{"line":256,"column":4},"end":{"line":256,"column":null}},"83":{"start":{"line":263,"column":30},"end":{"line":263,"column":39}},"84":{"start":{"line":264,"column":4},"end":{"line":276,"column":null}},"85":{"start":{"line":265,"column":33},"end":{"line":265,"column":41}},"86":{"start":{"line":266,"column":26},"end":{"line":268,"column":8}},"87":{"start":{"line":267,"column":8},"end":{"line":267,"column":null}},"88":{"start":{"line":269,"column":6},"end":{"line":274,"column":null}},"89":{"start":{"line":275,"column":6},"end":{"line":275,"column":null}},"90":{"start":{"line":224,"column":0},"end":{"line":224,"column":13}},"91":{"start":{"line":283,"column":2},"end":{"line":283,"column":null}},"92":{"start":{"line":279,"column":0},"end":{"line":279,"column":16}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":19,"column":27},"end":{"line":19,"column":28}},"loc":{"start":{"line":19,"column":60},"end":{"line":25,"column":1}}},"1":{"name":"(anonymous_1)","decl":{"start":{"line":67,"column":2},"end":{"line":67,"column":6}},"loc":{"start":{"line":68,"column":2},"end":{"line":69,"column":26}}},"2":{"name":"(anonymous_2)","decl":{"start":{"line":68,"column":2},"end":{"line":68,"column":3}},"loc":{"start":{"line":69,"column":4},"end":{"line":69,"column":26}}},"3":{"name":"(anonymous_3)","decl":{"start":{"line":69,"column":14},"end":{"line":69,"column":15}},"loc":{"start":{"line":69,"column":21},"end":{"line":69,"column":25}}},"4":{"name":"(anonymous_4)","decl":{"start":{"line":71,"column":2},"end":{"line":71,"column":6}},"loc":{"start":{"line":72,"column":2},"end":{"line":73,"column":10}}},"5":{"name":"(anonymous_5)","decl":{"start":{"line":72,"column":2},"end":{"line":72,"column":3}},"loc":{"start":{"line":73,"column":4},"end":{"line":73,"column":10}}},"6":{"name":"(anonymous_6)","decl":{"start":{"line":74,"column":15},"end":{"line":74,"column":19}},"loc":{"start":{"line":74,"column":35},"end":{"line":74,"column":62}}},"7":{"name":"(anonymous_7)","decl":{"start":{"line":75,"column":32},"end":{"line":75,"column":null}},"loc":{"start":{"line":78,"column":17},"end":{"line":109,"column":1}}},"8":{"name":"(anonymous_8)","decl":{"start":{"line":80,"column":14},"end":{"line":80,"column":15}},"loc":{"start":{"line":80,"column":74},"end":{"line":100,"column":3}}},"9":{"name":"(anonymous_9)","decl":{"start":{"line":111,"column":29},"end":{"line":111,"column":null}},"loc":{"start":{"line":114,"column":23},"end":{"line":176,"column":1}}},"10":{"name":"(anonymous_10)","decl":{"start":{"line":121,"column":4},"end":{"line":121,"column":8}},"loc":{"start":{"line":121,"column":22},"end":{"line":123,"column":5}}},"11":{"name":"(anonymous_11)","decl":{"start":{"line":122,"column":30},"end":{"line":122,"column":31}},"loc":{"start":{"line":122,"column":37},"end":{"line":122,"column":55}}},"12":{"name":"(anonymous_12)","decl":{"start":{"line":124,"column":4},"end":{"line":124,"column":8}},"loc":{"start":{"line":124,"column":22},"end":{"line":128,"column":5}}},"13":{"name":"(anonymous_13)","decl":{"start":{"line":126,"column":8},"end":{"line":126,"column":9}},"loc":{"start":{"line":126,"column":15},"end":{"line":126,"column":61}}},"14":{"name":"(anonymous_14)","decl":{"start":{"line":129,"column":4},"end":{"line":129,"column":8}},"loc":{"start":{"line":129,"column":19},"end":{"line":135,"column":5}}},"15":{"name":"(anonymous_15)","decl":{"start":{"line":131,"column":8},"end":{"line":131,"column":9}},"loc":{"start":{"line":132,"column":10},"end":{"line":133,"column":68}}},"16":{"name":"(anonymous_16)","decl":{"start":{"line":136,"column":4},"end":{"line":136,"column":8}},"loc":{"start":{"line":136,"column":21},"end":{"line":140,"column":5}}},"17":{"name":"(anonymous_17)","decl":{"start":{"line":138,"column":8},"end":{"line":138,"column":9}},"loc":{"start":{"line":138,"column":15},"end":{"line":138,"column":60}}},"18":{"name":"(anonymous_18)","decl":{"start":{"line":141,"column":4},"end":{"line":141,"column":8}},"loc":{"start":{"line":141,"column":21},"end":{"line":145,"column":5}}},"19":{"name":"(anonymous_19)","decl":{"start":{"line":143,"column":8},"end":{"line":143,"column":9}},"loc":{"start":{"line":143,"column":15},"end":{"line":143,"column":60}}},"20":{"name":"(anonymous_20)","decl":{"start":{"line":146,"column":4},"end":{"line":146,"column":8}},"loc":{"start":{"line":146,"column":22},"end":{"line":153,"column":5}}},"21":{"name":"(anonymous_21)","decl":{"start":{"line":148,"column":8},"end":{"line":148,"column":9}},"loc":{"start":{"line":149,"column":10},"end":{"line":151,"column":36}}},"22":{"name":"(anonymous_22)","decl":{"start":{"line":154,"column":4},"end":{"line":154,"column":8}},"loc":{"start":{"line":154,"column":12},"end":{"line":156,"column":5}}},"23":{"name":"(anonymous_23)","decl":{"start":{"line":157,"column":4},"end":{"line":157,"column":8}},"loc":{"start":{"line":157,"column":17},"end":{"line":159,"column":5}}},"24":{"name":"(anonymous_24)","decl":{"start":{"line":160,"column":4},"end":{"line":160,"column":8}},"loc":{"start":{"line":160,"column":17},"end":{"line":162,"column":5}}},"25":{"name":"(anonymous_25)","decl":{"start":{"line":163,"column":4},"end":{"line":163,"column":8}},"loc":{"start":{"line":163,"column":14},"end":{"line":165,"column":5}}},"26":{"name":"(anonymous_26)","decl":{"start":{"line":166,"column":4},"end":{"line":166,"column":8}},"loc":{"start":{"line":166,"column":16},"end":{"line":168,"column":5}}},"27":{"name":"(anonymous_27)","decl":{"start":{"line":169,"column":4},"end":{"line":169,"column":8}},"loc":{"start":{"line":169,"column":16},"end":{"line":171,"column":5}}},"28":{"name":"(anonymous_28)","decl":{"start":{"line":172,"column":4},"end":{"line":172,"column":8}},"loc":{"start":{"line":172,"column":17},"end":{"line":174,"column":5}}},"29":{"name":"(anonymous_29)","decl":{"start":{"line":178,"column":28},"end":{"line":178,"column":33}},"loc":{"start":{"line":188,"column":5},"end":{"line":222,"column":1}}},"30":{"name":"(anonymous_30)","decl":{"start":{"line":216,"column":4},"end":{"line":216,"column":8}},"loc":{"start":{"line":216,"column":23},"end":{"line":219,"column":5}}},"31":{"name":"(anonymous_31)","decl":{"start":{"line":225,"column":2},"end":{"line":225,"column":null}},"loc":{"start":{"line":227,"column":53},"end":{"line":228,"column":6}}},"32":{"name":"(anonymous_32)","decl":{"start":{"line":233,"column":2},"end":{"line":233,"column":7}},"loc":{"start":{"line":233,"column":13},"end":{"line":244,"column":3}}},"33":{"name":"(anonymous_33)","decl":{"start":{"line":248,"column":2},"end":{"line":248,"column":7}},"loc":{"start":{"line":248,"column":12},"end":{"line":257,"column":3}}},"34":{"name":"(anonymous_34)","decl":{"start":{"line":262,"column":2},"end":{"line":262,"column":7}},"loc":{"start":{"line":262,"column":14},"end":{"line":277,"column":3}}},"35":{"name":"(anonymous_35)","decl":{"start":{"line":265,"column":33},"end":{"line":265,"column":36}},"loc":{"start":{"line":265,"column":38},"end":{"line":265,"column":41}}},"36":{"name":"(anonymous_36)","decl":{"start":{"line":266,"column":44},"end":{"line":266,"column":45}},"loc":{"start":{"line":266,"column":56},"end":{"line":268,"column":7}}},"37":{"name":"getServiceInterface","decl":{"start":{"line":279,"column":16},"end":{"line":279,"column":35}},"loc":{"start":{"line":281,"column":42},"end":{"line":284,"column":1}}}},"branchMap":{"0":{"loc":{"start":{"line":21,"column":2},"end":{"line":21,"column":null}},"type":"if","locations":[{"start":{"line":21,"column":2},"end":{"line":21,"column":null}}]},"1":{"loc":{"start":{"line":82,"column":6},"end":{"line":84,"column":80}},"type":"binary-expr","locations":[{"start":{"line":82,"column":6},"end":{"line":82,"column":12}},{"start":{"line":83,"column":6},"end":{"line":83,"column":30}},{"start":{"line":84,"column":6},"end":{"line":84,"column":80}}]},"2":{"loc":{"start":{"line":86,"column":4},"end":{"line":96,"column":null}},"type":"if","locations":[{"start":{"line":86,"column":4},"end":{"line":96,"column":null}},{"start":{"line":88,"column":11},"end":{"line":96,"column":null}}]},"3":{"loc":{"start":{"line":88,"column":11},"end":{"line":96,"column":null}},"type":"if","locations":[{"start":{"line":88,"column":11},"end":{"line":96,"column":null}}]},"4":{"loc":{"start":{"line":89,"column":6},"end":{"line":95,"column":null}},"type":"if","locations":[{"start":{"line":89,"column":6},"end":{"line":95,"column":null}},{"start":{"line":91,"column":13},"end":{"line":95,"column":null}}]},"5":{"loc":{"start":{"line":90,"column":22},"end":{"line":90,"column":82}},"type":"cond-expr","locations":[{"start":{"line":90,"column":48},"end":{"line":90,"column":77}},{"start":{"line":90,"column":80},"end":{"line":90,"column":82}}]},"6":{"loc":{"start":{"line":91,"column":13},"end":{"line":95,"column":null}},"type":"if","locations":[{"start":{"line":91,"column":13},"end":{"line":95,"column":null}},{"start":{"line":93,"column":13},"end":{"line":95,"column":null}}]},"7":{"loc":{"start":{"line":97,"column":14},"end":{"line":97,"column":42}},"type":"cond-expr","locations":[{"start":{"line":97,"column":23},"end":{"line":97,"column":37}},{"start":{"line":97,"column":40},"end":{"line":97,"column":42}}]},"8":{"loc":{"start":{"line":98,"column":6},"end":{"line":98,"column":null}},"type":"cond-expr","locations":[{"start":{"line":98,"column":17},"end":{"line":98,"column":31}},{"start":{"line":98,"column":34},"end":{"line":98,"column":null}}]},"9":{"loc":{"start":{"line":99,"column":18},"end":{"line":99,"column":47}},"type":"cond-expr","locations":[{"start":{"line":99,"column":32},"end":{"line":99,"column":34}},{"start":{"line":99,"column":37},"end":{"line":99,"column":47}}]},"10":{"loc":{"start":{"line":101,"column":2},"end":{"line":103,"column":null}},"type":"if","locations":[{"start":{"line":101,"column":2},"end":{"line":103,"column":null}}]},"11":{"loc":{"start":{"line":104,"column":2},"end":{"line":106,"column":null}},"type":"if","locations":[{"start":{"line":104,"column":2},"end":{"line":106,"column":null}}]},"12":{"loc":{"start":{"line":126,"column":15},"end":{"line":126,"column":61}},"type":"binary-expr","locations":[{"start":{"line":126,"column":15},"end":{"line":126,"column":30}},{"start":{"line":126,"column":34},"end":{"line":126,"column":61}}]},"13":{"loc":{"start":{"line":132,"column":10},"end":{"line":133,"column":68}},"type":"binary-expr","locations":[{"start":{"line":132,"column":10},"end":{"line":132,"column":25}},{"start":{"line":133,"column":11},"end":{"line":133,"column":37}},{"start":{"line":133,"column":41},"end":{"line":133,"column":67}}]},"14":{"loc":{"start":{"line":138,"column":15},"end":{"line":138,"column":60}},"type":"binary-expr","locations":[{"start":{"line":138,"column":15},"end":{"line":138,"column":30}},{"start":{"line":138,"column":34},"end":{"line":138,"column":60}}]},"15":{"loc":{"start":{"line":143,"column":15},"end":{"line":143,"column":60}},"type":"binary-expr","locations":[{"start":{"line":143,"column":15},"end":{"line":143,"column":30}},{"start":{"line":143,"column":34},"end":{"line":143,"column":60}}]},"16":{"loc":{"start":{"line":149,"column":10},"end":{"line":151,"column":36}},"type":"binary-expr","locations":[{"start":{"line":149,"column":10},"end":{"line":149,"column":25}},{"start":{"line":150,"column":10},"end":{"line":150,"column":36}},{"start":{"line":151,"column":10},"end":{"line":151,"column":36}}]},"17":{"loc":{"start":{"line":194,"column":2},"end":{"line":196,"column":null}},"type":"if","locations":[{"start":{"line":194,"column":2},"end":{"line":196,"column":null}}]},"18":{"loc":{"start":{"line":213,"column":17},"end":{"line":215,"column":12}},"type":"cond-expr","locations":[{"start":{"line":214,"column":8},"end":{"line":214,"column":62}},{"start":{"line":215,"column":8},"end":{"line":215,"column":12}}]},"19":{"loc":{"start":{"line":217,"column":6},"end":{"line":217,"column":null}},"type":"if","locations":[{"start":{"line":217,"column":6},"end":{"line":217,"column":null}}]}},"s":{"0":6,"1":6,"2":6,"3":8,"4":8,"5":0,"6":8,"7":8,"8":8,"9":6,"10":6,"11":0,"12":0,"13":0,"14":6,"15":0,"16":0,"17":6,"18":0,"19":6,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0,"36":0,"37":6,"38":6,"39":0,"40":0,"41":0,"42":0,"43":0,"44":0,"45":0,"46":0,"47":0,"48":0,"49":0,"50":0,"51":0,"52":0,"53":0,"54":0,"55":0,"56":0,"57":0,"58":0,"59":0,"60":0,"61":6,"62":6,"63":0,"64":0,"65":0,"66":0,"67":0,"68":0,"69":0,"70":0,"71":0,"72":0,"73":0,"74":0,"75":0,"76":0,"77":0,"78":0,"79":0,"80":0,"81":0,"82":0,"83":0,"84":0,"85":0,"86":0,"87":0,"88":0,"89":0,"90":6,"91":0,"92":6},"f":{"0":8,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0,"36":0,"37":0},"b":{"0":[0],"1":[0,0,0],"2":[0,0],"3":[0],"4":[0,0],"5":[0,0],"6":[0,0],"7":[0,0],"8":[0,0],"9":[0,0],"10":[0],"11":[0],"12":[0,0],"13":[0,0,0],"14":[0,0],"15":[0,0],"16":[0,0,0],"17":[0],"18":[0,0],"19":[0]}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/util/getServiceInterfaces.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/util/getServiceInterfaces.ts","statementMap":{"0":{"start":{"line":2,"column":0},"end":{"line":2,"column":null}},"1":{"start":{"line":8,"column":32},"end":{"line":53,"column":1}},"2":{"start":{"line":17,"column":33},"end":{"line":20,"column":4}},"3":{"start":{"line":22,"column":60},"end":{"line":50,"column":null}},"4":{"start":{"line":24,"column":21},"end":{"line":24,"column":61}},"5":{"start":{"line":25,"column":19},"end":{"line":29,"column":8}},"6":{"start":{"line":30,"column":6},"end":{"line":32,"column":null}},"7":{"start":{"line":31,"column":8},"end":{"line":31,"column":null}},"8":{"start":{"line":33,"column":25},"end":{"line":39,"column":26}},"9":{"start":{"line":39,"column":21},"end":{"line":39,"column":25}},"10":{"start":{"line":40,"column":6},"end":{"line":49,"column":null}},"11":{"start":{"line":46,"column":10},"end":{"line":46,"column":null}},"12":{"start":{"line":46,"column":34},"end":{"line":46,"column":null}},"13":{"start":{"line":47,"column":10},"end":{"line":47,"column":null}},"14":{"start":{"line":52,"column":2},"end":{"line":52,"column":null}},"15":{"start":{"line":57,"column":13},"end":{"line":57,"column":29}},"16":{"start":{"line":58,"column":13},"end":{"line":58,"column":41}},"17":{"start":{"line":65,"column":26},"end":{"line":65,"column":35}},"18":{"start":{"line":66,"column":21},"end":{"line":66,"column":41}},"19":{"start":{"line":68,"column":6},"end":{"line":72,"column":8}},"20":{"start":{"line":74,"column":4},"end":{"line":74,"column":null}},"21":{"start":{"line":80,"column":26},"end":{"line":80,"column":35}},"22":{"start":{"line":82,"column":6},"end":{"line":85,"column":8}},"23":{"start":{"line":87,"column":4},"end":{"line":87,"column":null}},"24":{"start":{"line":94,"column":26},"end":{"line":94,"column":35}},"25":{"start":{"line":95,"column":4},"end":{"line":106,"column":null}},"26":{"start":{"line":96,"column":33},"end":{"line":96,"column":41}},"27":{"start":{"line":97,"column":26},"end":{"line":99,"column":8}},"28":{"start":{"line":98,"column":8},"end":{"line":98,"column":null}},"29":{"start":{"line":100,"column":6},"end":{"line":104,"column":null}},"30":{"start":{"line":105,"column":6},"end":{"line":105,"column":null}},"31":{"start":{"line":55,"column":0},"end":{"line":55,"column":13}},"32":{"start":{"line":113,"column":2},"end":{"line":113,"column":null}},"33":{"start":{"line":109,"column":0},"end":{"line":109,"column":16}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":8,"column":32},"end":{"line":8,"column":37}},"loc":{"start":{"line":16,"column":5},"end":{"line":53,"column":1}}},"1":{"name":"(anonymous_1)","decl":{"start":{"line":23,"column":46},"end":{"line":23,"column":51}},"loc":{"start":{"line":23,"column":78},"end":{"line":50,"column":5}}},"2":{"name":"(anonymous_2)","decl":{"start":{"line":39,"column":15},"end":{"line":39,"column":18}},"loc":{"start":{"line":39,"column":21},"end":{"line":39,"column":25}}},"3":{"name":"(anonymous_3)","decl":{"start":{"line":45,"column":8},"end":{"line":45,"column":12}},"loc":{"start":{"line":45,"column":27},"end":{"line":48,"column":9}}},"4":{"name":"(anonymous_4)","decl":{"start":{"line":56,"column":2},"end":{"line":56,"column":null}},"loc":{"start":{"line":58,"column":41},"end":{"line":59,"column":6}}},"5":{"name":"(anonymous_5)","decl":{"start":{"line":64,"column":2},"end":{"line":64,"column":7}},"loc":{"start":{"line":64,"column":13},"end":{"line":75,"column":3}}},"6":{"name":"(anonymous_6)","decl":{"start":{"line":79,"column":2},"end":{"line":79,"column":7}},"loc":{"start":{"line":79,"column":12},"end":{"line":88,"column":3}}},"7":{"name":"(anonymous_7)","decl":{"start":{"line":93,"column":2},"end":{"line":93,"column":7}},"loc":{"start":{"line":93,"column":14},"end":{"line":107,"column":3}}},"8":{"name":"(anonymous_8)","decl":{"start":{"line":96,"column":33},"end":{"line":96,"column":36}},"loc":{"start":{"line":96,"column":38},"end":{"line":96,"column":41}}},"9":{"name":"(anonymous_9)","decl":{"start":{"line":97,"column":44},"end":{"line":97,"column":45}},"loc":{"start":{"line":97,"column":56},"end":{"line":99,"column":7}}},"10":{"name":"getServiceInterfaces","decl":{"start":{"line":109,"column":16},"end":{"line":109,"column":36}},"loc":{"start":{"line":111,"column":30},"end":{"line":114,"column":1}}}},"branchMap":{"0":{"loc":{"start":{"line":30,"column":6},"end":{"line":32,"column":null}},"type":"if","locations":[{"start":{"line":30,"column":6},"end":{"line":32,"column":null}}]},"1":{"loc":{"start":{"line":46,"column":10},"end":{"line":46,"column":null}},"type":"if","locations":[{"start":{"line":46,"column":10},"end":{"line":46,"column":null}}]}},"s":{"0":5,"1":5,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":5,"32":0,"33":5},"f":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0},"b":{"0":[0],"1":[0]}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/util/graph.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/util/graph.ts","statementMap":{"0":{"start":{"line":15,"column":67},"end":{"line":15,"column":69}},"1":{"start":{"line":22,"column":49},"end":{"line":25,"column":null}},"2":{"start":{"line":26,"column":4},"end":{"line":34,"column":null}},"3":{"start":{"line":27,"column":20},"end":{"line":31,"column":null}},"4":{"start":{"line":32,"column":6},"end":{"line":32,"column":null}},"5":{"start":{"line":33,"column":6},"end":{"line":33,"column":null}},"6":{"start":{"line":35,"column":4},"end":{"line":43,"column":null}},"7":{"start":{"line":36,"column":20},"end":{"line":40,"column":null}},"8":{"start":{"line":41,"column":6},"end":{"line":41,"column":null}},"9":{"start":{"line":42,"column":6},"end":{"line":42,"column":null}},"10":{"start":{"line":44,"column":4},"end":{"line":44,"column":null}},"11":{"start":{"line":45,"column":4},"end":{"line":45,"column":null}},"12":{"start":{"line":50,"column":21},"end":{"line":50,"column":34}},"13":{"start":{"line":52,"column":6},"end":{"line":56,"column":null}},"14":{"start":{"line":53,"column":8},"end":{"line":55,"column":null}},"15":{"start":{"line":54,"column":10},"end":{"line":54,"column":null}},"16":{"start":{"line":58,"column":4},"end":{"line":58,"column":null}},"17":{"start":{"line":65,"column":17},"end":{"line":69,"column":null}},"18":{"start":{"line":70,"column":4},"end":{"line":70,"column":null}},"19":{"start":{"line":71,"column":4},"end":{"line":71,"column":null}},"20":{"start":{"line":72,"column":4},"end":{"line":72,"column":null}},"21":{"start":{"line":79,"column":57},"end":{"line":79,"column":59}},"22":{"start":{"line":83,"column":6},"end":{"line":85,"column":null}},"23":{"start":{"line":84,"column":8},"end":{"line":84,"column":14}},"24":{"start":{"line":86,"column":6},"end":{"line":86,"column":null}},"25":{"start":{"line":87,"column":6},"end":{"line":87,"column":null}},"26":{"start":{"line":88,"column":23},"end":{"line":90,"column":30}},"27":{"start":{"line":89,"column":23},"end":{"line":89,"column":40}},"28":{"start":{"line":90,"column":20},"end":{"line":90,"column":29}},"29":{"start":{"line":91,"column":6},"end":{"line":101,"column":null}},"30":{"start":{"line":92,"column":19},"end":{"line":92,"column":29}},"31":{"start":{"line":93,"column":8},"end":{"line":93,"column":null}},"32":{"start":{"line":94,"column":8},"end":{"line":100,"column":null}},"33":{"start":{"line":95,"column":23},"end":{"line":95,"column":33}},"34":{"start":{"line":96,"column":10},"end":{"line":99,"column":null}},"35":{"start":{"line":97,"column":12},"end":{"line":97,"column":null}},"36":{"start":{"line":98,"column":12},"end":{"line":98,"column":null}},"37":{"start":{"line":104,"column":4},"end":{"line":121,"column":null}},"38":{"start":{"line":105,"column":23},"end":{"line":105,"column":58}},"39":{"start":{"line":106,"column":6},"end":{"line":118,"column":null}},"40":{"start":{"line":107,"column":8},"end":{"line":117,"column":null}},"41":{"start":{"line":108,"column":21},"end":{"line":108,"column":31}},"42":{"start":{"line":109,"column":10},"end":{"line":109,"column":null}},"43":{"start":{"line":110,"column":10},"end":{"line":116,"column":null}},"44":{"start":{"line":111,"column":25},"end":{"line":111,"column":35}},"45":{"start":{"line":112,"column":12},"end":{"line":115,"column":null}},"46":{"start":{"line":113,"column":14},"end":{"line":113,"column":null}},"47":{"start":{"line":114,"column":14},"end":{"line":114,"column":null}},"48":{"start":{"line":120,"column":6},"end":{"line":120,"column":null}},"49":{"start":{"line":128,"column":57},"end":{"line":128,"column":59}},"50":{"start":{"line":132,"column":6},"end":{"line":134,"column":null}},"51":{"start":{"line":133,"column":8},"end":{"line":133,"column":14}},"52":{"start":{"line":135,"column":6},"end":{"line":135,"column":null}},"53":{"start":{"line":136,"column":6},"end":{"line":136,"column":null}},"54":{"start":{"line":137,"column":23},"end":{"line":139,"column":32}},"55":{"start":{"line":138,"column":23},"end":{"line":138,"column":38}},"56":{"start":{"line":139,"column":20},"end":{"line":139,"column":31}},"57":{"start":{"line":140,"column":6},"end":{"line":150,"column":null}},"58":{"start":{"line":141,"column":19},"end":{"line":141,"column":29}},"59":{"start":{"line":142,"column":8},"end":{"line":142,"column":null}},"60":{"start":{"line":143,"column":8},"end":{"line":149,"column":null}},"61":{"start":{"line":144,"column":23},"end":{"line":144,"column":33}},"62":{"start":{"line":145,"column":10},"end":{"line":148,"column":null}},"63":{"start":{"line":146,"column":12},"end":{"line":146,"column":null}},"64":{"start":{"line":147,"column":12},"end":{"line":147,"column":null}},"65":{"start":{"line":153,"column":4},"end":{"line":170,"column":null}},"66":{"start":{"line":154,"column":23},"end":{"line":154,"column":56}},"67":{"start":{"line":155,"column":6},"end":{"line":167,"column":null}},"68":{"start":{"line":156,"column":8},"end":{"line":166,"column":null}},"69":{"start":{"line":157,"column":21},"end":{"line":157,"column":31}},"70":{"start":{"line":158,"column":10},"end":{"line":158,"column":null}},"71":{"start":{"line":159,"column":10},"end":{"line":165,"column":null}},"72":{"start":{"line":160,"column":25},"end":{"line":160,"column":35}},"73":{"start":{"line":161,"column":12},"end":{"line":164,"column":null}},"74":{"start":{"line":162,"column":14},"end":{"line":162,"column":null}},"75":{"start":{"line":163,"column":14},"end":{"line":163,"column":null}},"76":{"start":{"line":169,"column":6},"end":{"line":169,"column":null}},"77":{"start":{"line":181,"column":6},"end":{"line":183,"column":55}},"78":{"start":{"line":183,"column":47},"end":{"line":183,"column":55}},"79":{"start":{"line":184,"column":52},"end":{"line":184,"column":54}},"80":{"start":{"line":185,"column":57},"end":{"line":185,"column":59}},"81":{"start":{"line":190,"column":6},"end":{"line":192,"column":null}},"82":{"start":{"line":191,"column":8},"end":{"line":191,"column":null}},"83":{"start":{"line":193,"column":6},"end":{"line":195,"column":null}},"84":{"start":{"line":194,"column":8},"end":{"line":194,"column":14}},"85":{"start":{"line":196,"column":6},"end":{"line":196,"column":null}},"86":{"start":{"line":197,"column":6},"end":{"line":197,"column":null}},"87":{"start":{"line":198,"column":23},"end":{"line":200,"column":46}},"88":{"start":{"line":199,"column":23},"end":{"line":199,"column":40}},"89":{"start":{"line":200,"column":20},"end":{"line":200,"column":45}},"90":{"start":{"line":201,"column":6},"end":{"line":215,"column":null}},"91":{"start":{"line":202,"column":19},"end":{"line":202,"column":29}},"92":{"start":{"line":203,"column":8},"end":{"line":203,"column":null}},"93":{"start":{"line":204,"column":8},"end":{"line":214,"column":null}},"94":{"start":{"line":205,"column":23},"end":{"line":205,"column":33}},"95":{"start":{"line":206,"column":10},"end":{"line":213,"column":null}},"96":{"start":{"line":207,"column":12},"end":{"line":209,"column":null}},"97":{"start":{"line":208,"column":14},"end":{"line":208,"column":null}},"98":{"start":{"line":211,"column":12},"end":{"line":211,"column":null}},"99":{"start":{"line":212,"column":12},"end":{"line":212,"column":null}},"100":{"start":{"line":218,"column":4},"end":{"line":242,"column":null}},"101":{"start":{"line":219,"column":23},"end":{"line":219,"column":74}},"102":{"start":{"line":219,"column":61},"end":{"line":219,"column":73}},"103":{"start":{"line":220,"column":6},"end":{"line":233,"column":null}},"104":{"start":{"line":221,"column":19},"end":{"line":221,"column":29}},"105":{"start":{"line":222,"column":8},"end":{"line":222,"column":null}},"106":{"start":{"line":223,"column":8},"end":{"line":232,"column":null}},"107":{"start":{"line":224,"column":23},"end":{"line":224,"column":33}},"108":{"start":{"line":225,"column":10},"end":{"line":231,"column":null}},"109":{"start":{"line":226,"column":12},"end":{"line":228,"column":null}},"110":{"start":{"line":227,"column":14},"end":{"line":227,"column":null}},"111":{"start":{"line":230,"column":12},"end":{"line":230,"column":null}},"112":{"start":{"line":235,"column":18},"end":{"line":235,"column":33}},"113":{"start":{"line":236,"column":6},"end":{"line":241,"column":null}},"114":{"start":{"line":237,"column":21},"end":{"line":237,"column":31}},"115":{"start":{"line":238,"column":8},"end":{"line":240,"column":null}},"116":{"start":{"line":239,"column":10},"end":{"line":239,"column":null}},"117":{"start":{"line":14,"column":0},"end":{"line":14,"column":13}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":16,"column":2},"end":{"line":16,"column":17}},"loc":{"start":{"line":16,"column":2},"end":{"line":16,"column":18}}},"1":{"name":"(anonymous_1)","decl":{"start":{"line":17,"column":2},"end":{"line":17,"column":11}},"loc":{"start":{"line":20,"column":60},"end":{"line":46,"column":3}}},"2":{"name":"(anonymous_2)","decl":{"start":{"line":47,"column":2},"end":{"line":47,"column":12}},"loc":{"start":{"line":48,"column":64},"end":{"line":59,"column":3}}},"3":{"name":"gen","decl":{"start":{"line":51,"column":14},"end":{"line":51,"column":17}},"loc":{"start":{"line":51,"column":17},"end":{"line":57,"column":5}}},"4":{"name":"(anonymous_4)","decl":{"start":{"line":60,"column":2},"end":{"line":60,"column":9}},"loc":{"start":{"line":63,"column":36},"end":{"line":73,"column":3}}},"5":{"name":"(anonymous_5)","decl":{"start":{"line":74,"column":2},"end":{"line":74,"column":20}},"loc":{"start":{"line":77,"column":59},"end":{"line":122,"column":3}}},"6":{"name":"rec","decl":{"start":{"line":80,"column":14},"end":{"line":80,"column":17}},"loc":{"start":{"line":81,"column":42},"end":{"line":102,"column":5}}},"7":{"name":"(anonymous_7)","decl":{"start":{"line":89,"column":16},"end":{"line":89,"column":17}},"loc":{"start":{"line":89,"column":23},"end":{"line":89,"column":40}}},"8":{"name":"(anonymous_8)","decl":{"start":{"line":90,"column":13},"end":{"line":90,"column":14}},"loc":{"start":{"line":90,"column":20},"end":{"line":90,"column":29}}},"9":{"name":"(anonymous_9)","decl":{"start":{"line":106,"column":14},"end":{"line":106,"column":22}},"loc":{"start":{"line":106,"column":23},"end":{"line":118,"column":7}}},"10":{"name":"(anonymous_10)","decl":{"start":{"line":123,"column":2},"end":{"line":123,"column":27}},"loc":{"start":{"line":126,"column":59},"end":{"line":171,"column":3}}},"11":{"name":"rec","decl":{"start":{"line":129,"column":14},"end":{"line":129,"column":17}},"loc":{"start":{"line":130,"column":42},"end":{"line":151,"column":5}}},"12":{"name":"(anonymous_12)","decl":{"start":{"line":138,"column":16},"end":{"line":138,"column":17}},"loc":{"start":{"line":138,"column":23},"end":{"line":138,"column":38}}},"13":{"name":"(anonymous_13)","decl":{"start":{"line":139,"column":13},"end":{"line":139,"column":14}},"loc":{"start":{"line":139,"column":20},"end":{"line":139,"column":31}}},"14":{"name":"(anonymous_14)","decl":{"start":{"line":155,"column":14},"end":{"line":155,"column":22}},"loc":{"start":{"line":155,"column":23},"end":{"line":167,"column":7}}},"15":{"name":"(anonymous_15)","decl":{"start":{"line":172,"column":2},"end":{"line":172,"column":14}},"loc":{"start":{"line":178,"column":59},"end":{"line":243,"column":3}}},"16":{"name":"(anonymous_16)","decl":{"start":{"line":183,"column":10},"end":{"line":183,"column":11}},"loc":{"start":{"line":183,"column":47},"end":{"line":183,"column":55}}},"17":{"name":"check","decl":{"start":{"line":186,"column":14},"end":{"line":186,"column":19}},"loc":{"start":{"line":188,"column":45},"end":{"line":216,"column":5}}},"18":{"name":"(anonymous_18)","decl":{"start":{"line":199,"column":16},"end":{"line":199,"column":17}},"loc":{"start":{"line":199,"column":23},"end":{"line":199,"column":40}}},"19":{"name":"(anonymous_19)","decl":{"start":{"line":200,"column":13},"end":{"line":200,"column":14}},"loc":{"start":{"line":200,"column":20},"end":{"line":200,"column":45}}},"20":{"name":"(anonymous_20)","decl":{"start":{"line":219,"column":54},"end":{"line":219,"column":55}},"loc":{"start":{"line":219,"column":61},"end":{"line":219,"column":73}}}},"branchMap":{"0":{"loc":{"start":{"line":53,"column":8},"end":{"line":55,"column":null}},"type":"if","locations":[{"start":{"line":53,"column":8},"end":{"line":55,"column":null}}]},"1":{"loc":{"start":{"line":83,"column":6},"end":{"line":85,"column":null}},"type":"if","locations":[{"start":{"line":83,"column":6},"end":{"line":85,"column":null}}]},"2":{"loc":{"start":{"line":96,"column":10},"end":{"line":99,"column":null}},"type":"if","locations":[{"start":{"line":96,"column":10},"end":{"line":99,"column":null}}]},"3":{"loc":{"start":{"line":104,"column":4},"end":{"line":121,"column":null}},"type":"if","locations":[{"start":{"line":104,"column":4},"end":{"line":121,"column":null}},{"start":{"line":119,"column":11},"end":{"line":121,"column":null}}]},"4":{"loc":{"start":{"line":112,"column":12},"end":{"line":115,"column":null}},"type":"if","locations":[{"start":{"line":112,"column":12},"end":{"line":115,"column":null}}]},"5":{"loc":{"start":{"line":132,"column":6},"end":{"line":134,"column":null}},"type":"if","locations":[{"start":{"line":132,"column":6},"end":{"line":134,"column":null}}]},"6":{"loc":{"start":{"line":145,"column":10},"end":{"line":148,"column":null}},"type":"if","locations":[{"start":{"line":145,"column":10},"end":{"line":148,"column":null}}]},"7":{"loc":{"start":{"line":153,"column":4},"end":{"line":170,"column":null}},"type":"if","locations":[{"start":{"line":153,"column":4},"end":{"line":170,"column":null}},{"start":{"line":168,"column":11},"end":{"line":170,"column":null}}]},"8":{"loc":{"start":{"line":161,"column":12},"end":{"line":164,"column":null}},"type":"if","locations":[{"start":{"line":161,"column":12},"end":{"line":164,"column":null}}]},"9":{"loc":{"start":{"line":181,"column":6},"end":{"line":183,"column":55}},"type":"cond-expr","locations":[{"start":{"line":182,"column":10},"end":{"line":182,"column":12}},{"start":{"line":183,"column":10},"end":{"line":183,"column":55}}]},"10":{"loc":{"start":{"line":190,"column":6},"end":{"line":192,"column":null}},"type":"if","locations":[{"start":{"line":190,"column":6},"end":{"line":192,"column":null}}]},"11":{"loc":{"start":{"line":193,"column":6},"end":{"line":195,"column":null}},"type":"if","locations":[{"start":{"line":193,"column":6},"end":{"line":195,"column":null}}]},"12":{"loc":{"start":{"line":206,"column":10},"end":{"line":213,"column":null}},"type":"if","locations":[{"start":{"line":206,"column":10},"end":{"line":213,"column":null}},{"start":{"line":210,"column":17},"end":{"line":213,"column":null}}]},"13":{"loc":{"start":{"line":207,"column":12},"end":{"line":209,"column":null}},"type":"if","locations":[{"start":{"line":207,"column":12},"end":{"line":209,"column":null}}]},"14":{"loc":{"start":{"line":218,"column":4},"end":{"line":242,"column":null}},"type":"if","locations":[{"start":{"line":218,"column":4},"end":{"line":242,"column":null}},{"start":{"line":234,"column":11},"end":{"line":242,"column":null}}]},"15":{"loc":{"start":{"line":225,"column":10},"end":{"line":231,"column":null}},"type":"if","locations":[{"start":{"line":225,"column":10},"end":{"line":231,"column":null}},{"start":{"line":229,"column":17},"end":{"line":231,"column":null}}]},"16":{"loc":{"start":{"line":226,"column":12},"end":{"line":228,"column":null}},"type":"if","locations":[{"start":{"line":226,"column":12},"end":{"line":228,"column":null}}]},"17":{"loc":{"start":{"line":238,"column":8},"end":{"line":240,"column":null}},"type":"if","locations":[{"start":{"line":238,"column":8},"end":{"line":240,"column":null}}]}},"s":{"0":11,"1":39,"2":39,"3":20,"4":20,"5":20,"6":39,"7":1,"8":1,"9":1,"10":39,"11":39,"12":1,"13":1,"14":4,"15":1,"16":1,"17":12,"18":12,"19":12,"20":12,"21":6,"22":15,"23":1,"24":14,"25":14,"26":14,"27":23,"28":9,"29":14,"30":16,"31":16,"32":16,"33":18,"34":18,"35":9,"36":9,"37":6,"38":5,"39":5,"40":5,"41":15,"42":15,"43":15,"44":15,"45":15,"46":10,"47":10,"48":1,"49":6,"50":15,"51":1,"52":14,"53":14,"54":14,"55":23,"56":9,"57":14,"58":16,"59":16,"60":16,"61":18,"62":18,"63":9,"64":9,"65":6,"66":5,"67":5,"68":5,"69":15,"70":15,"71":15,"72":15,"73":15,"74":10,"75":10,"76":1,"77":3,"78":11,"79":3,"80":3,"81":11,"82":3,"83":8,"84":0,"85":8,"86":8,"87":6,"88":12,"89":8,"90":6,"91":11,"92":11,"93":11,"94":13,"95":13,"96":6,"97":6,"98":7,"99":7,"100":3,"101":0,"102":0,"103":0,"104":0,"105":0,"106":0,"107":0,"108":0,"109":0,"110":0,"111":0,"112":3,"113":3,"114":11,"115":11,"116":3,"117":5},"f":{"0":11,"1":39,"2":1,"3":1,"4":12,"5":6,"6":15,"7":23,"8":9,"9":5,"10":6,"11":15,"12":23,"13":9,"14":5,"15":3,"16":11,"17":11,"18":12,"19":8,"20":0},"b":{"0":[1],"1":[1],"2":[9],"3":[5,1],"4":[10],"5":[1],"6":[9],"7":[5,1],"8":[10],"9":[0,3],"10":[3],"11":[0],"12":[6,7],"13":[6],"14":[0,3],"15":[0,0],"16":[0],"17":[3]}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/util/inMs.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/util/inMs.ts","statementMap":{"0":{"start":{"line":3,"column":23},"end":{"line":3,"column":58}},"1":{"start":{"line":5,"column":23},"end":{"line":13,"column":1}},"2":{"start":{"line":6,"column":2},"end":{"line":6,"column":null}},"3":{"start":{"line":6,"column":13},"end":{"line":6,"column":null}},"4":{"start":{"line":7,"column":2},"end":{"line":7,"column":null}},"5":{"start":{"line":7,"column":21},"end":{"line":7,"column":null}},"6":{"start":{"line":8,"column":2},"end":{"line":8,"column":null}},"7":{"start":{"line":8,"column":20},"end":{"line":8,"column":null}},"8":{"start":{"line":9,"column":2},"end":{"line":9,"column":null}},"9":{"start":{"line":9,"column":20},"end":{"line":9,"column":null}},"10":{"start":{"line":10,"column":2},"end":{"line":10,"column":null}},"11":{"start":{"line":10,"column":20},"end":{"line":10,"column":null}},"12":{"start":{"line":11,"column":2},"end":{"line":11,"column":null}},"13":{"start":{"line":11,"column":20},"end":{"line":11,"column":null}},"14":{"start":{"line":12,"column":2},"end":{"line":12,"column":null}},"15":{"start":{"line":14,"column":17},"end":{"line":19,"column":1}},"16":{"start":{"line":15,"column":2},"end":{"line":15,"column":null}},"17":{"start":{"line":15,"column":15},"end":{"line":15,"column":null}},"18":{"start":{"line":16,"column":16},"end":{"line":16,"column":41}},"19":{"start":{"line":17,"column":19},"end":{"line":17,"column":63}},"20":{"start":{"line":18,"column":2},"end":{"line":18,"column":null}},"21":{"start":{"line":20,"column":20},"end":{"line":31,"column":1}},"22":{"start":{"line":21,"column":2},"end":{"line":21,"column":null}},"23":{"start":{"line":21,"column":32},"end":{"line":21,"column":null}},"24":{"start":{"line":22,"column":2},"end":{"line":22,"column":null}},"25":{"start":{"line":22,"column":13},"end":{"line":22,"column":null}},"26":{"start":{"line":23,"column":18},"end":{"line":23,"column":44}},"27":{"start":{"line":24,"column":2},"end":{"line":24,"column":null}},"28":{"start":{"line":24,"column":16},"end":{"line":24,"column":null}},"29":{"start":{"line":25,"column":42},"end":{"line":25,"column":49}},"30":{"start":{"line":26,"column":21},"end":{"line":26,"column":41}},"31":{"start":{"line":27,"column":21},"end":{"line":27,"column":63}},"32":{"start":{"line":28,"column":22},"end":{"line":28,"column":50}},"33":{"start":{"line":30,"column":2},"end":{"line":30,"column":null}},"34":{"start":{"line":20,"column":13},"end":{"line":20,"column":20}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":5,"column":23},"end":{"line":5,"column":24}},"loc":{"start":{"line":5,"column":41},"end":{"line":13,"column":1}}},"1":{"name":"(anonymous_1)","decl":{"start":{"line":14,"column":17},"end":{"line":14,"column":18}},"loc":{"start":{"line":14,"column":63},"end":{"line":19,"column":1}}},"2":{"name":"(anonymous_2)","decl":{"start":{"line":20,"column":20},"end":{"line":20,"column":21}},"loc":{"start":{"line":20,"column":47},"end":{"line":31,"column":1}}}},"branchMap":{"0":{"loc":{"start":{"line":6,"column":2},"end":{"line":6,"column":null}},"type":"if","locations":[{"start":{"line":6,"column":2},"end":{"line":6,"column":null}}]},"1":{"loc":{"start":{"line":7,"column":2},"end":{"line":7,"column":null}},"type":"if","locations":[{"start":{"line":7,"column":2},"end":{"line":7,"column":null}}]},"2":{"loc":{"start":{"line":8,"column":2},"end":{"line":8,"column":null}},"type":"if","locations":[{"start":{"line":8,"column":2},"end":{"line":8,"column":null}}]},"3":{"loc":{"start":{"line":9,"column":2},"end":{"line":9,"column":null}},"type":"if","locations":[{"start":{"line":9,"column":2},"end":{"line":9,"column":null}}]},"4":{"loc":{"start":{"line":10,"column":2},"end":{"line":10,"column":null}},"type":"if","locations":[{"start":{"line":10,"column":2},"end":{"line":10,"column":null}}]},"5":{"loc":{"start":{"line":11,"column":2},"end":{"line":11,"column":null}},"type":"if","locations":[{"start":{"line":11,"column":2},"end":{"line":11,"column":null}}]},"6":{"loc":{"start":{"line":15,"column":2},"end":{"line":15,"column":null}},"type":"if","locations":[{"start":{"line":15,"column":2},"end":{"line":15,"column":null}}]},"7":{"loc":{"start":{"line":21,"column":2},"end":{"line":21,"column":null}},"type":"if","locations":[{"start":{"line":21,"column":2},"end":{"line":21,"column":null}}]},"8":{"loc":{"start":{"line":22,"column":2},"end":{"line":22,"column":null}},"type":"if","locations":[{"start":{"line":22,"column":2},"end":{"line":22,"column":null}}]},"9":{"loc":{"start":{"line":24,"column":2},"end":{"line":24,"column":null}},"type":"if","locations":[{"start":{"line":24,"column":2},"end":{"line":24,"column":null}}]},"10":{"loc":{"start":{"line":27,"column":30},"end":{"line":27,"column":49}},"type":"binary-expr","locations":[{"start":{"line":27,"column":30},"end":{"line":27,"column":42}},{"start":{"line":27,"column":46},"end":{"line":27,"column":49}}]}},"s":{"0":6,"1":6,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":6,"16":0,"17":0,"18":0,"19":0,"20":0,"21":6,"22":1,"23":0,"24":1,"25":1,"26":0,"27":0,"28":0,"29":0,"30":0,"31":0,"32":0,"33":0,"34":6},"f":{"0":0,"1":0,"2":1},"b":{"0":[0],"1":[0],"2":[0],"3":[0],"4":[0],"5":[0],"6":[0],"7":[0],"8":[1],"9":[0],"10":[0,0]}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/util/index.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/util/index.ts","statementMap":{"0":{"start":{"line":1,"column":0},"end":{"line":1,"column":22}},"1":{"start":{"line":2,"column":0},"end":{"line":2,"column":21}},"2":{"start":{"line":3,"column":0},"end":{"line":3,"column":26}},"3":{"start":{"line":4,"column":0},"end":{"line":4,"column":20}},"4":{"start":{"line":5,"column":0},"end":{"line":5,"column":20}},"5":{"start":{"line":6,"column":0},"end":{"line":6,"column":23}},"6":{"start":{"line":7,"column":0},"end":{"line":7,"column":15}},"7":{"start":{"line":9,"column":0},"end":{"line":9,"column":9}},"8":{"start":{"line":9,"column":9},"end":{"line":9,"column":30}},"9":{"start":{"line":9,"column":30},"end":{"line":9,"column":80}},"10":{"start":{"line":10,"column":0},"end":{"line":10,"column":9}},"11":{"start":{"line":10,"column":9},"end":{"line":10,"column":35}},"12":{"start":{"line":11,"column":0},"end":{"line":11,"column":9}},"13":{"start":{"line":11,"column":9},"end":{"line":11,"column":61}},"14":{"start":{"line":12,"column":0},"end":{"line":12,"column":9}},"15":{"start":{"line":12,"column":9},"end":{"line":12,"column":56}},"16":{"start":{"line":13,"column":0},"end":{"line":13,"column":9}},"17":{"start":{"line":13,"column":9},"end":{"line":13,"column":50}},"18":{"start":{"line":14,"column":0},"end":{"line":14,"column":29}},"19":{"start":{"line":15,"column":0},"end":{"line":15,"column":9}},"20":{"start":{"line":15,"column":9},"end":{"line":15,"column":53}},"21":{"start":{"line":16,"column":0},"end":{"line":16,"column":9}},"22":{"start":{"line":16,"column":9},"end":{"line":16,"column":29}}},"fnMap":{"0":{"name":"(anonymous_4)","decl":{"start":{"line":9,"column":9},"end":{"line":9,"column":28}},"loc":{"start":{"line":9,"column":9},"end":{"line":9,"column":30}}},"1":{"name":"(anonymous_5)","decl":{"start":{"line":9,"column":30},"end":{"line":9,"column":49}},"loc":{"start":{"line":9,"column":30},"end":{"line":9,"column":80}}},"2":{"name":"(anonymous_6)","decl":{"start":{"line":10,"column":9},"end":{"line":10,"column":16}},"loc":{"start":{"line":10,"column":9},"end":{"line":10,"column":35}}},"3":{"name":"(anonymous_7)","decl":{"start":{"line":11,"column":9},"end":{"line":11,"column":29}},"loc":{"start":{"line":11,"column":9},"end":{"line":11,"column":61}}},"4":{"name":"(anonymous_8)","decl":{"start":{"line":12,"column":9},"end":{"line":12,"column":25}},"loc":{"start":{"line":12,"column":9},"end":{"line":12,"column":56}}},"5":{"name":"(anonymous_9)","decl":{"start":{"line":13,"column":9},"end":{"line":13,"column":30}},"loc":{"start":{"line":13,"column":9},"end":{"line":13,"column":50}}},"6":{"name":"(anonymous_10)","decl":{"start":{"line":15,"column":9},"end":{"line":15,"column":25}},"loc":{"start":{"line":15,"column":9},"end":{"line":15,"column":53}}},"7":{"name":"(anonymous_11)","decl":{"start":{"line":16,"column":9},"end":{"line":16,"column":13}},"loc":{"start":{"line":16,"column":9},"end":{"line":16,"column":29}}}},"branchMap":{},"s":{"0":5,"1":5,"2":5,"3":5,"4":5,"5":5,"6":5,"7":5,"8":5,"9":5,"10":5,"11":5,"12":5,"13":5,"14":5,"15":5,"16":5,"17":5,"18":5,"19":5,"20":5,"21":5,"22":5},"f":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0},"b":{}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/util/nullIfEmpty.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/util/nullIfEmpty.ts","statementMap":{"0":{"start":{"line":10,"column":2},"end":{"line":10,"column":null}},"1":{"start":{"line":10,"column":18},"end":{"line":10,"column":null}},"2":{"start":{"line":11,"column":2},"end":{"line":11,"column":null}},"3":{"start":{"line":7,"column":0},"end":{"line":7,"column":24}}},"fnMap":{"0":{"name":"nullIfEmpty","decl":{"start":{"line":7,"column":24},"end":{"line":7,"column":35}},"loc":{"start":{"line":8,"column":13},"end":{"line":12,"column":1}}}},"branchMap":{"0":{"loc":{"start":{"line":10,"column":2},"end":{"line":10,"column":null}},"type":"if","locations":[{"start":{"line":10,"column":2},"end":{"line":10,"column":null}}]},"1":{"loc":{"start":{"line":11,"column":9},"end":{"line":11,"column":47}},"type":"cond-expr","locations":[{"start":{"line":11,"column":39},"end":{"line":11,"column":43}},{"start":{"line":11,"column":46},"end":{"line":11,"column":47}}]}},"s":{"0":0,"1":0,"2":0,"3":5},"f":{"0":0},"b":{"0":[0],"1":[0,0]}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/util/once.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/util/once.ts","statementMap":{"0":{"start":{"line":2,"column":25},"end":{"line":2,"column":27}},"1":{"start":{"line":3,"column":2},"end":{"line":8,"column":null}},"2":{"start":{"line":4,"column":4},"end":{"line":6,"column":null}},"3":{"start":{"line":5,"column":6},"end":{"line":5,"column":null}},"4":{"start":{"line":7,"column":4},"end":{"line":7,"column":null}},"5":{"start":{"line":1,"column":0},"end":{"line":1,"column":16}}},"fnMap":{"0":{"name":"once","decl":{"start":{"line":1,"column":16},"end":{"line":1,"column":20}},"loc":{"start":{"line":1,"column":35},"end":{"line":9,"column":1}}},"1":{"name":"(anonymous_1)","decl":{"start":{"line":3,"column":9},"end":{"line":3,"column":12}},"loc":{"start":{"line":3,"column":14},"end":{"line":8,"column":3}}}},"branchMap":{"0":{"loc":{"start":{"line":4,"column":4},"end":{"line":6,"column":null}},"type":"if","locations":[{"start":{"line":4,"column":4},"end":{"line":6,"column":null}}]}},"s":{"0":26,"1":26,"2":139,"3":25,"4":139,"5":6},"f":{"0":26,"1":139},"b":{"0":[25]}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/util/patterns.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/util/patterns.ts","statementMap":{"0":{"start":{"line":2,"column":0},"end":{"line":2,"column":36}},"1":{"start":{"line":4,"column":13},"end":{"line":7,"column":null}},"2":{"start":{"line":9,"column":13},"end":{"line":12,"column":null}},"3":{"start":{"line":14,"column":13},"end":{"line":17,"column":null}},"4":{"start":{"line":19,"column":13},"end":{"line":22,"column":null}},"5":{"start":{"line":24,"column":13},"end":{"line":27,"column":null}},"6":{"start":{"line":29,"column":13},"end":{"line":32,"column":null}},"7":{"start":{"line":34,"column":13},"end":{"line":37,"column":null}},"8":{"start":{"line":39,"column":13},"end":{"line":42,"column":null}},"9":{"start":{"line":44,"column":13},"end":{"line":48,"column":null}},"10":{"start":{"line":50,"column":13},"end":{"line":53,"column":null}},"11":{"start":{"line":55,"column":13},"end":{"line":59,"column":null}}},"fnMap":{},"branchMap":{},"s":{"0":5,"1":5,"2":5,"3":5,"4":5,"5":5,"6":5,"7":5,"8":5,"9":5,"10":5,"11":5},"f":{},"b":{}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/util/regexes.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/util/regexes.ts","statementMap":{"0":{"start":{"line":2,"column":13},"end":{"line":3,"column":null}},"1":{"start":{"line":6,"column":13},"end":{"line":7,"column":null}},"2":{"start":{"line":9,"column":13},"end":{"line":10,"column":null}},"3":{"start":{"line":12,"column":13},"end":{"line":12,"column":null}},"4":{"start":{"line":14,"column":13},"end":{"line":14,"column":null}},"5":{"start":{"line":17,"column":13},"end":{"line":18,"column":null}},"6":{"start":{"line":20,"column":13},"end":{"line":21,"column":null}},"7":{"start":{"line":23,"column":13},"end":{"line":24,"column":null}},"8":{"start":{"line":27,"column":13},"end":{"line":27,"column":null}},"9":{"start":{"line":30,"column":13},"end":{"line":30,"column":null}},"10":{"start":{"line":33,"column":13},"end":{"line":34,"column":null}}},"fnMap":{},"branchMap":{},"s":{"0":5,"1":5,"2":5,"3":5,"4":5,"5":5,"6":5,"7":5,"8":5,"9":5,"10":5},"f":{},"b":{}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/util/splitCommand.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/util/splitCommand.ts","statementMap":{"0":{"start":{"line":1,"column":0},"end":{"line":1,"column":44}},"1":{"start":{"line":3,"column":28},"end":{"line":8,"column":1}},"2":{"start":{"line":6,"column":2},"end":{"line":6,"column":null}},"3":{"start":{"line":6,"column":37},"end":{"line":6,"column":null}},"4":{"start":{"line":7,"column":2},"end":{"line":7,"column":null}},"5":{"start":{"line":3,"column":13},"end":{"line":3,"column":28}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":3,"column":28},"end":{"line":3,"column":null}},"loc":{"start":{"line":5,"column":14},"end":{"line":8,"column":1}}}},"branchMap":{"0":{"loc":{"start":{"line":6,"column":2},"end":{"line":6,"column":null}},"type":"if","locations":[{"start":{"line":6,"column":2},"end":{"line":6,"column":null}}]}},"s":{"0":5,"1":5,"2":0,"3":0,"4":0,"5":5},"f":{"0":0},"b":{"0":[0]}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/util/stringFromStdErrOut.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/util/stringFromStdErrOut.ts","statementMap":{"0":{"start":{"line":5,"column":2},"end":{"line":5,"column":null}},"1":{"start":{"line":1,"column":0},"end":{"line":1,"column":7}}},"fnMap":{"0":{"name":"stringFromStdErrOut","decl":{"start":{"line":1,"column":22},"end":{"line":1,"column":41}},"loc":{"start":{"line":4,"column":1},"end":{"line":6,"column":1}}}},"branchMap":{"0":{"loc":{"start":{"line":5,"column":9},"end":{"line":5,"column":56}},"type":"cond-expr","locations":[{"start":{"line":5,"column":21},"end":{"line":5,"column":45}},{"start":{"line":5,"column":48},"end":{"line":5,"column":56}}]}},"s":{"0":0,"1":6},"f":{"0":0},"b":{"0":[0,0]}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/util/typeHelpers.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/util/typeHelpers.ts","statementMap":{"0":{"start":{"line":11,"column":28},"end":{"line":12,"column":60}},"1":{"start":{"line":12,"column":2},"end":{"line":12,"column":60}},"2":{"start":{"line":11,"column":13},"end":{"line":11,"column":28}},"3":{"start":{"line":108,"column":12},"end":{"line":112,"column":10}},"4":{"start":{"line":113,"column":2},"end":{"line":113,"column":null}},"5":{"start":{"line":115,"column":2},"end":{"line":115,"column":null}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":11,"column":28},"end":{"line":11,"column":29}},"loc":{"start":{"line":12,"column":2},"end":{"line":12,"column":60}}},"1":{"name":"test","decl":{"start":{"line":106,"column":9},"end":{"line":106,"column":13}},"loc":{"start":{"line":106,"column":13},"end":{"line":116,"column":1}}},"2":{"name":"(anonymous_2)","decl":{"start":{"line":108,"column":12},"end":{"line":108,"column":19}},"loc":{"start":{"line":112,"column":7},"end":{"line":112,"column":10}}}},"branchMap":{"0":{"loc":{"start":{"line":12,"column":2},"end":{"line":12,"column":60}},"type":"binary-expr","locations":[{"start":{"line":12,"column":2},"end":{"line":12,"column":21}},{"start":{"line":12,"column":26},"end":{"line":12,"column":38}},{"start":{"line":12,"column":42},"end":{"line":12,"column":59}}]}},"s":{"0":5,"1":0,"2":5,"3":0,"4":0,"5":0},"f":{"0":0,"1":0,"2":0},"b":{"0":[0,0,0]}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/version/VersionGraph.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/version/VersionGraph.ts","statementMap":{"0":{"start":{"line":1,"column":0},"end":{"line":1,"column":56}},"1":{"start":{"line":4,"column":0},"end":{"line":4,"column":45}},"2":{"start":{"line":5,"column":0},"end":{"line":5,"column":35}},"3":{"start":{"line":6,"column":0},"end":{"line":6,"column":55}},"4":{"start":{"line":14,"column":13},"end":{"line":14,"column":49}},"5":{"start":{"line":17,"column":4},"end":{"line":108,"column":null}},"6":{"start":{"line":18,"column":20},"end":{"line":18,"column":null}},"7":{"start":{"line":32,"column":10},"end":{"line":32,"column":12}},"8":{"start":{"line":33,"column":6},"end":{"line":41,"column":null}},"9":{"start":{"line":34,"column":18},"end":{"line":34,"column":64}},"10":{"start":{"line":35,"column":23},"end":{"line":35,"column":49}},"11":{"start":{"line":36,"column":23},"end":{"line":36,"column":37}},"12":{"start":{"line":37,"column":8},"end":{"line":39,"column":null}},"13":{"start":{"line":38,"column":10},"end":{"line":38,"column":null}},"14":{"start":{"line":40,"column":8},"end":{"line":40,"column":null}},"15":{"start":{"line":42,"column":6},"end":{"line":106,"column":null}},"16":{"start":{"line":43,"column":8},"end":{"line":43,"column":null}},"17":{"start":{"line":43,"column":41},"end":{"line":43,"column":66}},"18":{"start":{"line":53,"column":24},"end":{"line":53,"column":33}},"19":{"start":{"line":54,"column":8},"end":{"line":105,"column":null}},"20":{"start":{"line":55,"column":10},"end":{"line":67,"column":null}},"21":{"start":{"line":57,"column":12},"end":{"line":64,"column":null}},"22":{"start":{"line":58,"column":14},"end":{"line":58,"column":null}},"23":{"start":{"line":59,"column":14},"end":{"line":61,"column":null}},"24":{"start":{"line":63,"column":14},"end":{"line":63,"column":null}},"25":{"start":{"line":65,"column":27},"end":{"line":65,"column":57}},"26":{"start":{"line":66,"column":12},"end":{"line":66,"column":null}},"27":{"start":{"line":69,"column":10},"end":{"line":81,"column":null}},"28":{"start":{"line":71,"column":12},"end":{"line":78,"column":null}},"29":{"start":{"line":72,"column":14},"end":{"line":72,"column":null}},"30":{"start":{"line":73,"column":14},"end":{"line":75,"column":null}},"31":{"start":{"line":77,"column":14},"end":{"line":77,"column":null}},"32":{"start":{"line":79,"column":27},"end":{"line":79,"column":57}},"33":{"start":{"line":80,"column":12},"end":{"line":80,"column":null}},"34":{"start":{"line":83,"column":10},"end":{"line":104,"column":null}},"35":{"start":{"line":84,"column":12},"end":{"line":103,"column":null}},"36":{"start":{"line":85,"column":28},"end":{"line":85,"column":56}},"37":{"start":{"line":86,"column":29},"end":{"line":86,"column":59}},"38":{"start":{"line":87,"column":14},"end":{"line":91,"column":null}},"39":{"start":{"line":92,"column":14},"end":{"line":102,"column":null}},"40":{"start":{"line":94,"column":18},"end":{"line":95,"column":45}},"41":{"start":{"line":97,"column":16},"end":{"line":101,"column":null}},"42":{"start":{"line":107,"column":6},"end":{"line":107,"column":null}},"43":{"start":{"line":110,"column":19},"end":{"line":111,"column":null}},"44":{"start":{"line":111,"column":4},"end":{"line":111,"column":55}},"45":{"start":{"line":120,"column":4},"end":{"line":120,"column":null}},"46":{"start":{"line":131,"column":18},"end":{"line":131,"column":30}},"47":{"start":{"line":132,"column":4},"end":{"line":151,"column":null}},"48":{"start":{"line":133,"column":19},"end":{"line":140,"column":null}},"49":{"start":{"line":135,"column":10},"end":{"line":137,"column":76}},"50":{"start":{"line":139,"column":10},"end":{"line":140,"column":74}},"51":{"start":{"line":142,"column":6},"end":{"line":150,"column":null}},"52":{"start":{"line":143,"column":8},"end":{"line":148,"column":null}},"53":{"start":{"line":144,"column":10},"end":{"line":146,"column":null}},"54":{"start":{"line":145,"column":12},"end":{"line":145,"column":null}},"55":{"start":{"line":147,"column":10},"end":{"line":147,"column":null}},"56":{"start":{"line":149,"column":8},"end":{"line":149,"column":14}},"57":{"start":{"line":152,"column":4},"end":{"line":152,"column":null}},"58":{"start":{"line":154,"column":19},"end":{"line":171,"column":null}},"59":{"start":{"line":155,"column":4},"end":{"line":170,"column":null}},"60":{"start":{"line":158,"column":10},"end":{"line":161,"column":53}},"61":{"start":{"line":165,"column":8},"end":{"line":168,"column":null}},"62":{"start":{"line":173,"column":17},"end":{"line":190,"column":null}},"63":{"start":{"line":174,"column":4},"end":{"line":189,"column":null}},"64":{"start":{"line":177,"column":10},"end":{"line":180,"column":53}},"65":{"start":{"line":184,"column":8},"end":{"line":187,"column":null}},"66":{"start":{"line":8,"column":0},"end":{"line":8,"column":13}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":13,"column":2},"end":{"line":13,"column":null}},"loc":{"start":{"line":15,"column":37},"end":{"line":109,"column":3}}},"1":{"name":"(anonymous_1)","decl":{"start":{"line":17,"column":22},"end":{"line":17,"column":25}},"loc":{"start":{"line":17,"column":27},"end":{"line":108,"column":5}}},"2":{"name":"(anonymous_2)","decl":{"start":{"line":43,"column":31},"end":{"line":43,"column":32}},"loc":{"start":{"line":43,"column":41},"end":{"line":43,"column":66}}},"3":{"name":"(anonymous_3)","decl":{"start":{"line":93,"column":16},"end":{"line":93,"column":17}},"loc":{"start":{"line":94,"column":18},"end":{"line":95,"column":45}}},"4":{"name":"(anonymous_4)","decl":{"start":{"line":110,"column":24},"end":{"line":110,"column":27}},"loc":{"start":{"line":111,"column":4},"end":{"line":111,"column":55}}},"5":{"name":"(anonymous_5)","decl":{"start":{"line":113,"column":2},"end":{"line":113,"column":8}},"loc":{"start":{"line":118,"column":74},"end":{"line":121,"column":3}}},"6":{"name":"(anonymous_6)","decl":{"start":{"line":122,"column":2},"end":{"line":122,"column":7}},"loc":{"start":{"line":130,"column":3},"end":{"line":153,"column":3}}},"7":{"name":"(anonymous_7)","decl":{"start":{"line":134,"column":8},"end":{"line":134,"column":9}},"loc":{"start":{"line":135,"column":10},"end":{"line":137,"column":76}}},"8":{"name":"(anonymous_8)","decl":{"start":{"line":138,"column":8},"end":{"line":138,"column":9}},"loc":{"start":{"line":139,"column":10},"end":{"line":140,"column":74}}},"9":{"name":"(anonymous_9)","decl":{"start":{"line":154,"column":24},"end":{"line":154,"column":27}},"loc":{"start":{"line":155,"column":4},"end":{"line":170,"column":null}}},"10":{"name":"(anonymous_10)","decl":{"start":{"line":157,"column":8},"end":{"line":157,"column":9}},"loc":{"start":{"line":158,"column":10},"end":{"line":161,"column":53}}},"11":{"name":"(anonymous_11)","decl":{"start":{"line":164,"column":6},"end":{"line":164,"column":7}},"loc":{"start":{"line":165,"column":8},"end":{"line":168,"column":null}}},"12":{"name":"(anonymous_12)","decl":{"start":{"line":173,"column":22},"end":{"line":173,"column":25}},"loc":{"start":{"line":174,"column":4},"end":{"line":189,"column":null}}},"13":{"name":"(anonymous_13)","decl":{"start":{"line":176,"column":8},"end":{"line":176,"column":9}},"loc":{"start":{"line":177,"column":10},"end":{"line":180,"column":53}}},"14":{"name":"(anonymous_14)","decl":{"start":{"line":183,"column":6},"end":{"line":183,"column":7}},"loc":{"start":{"line":184,"column":8},"end":{"line":187,"column":null}}}},"branchMap":{"0":{"loc":{"start":{"line":36,"column":23},"end":{"line":36,"column":37}},"type":"binary-expr","locations":[{"start":{"line":36,"column":23},"end":{"line":36,"column":31}},{"start":{"line":36,"column":35},"end":{"line":36,"column":37}}]},"1":{"loc":{"start":{"line":37,"column":8},"end":{"line":39,"column":null}},"type":"if","locations":[{"start":{"line":37,"column":8},"end":{"line":39,"column":null}}]},"2":{"loc":{"start":{"line":55,"column":10},"end":{"line":67,"column":null}},"type":"if","locations":[{"start":{"line":55,"column":10},"end":{"line":67,"column":null}}]},"3":{"loc":{"start":{"line":57,"column":12},"end":{"line":64,"column":null}},"type":"if","locations":[{"start":{"line":57,"column":12},"end":{"line":64,"column":null}},{"start":{"line":62,"column":19},"end":{"line":64,"column":null}}]},"4":{"loc":{"start":{"line":69,"column":10},"end":{"line":81,"column":null}},"type":"if","locations":[{"start":{"line":69,"column":10},"end":{"line":81,"column":null}}]},"5":{"loc":{"start":{"line":71,"column":12},"end":{"line":78,"column":null}},"type":"if","locations":[{"start":{"line":71,"column":12},"end":{"line":78,"column":null}},{"start":{"line":76,"column":19},"end":{"line":78,"column":null}}]},"6":{"loc":{"start":{"line":83,"column":10},"end":{"line":104,"column":null}},"type":"if","locations":[{"start":{"line":83,"column":10},"end":{"line":104,"column":null}}]},"7":{"loc":{"start":{"line":94,"column":18},"end":{"line":95,"column":45}},"type":"binary-expr","locations":[{"start":{"line":94,"column":18},"end":{"line":94,"column":55}},{"start":{"line":95,"column":18},"end":{"line":95,"column":45}}]},"8":{"loc":{"start":{"line":132,"column":4},"end":{"line":151,"column":null}},"type":"if","locations":[{"start":{"line":132,"column":4},"end":{"line":151,"column":null}}]},"9":{"loc":{"start":{"line":132,"column":8},"end":{"line":132,"column":18}},"type":"binary-expr","locations":[{"start":{"line":132,"column":8},"end":{"line":132,"column":12}},{"start":{"line":132,"column":16},"end":{"line":132,"column":18}}]},"10":{"loc":{"start":{"line":135,"column":10},"end":{"line":137,"column":76}},"type":"binary-expr","locations":[{"start":{"line":135,"column":11},"end":{"line":135,"column":45}},{"start":{"line":136,"column":12},"end":{"line":136,"column":40}},{"start":{"line":137,"column":11},"end":{"line":137,"column":48}},{"start":{"line":137,"column":52},"end":{"line":137,"column":75}}]},"11":{"loc":{"start":{"line":139,"column":10},"end":{"line":140,"column":74}},"type":"binary-expr","locations":[{"start":{"line":139,"column":11},"end":{"line":139,"column":45}},{"start":{"line":139,"column":49},"end":{"line":139,"column":75}},{"start":{"line":140,"column":11},"end":{"line":140,"column":48}},{"start":{"line":140,"column":52},"end":{"line":140,"column":73}}]},"12":{"loc":{"start":{"line":142,"column":6},"end":{"line":150,"column":null}},"type":"if","locations":[{"start":{"line":142,"column":6},"end":{"line":150,"column":null}}]},"13":{"loc":{"start":{"line":144,"column":10},"end":{"line":146,"column":null}},"type":"if","locations":[{"start":{"line":144,"column":10},"end":{"line":146,"column":null}}]},"14":{"loc":{"start":{"line":158,"column":10},"end":{"line":161,"column":53}},"type":"binary-expr","locations":[{"start":{"line":158,"column":11},"end":{"line":158,"column":45}},{"start":{"line":159,"column":12},"end":{"line":159,"column":57}},{"start":{"line":160,"column":11},"end":{"line":160,"column":48}},{"start":{"line":161,"column":12},"end":{"line":161,"column":52}}]},"15":{"loc":{"start":{"line":166,"column":10},"end":{"line":168,"column":50}},"type":"cond-expr","locations":[{"start":{"line":167,"column":14},"end":{"line":167,"column":24}},{"start":{"line":168,"column":14},"end":{"line":168,"column":50}}]},"16":{"loc":{"start":{"line":177,"column":10},"end":{"line":180,"column":53}},"type":"binary-expr","locations":[{"start":{"line":177,"column":11},"end":{"line":177,"column":45}},{"start":{"line":178,"column":12},"end":{"line":178,"column":57}},{"start":{"line":179,"column":11},"end":{"line":179,"column":48}},{"start":{"line":180,"column":12},"end":{"line":180,"column":52}}]},"17":{"loc":{"start":{"line":185,"column":10},"end":{"line":187,"column":50}},"type":"cond-expr","locations":[{"start":{"line":186,"column":14},"end":{"line":186,"column":24}},{"start":{"line":187,"column":14},"end":{"line":187,"column":50}}]}},"s":{"0":4,"1":4,"2":4,"3":4,"4":5,"5":5,"6":5,"7":5,"8":5,"9":5,"10":5,"11":5,"12":5,"13":5,"14":5,"15":5,"16":5,"17":0,"18":5,"19":5,"20":5,"21":5,"22":0,"23":0,"24":5,"25":5,"26":5,"27":5,"28":5,"29":0,"30":0,"31":5,"32":5,"33":5,"34":5,"35":0,"36":0,"37":0,"38":0,"39":0,"40":0,"41":0,"42":5,"43":5,"44":5,"45":5,"46":0,"47":0,"48":0,"49":0,"50":0,"51":0,"52":0,"53":0,"54":0,"55":0,"56":0,"57":0,"58":5,"59":5,"60":15,"61":10,"62":5,"63":5,"64":15,"65":10,"66":4},"f":{"0":5,"1":5,"2":0,"3":0,"4":5,"5":5,"6":0,"7":0,"8":0,"9":5,"10":15,"11":10,"12":5,"13":15,"14":10},"b":{"0":[5,5],"1":[5],"2":[5],"3":[0,5],"4":[5],"5":[0,5],"6":[0],"7":[0,0],"8":[0],"9":[0,0],"10":[0,0,0,0],"11":[0,0,0,0],"12":[0],"13":[0],"14":[15,10,15,5],"15":[5,5],"16":[15,10,15,5],"17":[5,5]}} +,"/Users/matthill/Code/start9/start-os/sdk/lib/version/VersionInfo.ts": {"path":"/Users/matthill/Code/start9/start-os/sdk/lib/version/VersionInfo.ts","statementMap":{"0":{"start":{"line":4,"column":13},"end":{"line":4,"column":null}},"1":{"start":{"line":33,"column":37},"end":{"line":33,"column":41}},"2":{"start":{"line":35,"column":13},"end":{"line":35,"column":71}},"3":{"start":{"line":38,"column":4},"end":{"line":38,"column":null}},"4":{"start":{"line":44,"column":4},"end":{"line":47,"column":null}},"5":{"start":{"line":32,"column":0},"end":{"line":32,"column":13}},"6":{"start":{"line":52,"column":42},"end":{"line":60,"column":32}},"7":{"start":{"line":62,"column":34},"end":{"line":62,"column":41}},"8":{"start":{"line":64,"column":34},"end":{"line":64,"column":41}},"9":{"start":{"line":66,"column":2},"end":{"line":71,"column":null}},"10":{"start":{"line":72,"column":2},"end":{"line":77,"column":null}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":34,"column":2},"end":{"line":34,"column":null}},"loc":{"start":{"line":35,"column":71},"end":{"line":36,"column":6}}},"1":{"name":"(anonymous_1)","decl":{"start":{"line":37,"column":2},"end":{"line":37,"column":8}},"loc":{"start":{"line":37,"column":68},"end":{"line":39,"column":3}}},"2":{"name":"(anonymous_2)","decl":{"start":{"line":41,"column":2},"end":{"line":41,"column":11}},"loc":{"start":{"line":42,"column":33},"end":{"line":48,"column":3}}},"3":{"name":"__type_tests","decl":{"start":{"line":51,"column":9},"end":{"line":51,"column":21}},"loc":{"start":{"line":51,"column":21},"end":{"line":78,"column":1}}}},"branchMap":{},"s":{"0":4,"1":13,"2":13,"3":5,"4":8,"5":4,"6":0,"7":0,"8":0,"9":0,"10":0},"f":{"0":13,"1":5,"2":8,"3":0},"b":{}} +} diff --git a/sdk/lib/coverage/lcov-report/base.css b/sdk/lib/coverage/lcov-report/base.css new file mode 100644 index 000000000..f418035b4 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/base.css @@ -0,0 +1,224 @@ +body, html { + margin:0; padding: 0; + height: 100%; +} +body { + font-family: Helvetica Neue, Helvetica, Arial; + font-size: 14px; + color:#333; +} +.small { font-size: 12px; } +*, *:after, *:before { + -webkit-box-sizing:border-box; + -moz-box-sizing:border-box; + box-sizing:border-box; + } +h1 { font-size: 20px; margin: 0;} +h2 { font-size: 14px; } +pre { + font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace; + margin: 0; + padding: 0; + -moz-tab-size: 2; + -o-tab-size: 2; + tab-size: 2; +} +a { color:#0074D9; text-decoration:none; } +a:hover { text-decoration:underline; } +.strong { font-weight: bold; } +.space-top1 { padding: 10px 0 0 0; } +.pad2y { padding: 20px 0; } +.pad1y { padding: 10px 0; } +.pad2x { padding: 0 20px; } +.pad2 { padding: 20px; } +.pad1 { padding: 10px; } +.space-left2 { padding-left:55px; } +.space-right2 { padding-right:20px; } +.center { text-align:center; } +.clearfix { display:block; } +.clearfix:after { + content:''; + display:block; + height:0; + clear:both; + visibility:hidden; + } +.fl { float: left; } +@media only screen and (max-width:640px) { + .col3 { width:100%; max-width:100%; } + .hide-mobile { display:none!important; } +} + +.quiet { + color: #7f7f7f; + color: rgba(0,0,0,0.5); +} +.quiet a { opacity: 0.7; } + +.fraction { + font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; + font-size: 10px; + color: #555; + background: #E8E8E8; + padding: 4px 5px; + border-radius: 3px; + vertical-align: middle; +} + +div.path a:link, div.path a:visited { color: #333; } +table.coverage { + border-collapse: collapse; + margin: 10px 0 0 0; + padding: 0; +} + +table.coverage td { + margin: 0; + padding: 0; + vertical-align: top; +} +table.coverage td.line-count { + text-align: right; + padding: 0 5px 0 20px; +} +table.coverage td.line-coverage { + text-align: right; + padding-right: 10px; + min-width:20px; +} + +table.coverage td span.cline-any { + display: inline-block; + padding: 0 5px; + width: 100%; +} +.missing-if-branch { + display: inline-block; + margin-right: 5px; + border-radius: 3px; + position: relative; + padding: 0 4px; + background: #333; + color: yellow; +} + +.skip-if-branch { + display: none; + margin-right: 10px; + position: relative; + padding: 0 4px; + background: #ccc; + color: white; +} +.missing-if-branch .typ, .skip-if-branch .typ { + color: inherit !important; +} +.coverage-summary { + border-collapse: collapse; + width: 100%; +} +.coverage-summary tr { border-bottom: 1px solid #bbb; } +.keyline-all { border: 1px solid #ddd; } +.coverage-summary td, .coverage-summary th { padding: 10px; } +.coverage-summary tbody { border: 1px solid #bbb; } +.coverage-summary td { border-right: 1px solid #bbb; } +.coverage-summary td:last-child { border-right: none; } +.coverage-summary th { + text-align: left; + font-weight: normal; + white-space: nowrap; +} +.coverage-summary th.file { border-right: none !important; } +.coverage-summary th.pct { } +.coverage-summary th.pic, +.coverage-summary th.abs, +.coverage-summary td.pct, +.coverage-summary td.abs { text-align: right; } +.coverage-summary td.file { white-space: nowrap; } +.coverage-summary td.pic { min-width: 120px !important; } +.coverage-summary tfoot td { } + +.coverage-summary .sorter { + height: 10px; + width: 7px; + display: inline-block; + margin-left: 0.5em; + background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent; +} +.coverage-summary .sorted .sorter { + background-position: 0 -20px; +} +.coverage-summary .sorted-desc .sorter { + background-position: 0 -10px; +} +.status-line { height: 10px; } +/* yellow */ +.cbranch-no { background: yellow !important; color: #111; } +/* dark red */ +.red.solid, .status-line.low, .low .cover-fill { background:#C21F39 } +.low .chart { border:1px solid #C21F39 } +.highlighted, +.highlighted .cstat-no, .highlighted .fstat-no, .highlighted .cbranch-no{ + background: #C21F39 !important; +} +/* medium red */ +.cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE } +/* light red */ +.low, .cline-no { background:#FCE1E5 } +/* light green */ +.high, .cline-yes { background:rgb(230,245,208) } +/* medium green */ +.cstat-yes { background:rgb(161,215,106) } +/* dark green */ +.status-line.high, .high .cover-fill { background:rgb(77,146,33) } +.high .chart { border:1px solid rgb(77,146,33) } +/* dark yellow (gold) */ +.status-line.medium, .medium .cover-fill { background: #f9cd0b; } +.medium .chart { border:1px solid #f9cd0b; } +/* light yellow */ +.medium { background: #fff4c2; } + +.cstat-skip { background: #ddd; color: #111; } +.fstat-skip { background: #ddd; color: #111 !important; } +.cbranch-skip { background: #ddd !important; color: #111; } + +span.cline-neutral { background: #eaeaea; } + +.coverage-summary td.empty { + opacity: .5; + padding-top: 4px; + padding-bottom: 4px; + line-height: 1; + color: #888; +} + +.cover-fill, .cover-empty { + display:inline-block; + height: 12px; +} +.chart { + line-height: 0; +} +.cover-empty { + background: white; +} +.cover-full { + border-right: none !important; +} +pre.prettyprint { + border: none !important; + padding: 0 !important; + margin: 0 !important; +} +.com { color: #999 !important; } +.ignore-none { color: #999; font-weight: normal; } + +.wrapper { + min-height: 100%; + height: auto !important; + height: 100%; + margin: 0 auto -48px; +} +.footer, .push { + height: 48px; +} diff --git a/sdk/lib/coverage/lcov-report/block-navigation.js b/sdk/lib/coverage/lcov-report/block-navigation.js new file mode 100644 index 000000000..cc1213023 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/block-navigation.js @@ -0,0 +1,87 @@ +/* eslint-disable */ +var jumpToCode = (function init() { + // Classes of code we would like to highlight in the file view + var missingCoverageClasses = ['.cbranch-no', '.cstat-no', '.fstat-no']; + + // Elements to highlight in the file listing view + var fileListingElements = ['td.pct.low']; + + // We don't want to select elements that are direct descendants of another match + var notSelector = ':not(' + missingCoverageClasses.join('):not(') + ') > '; // becomes `:not(a):not(b) > ` + + // Selecter that finds elements on the page to which we can jump + var selector = + fileListingElements.join(', ') + + ', ' + + notSelector + + missingCoverageClasses.join(', ' + notSelector); // becomes `:not(a):not(b) > a, :not(a):not(b) > b` + + // The NodeList of matching elements + var missingCoverageElements = document.querySelectorAll(selector); + + var currentIndex; + + function toggleClass(index) { + missingCoverageElements + .item(currentIndex) + .classList.remove('highlighted'); + missingCoverageElements.item(index).classList.add('highlighted'); + } + + function makeCurrent(index) { + toggleClass(index); + currentIndex = index; + missingCoverageElements.item(index).scrollIntoView({ + behavior: 'smooth', + block: 'center', + inline: 'center' + }); + } + + function goToPrevious() { + var nextIndex = 0; + if (typeof currentIndex !== 'number' || currentIndex === 0) { + nextIndex = missingCoverageElements.length - 1; + } else if (missingCoverageElements.length > 1) { + nextIndex = currentIndex - 1; + } + + makeCurrent(nextIndex); + } + + function goToNext() { + var nextIndex = 0; + + if ( + typeof currentIndex === 'number' && + currentIndex < missingCoverageElements.length - 1 + ) { + nextIndex = currentIndex + 1; + } + + makeCurrent(nextIndex); + } + + return function jump(event) { + if ( + document.getElementById('fileSearch') === document.activeElement && + document.activeElement != null + ) { + // if we're currently focused on the search input, we don't want to navigate + return; + } + + switch (event.which) { + case 78: // n + case 74: // j + goToNext(); + break; + case 66: // b + case 75: // k + case 80: // p + goToPrevious(); + break; + } + }; +})(); +window.addEventListener('keydown', jumpToCode); diff --git a/sdk/lib/coverage/lcov-report/config/builder/config.ts.html b/sdk/lib/coverage/lcov-report/config/builder/config.ts.html new file mode 100644 index 000000000..57a094a57 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/config/builder/config.ts.html @@ -0,0 +1,496 @@ + + + + + + Code coverage report for config/builder/config.ts + + + + + + + + + +
+
+

All files / config/builder config.ts

+
+ +
+ 78.57% + Statements + 11/14 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 75% + Functions + 3/4 +
+ + +
+ 78.57% + Lines + 11/14 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +2x +  +  +2x +  +  +1x +  +  +1x +  +  +1x +  +  +  +  +  +  +2x +  +  +2x +  +  +2x +2x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { ValueSpec } from "../configTypes"
+import { Value } from "./value"
+import { _ } from "../../util"
+import { Effects } from "../../types"
+import { Parser, object } from "ts-matches"
+ 
+export type LazyBuildOptions<Store> = {
+  effects: Effects
+}
+export type LazyBuild<Store, ExpectedOut> = (
+  options: LazyBuildOptions<Store>,
+) => Promise<ExpectedOut> | ExpectedOut
+ 
+// prettier-ignore
+export type ExtractConfigType<A extends Record<string, any> | Config<Record<string, any>, any> | Config<Record<string, any>, never>> = 
+  A extends Config<infer B, any> | Config<infer B, never> ? B :
+  A
+ 
+export type ConfigSpecOf<A extends Record<string, any>, Store = never> = {
+  [K in keyof A]: Value<A[K], Store>
+}
+ 
+export type MaybeLazyValues<A> = LazyBuild<any, A> | A
+/**
+ * Configs are the specs that are used by the os configuration form for this service.
+ * Here is an example of a simple configuration
+  ```ts
+    const smallConfig = Config.of({
+      test: Value.boolean({
+        name: "Test",
+        description: "This is the description for the test",
+        warning: null,
+        default: false,
+      }),
+    });
+  ```
+ 
+  The idea of a config is that now the form is going to ask for
+  Test: [ ] and the value is going to be checked as a boolean.
+  There are more complex values like selects, lists, and objects. See {@link Value}
+ 
+  Also, there is the ability to get a validator/parser from this config spec.
+  ```ts
+  const matchSmallConfig = smallConfig.validator();
+  type SmallConfig = typeof matchSmallConfig._TYPE;
+  ```
+ 
+  Here is an example of a more complex configuration which came from a configuration for a service
+  that works with bitcoin, like c-lightning.
+  ```ts
+ 
+    export const hostname = Value.string({
+  name: "Hostname",
+  default: null,
+  description: "Domain or IP address of bitcoin peer",
+  warning: null,
+  required: true,
+  masked: false,
+  placeholder: null,
+  pattern:
+    "(^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$)|((^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$)|(^[a-z2-7]{16}\\.onion$)|(^([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]$))",
+  patternDescription:
+    "Must be either a domain name, or an IPv4 or IPv6 address. Do not include protocol scheme (eg 'http://') or port.",
+});
+export const port = Value.number({
+  name: "Port",
+  default: null,
+  description: "Port that peer is listening on for inbound p2p connections",
+  warning: null,
+  required: false,
+  range: "[0,65535]",
+  integral: true,
+  units: null,
+  placeholder: null,
+});
+export const addNodesSpec = Config.of({ hostname: hostname, port: port });
+ 
+  ```
+ */
+export class Config<Type extends Record<string, any>, Store = never> {
+  private constructor(
+    private readonly spec: {
+      [K in keyof Type]: Value<Type[K], Store> | Value<Type[K], never>
+    },
+    public validator: Parser<unknown, Type>,
+  ) {}
+  async build(options: LazyBuildOptions<Store>) {
+    const answer = {} as {
+      [K in keyof Type]: ValueSpec
+    }
+    for (const k in this.spec) {
+      answer[k] = await this.spec[k].build(options as any)
+    }
+    return answer
+  }
+ 
+  static of<
+    Spec extends Record<string, Value<any, Store> | Value<any, never>>,
+    Store = never,
+  >(spec: Spec) {
+    const validatorObj = {} as {
+      [K in keyof Spec]: Parser<unknown, any>
+    }
+    for (const key in spec) {
+      validatorObj[key] = spec[key].validator
+    }
+    const validator = object(validatorObj)
+    return new Config<
+      {
+        [K in keyof Spec]: Spec[K] extends
+          | Value<infer T, Store>
+          | Value<infer T, never>
+          ? T
+          : never
+      },
+      Store
+    >(spec, validator as any)
+  }
+ 
+  /**
+   * Use this during the times that the input needs a more specific type.
+   * Used in types that the value/ variant/ list/ config is constructed somewhere else.
+  ```ts
+  const a = Config.text({
+    name: "a",
+    required: false,
+  })
+ 
+  return Config.of<Store>()({
+    myValue: a.withStore(),
+  })
+  ```
+   */
+  withStore<NewStore extends Store extends never ? any : Store>() {
+    return this as any as Config<Type, NewStore>
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/config/builder/index.html b/sdk/lib/coverage/lcov-report/config/builder/index.html new file mode 100644 index 000000000..c66a104b5 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/config/builder/index.html @@ -0,0 +1,146 @@ + + + + + + Code coverage report for config/builder + + + + + + + + + +
+
+

All files config/builder

+
+ +
+ 31.73% + Statements + 33/104 +
+ + +
+ 0% + Branches + 0/29 +
+ + +
+ 17.18% + Functions + 11/64 +
+ + +
+ 31.37% + Lines + 32/102 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
config.ts +
+
78.57%11/14100%0/075%3/478.57%11/14
list.ts +
+
70%14/20100%0/062.5%5/870%14/20
value.ts +
+
11.42%8/700%0/295.76%3/5210.29%7/68
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/config/builder/list.ts.html b/sdk/lib/coverage/lcov-report/config/builder/list.ts.html new file mode 100644 index 000000000..75eba036d --- /dev/null +++ b/sdk/lib/coverage/lcov-report/config/builder/list.ts.html @@ -0,0 +1,649 @@ + + + + + + Code coverage report for config/builder/list.ts + + + + + + + + + +
+
+

All files / config/builder list.ts

+
+ +
+ 70% + Statements + 14/20 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 62.5% + Functions + 5/8 +
+ + +
+ 70% + Lines + 14/20 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +2x +2x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +1x +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +1x +1x +1x +  +  +  +  +  +  +1x +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { Config, LazyBuild } from "./config"
+import {
+  ListValueSpecText,
+  Pattern,
+  RandomString,
+  UniqueBy,
+  ValueSpecList,
+  ValueSpecListOf,
+} from "../configTypes"
+import { Parser, arrayOf, number, string } from "ts-matches"
+/**
+ * Used as a subtype of Value.list
+```ts
+export const authorizationList = List.string({
+  "name": "Authorization",
+  "range": "[0,*)",
+  "default": [],
+  "description": "Username and hashed password for JSON-RPC connections. RPC clients connect using the usual http basic authentication.",
+  "warning": null
+}, {"masked":false,"placeholder":null,"pattern":"^[a-zA-Z0-9_-]+:([0-9a-fA-F]{2})+\\$([0-9a-fA-F]{2})+$","patternDescription":"Each item must be of the form \"<USERNAME>:<SALT>$<HASH>\"."});
+export const auth = Value.list(authorizationList);
+```
+*/
+export class List<Type, Store> {
+  private constructor(
+    public build: LazyBuild<Store, ValueSpecList>,
+    public validator: Parser<unknown, Type>,
+  ) {}
+  static text(
+    a: {
+      name: string
+      description?: string | null
+      warning?: string | null
+      /** Default = [] */
+      default?: string[]
+      minLength?: number | null
+      maxLength?: number | null
+    },
+    aSpec: {
+      /** Default = false */
+      masked?: boolean
+      placeholder?: string | null
+      minLength?: number | null
+      maxLength?: number | null
+      patterns: Pattern[]
+      /** Default = "text" */
+      inputmode?: ListValueSpecText["inputmode"]
+      generate?: null | RandomString
+    },
+  ) {
+    return new List<string[], never>(() => {
+      const spec = {
+        type: "text" as const,
+        placeholder: null,
+        minLength: null,
+        maxLength: null,
+        masked: false,
+        inputmode: "text" as const,
+        generate: null,
+        ...aSpec,
+      }
+      const built: ValueSpecListOf<"text"> = {
+        description: null,
+        warning: null,
+        default: [],
+        type: "list" as const,
+        minLength: null,
+        maxLength: null,
+        disabled: false,
+        ...a,
+        spec,
+      }
+      return built
+    }, arrayOf(string))
+  }
+  static dynamicText<Store = never>(
+    getA: LazyBuild<
+      Store,
+      {
+        name: string
+        description?: string | null
+        warning?: string | null
+        /** Default = [] */
+        default?: string[]
+        minLength?: number | null
+        maxLength?: number | null
+        disabled?: false | string
+        generate?: null | RandomString
+        spec: {
+          /** Default = false */
+          masked?: boolean
+          placeholder?: string | null
+          minLength?: number | null
+          maxLength?: number | null
+          patterns: Pattern[]
+          /** Default = "text" */
+          inputmode?: ListValueSpecText["inputmode"]
+        }
+      }
+    >,
+  ) {
+    return new List<string[], Store>(async (options) => {
+      const { spec: aSpec, ...a } = await getA(options)
+      const spec = {
+        type: "text" as const,
+        placeholder: null,
+        minLength: null,
+        maxLength: null,
+        masked: false,
+        inputmode: "text" as const,
+        generate: null,
+        ...aSpec,
+      }
+      const built: ValueSpecListOf<"text"> = {
+        description: null,
+        warning: null,
+        default: [],
+        type: "list" as const,
+        minLength: null,
+        maxLength: null,
+        disabled: false,
+        ...a,
+        spec,
+      }
+      return built
+    }, arrayOf(string))
+  }
+  static obj<Type extends Record<string, any>, Store>(
+    a: {
+      name: string
+      description?: string | null
+      warning?: string | null
+      /** Default [] */
+      default?: []
+      minLength?: number | null
+      maxLength?: number | null
+    },
+    aSpec: {
+      spec: Config<Type, Store>
+      displayAs?: null | string
+      uniqueBy?: null | UniqueBy
+    },
+  ) {
+    return new List<Type[], Store>(async (options) => {
+      const { spec: previousSpecSpec, ...restSpec } = aSpec
+      const specSpec = await previousSpecSpec.build(options)
+      const spec = {
+        type: "object" as const,
+        displayAs: null,
+        uniqueBy: null,
+        ...restSpec,
+        spec: specSpec,
+      }
+      const value = {
+        spec,
+        default: [],
+        ...a,
+      }
+      return {
+        description: null,
+        warning: null,
+        minLength: null,
+        maxLength: null,
+        type: "list" as const,
+        disabled: false,
+        ...value,
+      }
+    }, arrayOf(aSpec.spec.validator))
+  }
+ 
+  /**
+   * Use this during the times that the input needs a more specific type.
+   * Used in types that the value/ variant/ list/ config is constructed somewhere else.
+  ```ts
+  const a = Config.text({
+    name: "a",
+    required: false,
+  })
+ 
+  return Config.of<Store>()({
+    myValue: a.withStore(),
+  })
+  ```
+   */
+  withStore<NewStore extends Store extends never ? any : Store>() {
+    return this as any as List<Type, NewStore>
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/config/builder/value.ts.html b/sdk/lib/coverage/lcov-report/config/builder/value.ts.html new file mode 100644 index 000000000..2aa48d6e0 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/config/builder/value.ts.html @@ -0,0 +1,2434 @@ + + + + + + Code coverage report for config/builder/value.ts + + + + + + + + + +
+
+

All files / config/builder value.ts

+
+ +
+ 11.42% + Statements + 8/70 +
+ + +
+ 0% + Branches + 0/29 +
+ + +
+ 5.76% + Functions + 3/52 +
+ + +
+ 10.29% + Lines + 7/68 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335 +336 +337 +338 +339 +340 +341 +342 +343 +344 +345 +346 +347 +348 +349 +350 +351 +352 +353 +354 +355 +356 +357 +358 +359 +360 +361 +362 +363 +364 +365 +366 +367 +368 +369 +370 +371 +372 +373 +374 +375 +376 +377 +378 +379 +380 +381 +382 +383 +384 +385 +386 +387 +388 +389 +390 +391 +392 +393 +394 +395 +396 +397 +398 +399 +400 +401 +402 +403 +404 +405 +406 +407 +408 +409 +410 +411 +412 +413 +414 +415 +416 +417 +418 +419 +420 +421 +422 +423 +424 +425 +426 +427 +428 +429 +430 +431 +432 +433 +434 +435 +436 +437 +438 +439 +440 +441 +442 +443 +444 +445 +446 +447 +448 +449 +450 +451 +452 +453 +454 +455 +456 +457 +458 +459 +460 +461 +462 +463 +464 +465 +466 +467 +468 +469 +470 +471 +472 +473 +474 +475 +476 +477 +478 +479 +480 +481 +482 +483 +484 +485 +486 +487 +488 +489 +490 +491 +492 +493 +494 +495 +496 +497 +498 +499 +500 +501 +502 +503 +504 +505 +506 +507 +508 +509 +510 +511 +512 +513 +514 +515 +516 +517 +518 +519 +520 +521 +522 +523 +524 +525 +526 +527 +528 +529 +530 +531 +532 +533 +534 +535 +536 +537 +538 +539 +540 +541 +542 +543 +544 +545 +546 +547 +548 +549 +550 +551 +552 +553 +554 +555 +556 +557 +558 +559 +560 +561 +562 +563 +564 +565 +566 +567 +568 +569 +570 +571 +572 +573 +574 +575 +576 +577 +578 +579 +580 +581 +582 +583 +584 +585 +586 +587 +588 +589 +590 +591 +592 +593 +594 +595 +596 +597 +598 +599 +600 +601 +602 +603 +604 +605 +606 +607 +608 +609 +610 +611 +612 +613 +614 +615 +616 +617 +618 +619 +620 +621 +622 +623 +624 +625 +626 +627 +628 +629 +630 +631 +632 +633 +634 +635 +636 +637 +638 +639 +640 +641 +642 +643 +644 +645 +646 +647 +648 +649 +650 +651 +652 +653 +654 +655 +656 +657 +658 +659 +660 +661 +662 +663 +664 +665 +666 +667 +668 +669 +670 +671 +672 +673 +674 +675 +676 +677 +678 +679 +680 +681 +682 +683 +684 +685 +686 +687 +688 +689 +690 +691 +692 +693 +694 +695 +696 +697 +698 +699 +700 +701 +702 +703 +704 +705 +706 +707 +708 +709 +710 +711 +712 +713 +714 +715 +716 +717 +718 +719 +720 +721 +722 +723 +724 +725 +726 +727 +728 +729 +730 +731 +732 +733 +734 +735 +736 +737 +738 +739 +740 +741 +742 +743 +744 +745 +746 +747 +748 +749 +750 +751 +752 +753 +754 +755 +756 +757 +758 +759 +760 +761 +762 +763 +764 +765 +766 +767 +768 +769 +770 +771 +772 +773 +774 +775 +776 +777 +778 +779 +780 +781 +782 +783 +784  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +2x +2x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +2x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { Config, LazyBuild, LazyBuildOptions } from "./config"
+import { List } from "./list"
+import { Variants } from "./variants"
+import {
+  FilePath,
+  Pattern,
+  RandomString,
+  ValueSpec,
+  ValueSpecDatetime,
+  ValueSpecText,
+  ValueSpecTextarea,
+} from "../configTypes"
+import { DefaultString } from "../configTypes"
+import { _ } from "../../util"
+import {
+  Parser,
+  anyOf,
+  arrayOf,
+  boolean,
+  literal,
+  literals,
+  number,
+  object,
+  string,
+  unknown,
+} from "ts-matches"
+import { once } from "../../util/once"
+ 
+export type RequiredDefault<A> =
+  | false
+  | {
+      default: A | null
+    }
+ 
+function requiredLikeToAbove<Input extends RequiredDefault<A>, A>(
+  requiredLike: Input,
+) {
+  // prettier-ignore
+  return {
+    required: (typeof requiredLike === 'object' ? true : requiredLike) as (
+      Input extends { default: unknown} ? true:
+      Input extends true ? true :
+      false
+    ),
+    default:(typeof requiredLike === 'object' ? requiredLike.default : null) as (
+      Input extends { default: infer Default } ? Default :
+      null
+    )
+  };
+}
+type AsRequired<Type, MaybeRequiredType> = MaybeRequiredType extends
+  | { default: unknown }
+  | never
+  ? Type
+  : Type | null | undefined
+ 
+type InputAsRequired<A, Type> = A extends
+  | { required: { default: any } | never }
+  | never
+  ? Type
+  : Type | null | undefined
+const testForAsRequiredParser = once(
+  () => object({ required: object({ default: unknown }) }).test,
+)
+function asRequiredParser<
+  Type,
+  Input,
+  Return extends
+    | Parser<unknown, Type>
+    | Parser<unknown, Type | null | undefined>,
+>(parser: Parser<unknown, Type>, input: Input): Return {
+  Iif (testForAsRequiredParser()(input)) return parser as any
+  return parser.optional() as any
+}
+ 
+/**
+ * A value is going to be part of the form in the FE of the OS.
+ * Something like a boolean, a string, a number, etc.
+ * in the fe it will ask for the name of value, and use the rest of the value to determine how to render it.
+ * While writing with a value, you will start with `Value.` then let the IDE suggest the rest.
+ * for things like string, the options are going to be in {}.
+ * Keep an eye out for another config builder types as params.
+ * Note, usually this is going to be used in a `Config` {@link Config} builder.
+ ```ts
+const username = Value.string({
+  name: "Username",
+  default: "bitcoin",
+  description: "The username for connecting to Bitcoin over RPC.",
+  warning: null,
+  required: true,
+  masked: true,
+  placeholder: null,
+  pattern: "^[a-zA-Z0-9_]+$",
+  patternDescription: "Must be alphanumeric (can contain underscore).",
+});
+ ```
+ */
+export class Value<Type, Store> {
+  protected constructor(
+    public build: LazyBuild<Store, ValueSpec>,
+    public validator: Parser<unknown, Type>,
+  ) {}
+  static toggle(a: {
+    name: string
+    description?: string | null
+    warning?: string | null
+    default: boolean
+    /**  Immutable means it can only be configed at the first config then never again 
+    Default is false */
+    immutable?: boolean
+  }) {
+    return new Value<boolean, never>(
+      async () => ({
+        description: null,
+        warning: null,
+        type: "toggle" as const,
+        disabled: false,
+        immutable: a.immutable ?? false,
+        ...a,
+      }),
+      boolean,
+    )
+  }
+  static dynamicToggle<Store = never>(
+    a: LazyBuild<
+      Store,
+      {
+        name: string
+        description?: string | null
+        warning?: string | null
+        default: boolean
+        disabled?: false | string
+      }
+    >,
+  ) {
+    return new Value<boolean, Store>(
+      async (options) => ({
+        description: null,
+        warning: null,
+        type: "toggle" as const,
+        disabled: false,
+        immutable: false,
+        ...(await a(options)),
+      }),
+      boolean,
+    )
+  }
+  static text<Required extends RequiredDefault<DefaultString>>(a: {
+    name: string
+    description?: string | null
+    warning?: string | null
+    required: Required
+ 
+    /** Default = false */
+    masked?: boolean
+    placeholder?: string | null
+    minLength?: number | null
+    maxLength?: number | null
+    patterns?: Pattern[]
+    /** Default = 'text' */
+    inputmode?: ValueSpecText["inputmode"]
+    /**  Immutable means it can only be configured at the first config then never again
+     * Default is false
+     */
+    immutable?: boolean
+    generate?: null | RandomString
+  }) {
+    return new Value<AsRequired<string, Required>, never>(
+      async () => ({
+        type: "text" as const,
+        description: null,
+        warning: null,
+        masked: false,
+        placeholder: null,
+        minLength: null,
+        maxLength: null,
+        patterns: [],
+        inputmode: "text",
+        disabled: false,
+        immutable: a.immutable ?? false,
+        generate: a.generate ?? null,
+        ...a,
+        ...requiredLikeToAbove(a.required),
+      }),
+      asRequiredParser(string, a),
+    )
+  }
+  static dynamicText<Store = never>(
+    getA: LazyBuild<
+      Store,
+      {
+        name: string
+        description?: string | null
+        warning?: string | null
+        required: RequiredDefault<DefaultString>
+ 
+        /** Default = false */
+        masked?: boolean
+        placeholder?: string | null
+        minLength?: number | null
+        maxLength?: number | null
+        patterns?: Pattern[]
+        /** Default = 'text' */
+        inputmode?: ValueSpecText["inputmode"]
+        disabled?: string | false
+        /**  Immutable means it can only be configured at the first config then never again
+         * Default is false
+         */
+        generate?: null | RandomString
+      }
+    >,
+  ) {
+    return new Value<string | null | undefined, Store>(async (options) => {
+      const a = await getA(options)
+      return {
+        type: "text" as const,
+        description: null,
+        warning: null,
+        masked: false,
+        placeholder: null,
+        minLength: null,
+        maxLength: null,
+        patterns: [],
+        inputmode: "text",
+        disabled: false,
+        immutable: false,
+        generate: a.generate ?? null,
+        ...a,
+        ...requiredLikeToAbove(a.required),
+      }
+    }, string.optional())
+  }
+  static textarea(a: {
+    name: string
+    description?: string | null
+    warning?: string | null
+    required: boolean
+    minLength?: number | null
+    maxLength?: number | null
+    placeholder?: string | null
+    /**  Immutable means it can only be configed at the first config then never again 
+    Default is false */
+    immutable?: boolean
+  }) {
+    return new Value<string, never>(async () => {
+      const built: ValueSpecTextarea = {
+        description: null,
+        warning: null,
+        minLength: null,
+        maxLength: null,
+        placeholder: null,
+        type: "textarea" as const,
+        disabled: false,
+        immutable: a.immutable ?? false,
+        ...a,
+      }
+      return built
+    }, string)
+  }
+  static dynamicTextarea<Store = never>(
+    getA: LazyBuild<
+      Store,
+      {
+        name: string
+        description?: string | null
+        warning?: string | null
+        required: boolean
+        minLength?: number | null
+        maxLength?: number | null
+        placeholder?: string | null
+        disabled?: false | string
+      }
+    >,
+  ) {
+    return new Value<string, Store>(async (options) => {
+      const a = await getA(options)
+      return {
+        description: null,
+        warning: null,
+        minLength: null,
+        maxLength: null,
+        placeholder: null,
+        type: "textarea" as const,
+        disabled: false,
+        immutable: false,
+        ...a,
+      }
+    }, string)
+  }
+  static number<Required extends RequiredDefault<number>>(a: {
+    name: string
+    description?: string | null
+    warning?: string | null
+    required: Required
+    min?: number | null
+    max?: number | null
+    /** Default = '1' */
+    step?: number | null
+    integer: boolean
+    units?: string | null
+    placeholder?: string | null
+    /**  Immutable means it can only be configed at the first config then never again 
+    Default is false */
+    immutable?: boolean
+  }) {
+    return new Value<AsRequired<number, Required>, never>(
+      () => ({
+        type: "number" as const,
+        description: null,
+        warning: null,
+        min: null,
+        max: null,
+        step: null,
+        units: null,
+        placeholder: null,
+        disabled: false,
+        immutable: a.immutable ?? false,
+        ...a,
+        ...requiredLikeToAbove(a.required),
+      }),
+      asRequiredParser(number, a),
+    )
+  }
+  static dynamicNumber<Store = never>(
+    getA: LazyBuild<
+      Store,
+      {
+        name: string
+        description?: string | null
+        warning?: string | null
+        required: RequiredDefault<number>
+        min?: number | null
+        max?: number | null
+        /** Default = '1' */
+        step?: number | null
+        integer: boolean
+        units?: string | null
+        placeholder?: string | null
+        disabled?: false | string
+      }
+    >,
+  ) {
+    return new Value<number | null | undefined, Store>(async (options) => {
+      const a = await getA(options)
+      return {
+        type: "number" as const,
+        description: null,
+        warning: null,
+        min: null,
+        max: null,
+        step: null,
+        units: null,
+        placeholder: null,
+        disabled: false,
+        immutable: false,
+        ...a,
+        ...requiredLikeToAbove(a.required),
+      }
+    }, number.optional())
+  }
+  static color<Required extends RequiredDefault<string>>(a: {
+    name: string
+    description?: string | null
+    warning?: string | null
+    required: Required
+    /**  Immutable means it can only be configed at the first config then never again 
+    Default is false */
+    immutable?: boolean
+  }) {
+    return new Value<AsRequired<string, Required>, never>(
+      () => ({
+        type: "color" as const,
+        description: null,
+        warning: null,
+        disabled: false,
+        immutable: a.immutable ?? false,
+        ...a,
+        ...requiredLikeToAbove(a.required),
+      }),
+ 
+      asRequiredParser(string, a),
+    )
+  }
+ 
+  static dynamicColor<Store = never>(
+    getA: LazyBuild<
+      Store,
+      {
+        name: string
+        description?: string | null
+        warning?: string | null
+        required: RequiredDefault<string>
+        disabled?: false | string
+      }
+    >,
+  ) {
+    return new Value<string | null | undefined, Store>(async (options) => {
+      const a = await getA(options)
+      return {
+        type: "color" as const,
+        description: null,
+        warning: null,
+        disabled: false,
+        immutable: false,
+        ...a,
+        ...requiredLikeToAbove(a.required),
+      }
+    }, string.optional())
+  }
+  static datetime<Required extends RequiredDefault<string>>(a: {
+    name: string
+    description?: string | null
+    warning?: string | null
+    required: Required
+    /** Default = 'datetime-local' */
+    inputmode?: ValueSpecDatetime["inputmode"]
+    min?: string | null
+    max?: string | null
+    /**  Immutable means it can only be configed at the first config then never again 
+    Default is false */
+    immutable?: boolean
+  }) {
+    return new Value<AsRequired<string, Required>, never>(
+      () => ({
+        type: "datetime" as const,
+        description: null,
+        warning: null,
+        inputmode: "datetime-local",
+        min: null,
+        max: null,
+        step: null,
+        disabled: false,
+        immutable: a.immutable ?? false,
+        ...a,
+        ...requiredLikeToAbove(a.required),
+      }),
+      asRequiredParser(string, a),
+    )
+  }
+  static dynamicDatetime<Store = never>(
+    getA: LazyBuild<
+      Store,
+      {
+        name: string
+        description?: string | null
+        warning?: string | null
+        required: RequiredDefault<string>
+        /** Default = 'datetime-local' */
+        inputmode?: ValueSpecDatetime["inputmode"]
+        min?: string | null
+        max?: string | null
+        disabled?: false | string
+      }
+    >,
+  ) {
+    return new Value<string | null | undefined, Store>(async (options) => {
+      const a = await getA(options)
+      return {
+        type: "datetime" as const,
+        description: null,
+        warning: null,
+        inputmode: "datetime-local",
+        min: null,
+        max: null,
+        disabled: false,
+        immutable: false,
+        ...a,
+        ...requiredLikeToAbove(a.required),
+      }
+    }, string.optional())
+  }
+  static select<
+    Required extends RequiredDefault<string>,
+    B extends Record<string, string>,
+  >(a: {
+    name: string
+    description?: string | null
+    warning?: string | null
+    required: Required
+    values: B
+    /**
+     * Disabled:  false means that there is nothing disabled, good to modify
+     *           string means that this is the message displayed and the whole thing is disabled
+     *           string[] means that the options are disabled
+     */
+    disabled?: false | string | (string & keyof B)[]
+    /**  Immutable means it can only be configed at the first config then never again 
+    Default is false */
+    immutable?: boolean
+  }) {
+    return new Value<AsRequired<keyof B, Required>, never>(
+      () => ({
+        description: null,
+        warning: null,
+        type: "select" as const,
+        disabled: false,
+        immutable: a.immutable ?? false,
+        ...a,
+        ...requiredLikeToAbove(a.required),
+      }),
+      asRequiredParser(
+        anyOf(
+          ...Object.keys(a.values).map((x: keyof B & string) => literal(x)),
+        ),
+        a,
+      ) as any,
+    )
+  }
+  static dynamicSelect<Store = never>(
+    getA: LazyBuild<
+      Store,
+      {
+        name: string
+        description?: string | null
+        warning?: string | null
+        required: RequiredDefault<string>
+        values: Record<string, string>
+        /**
+         * Disabled:  false means that there is nothing disabled, good to modify
+         *           string means that this is the message displayed and the whole thing is disabled
+         *           string[] means that the options are disabled
+         */
+        disabled?: false | string | string[]
+      }
+    >,
+  ) {
+    return new Value<string | null | undefined, Store>(async (options) => {
+      const a = await getA(options)
+      return {
+        description: null,
+        warning: null,
+        type: "select" as const,
+        disabled: false,
+        immutable: false,
+        ...a,
+        ...requiredLikeToAbove(a.required),
+      }
+    }, string.optional())
+  }
+  static multiselect<Values extends Record<string, string>>(a: {
+    name: string
+    description?: string | null
+    warning?: string | null
+    default: string[]
+    values: Values
+    minLength?: number | null
+    maxLength?: number | null
+    /**  Immutable means it can only be configed at the first config then never again 
+    Default is false */
+    immutable?: boolean
+    /**
+     * Disabled:  false means that there is nothing disabled, good to modify
+     *           string means that this is the message displayed and the whole thing is disabled
+     *           string[] means that the options are disabled
+     */
+    disabled?: false | string | (string & keyof Values)[]
+  }) {
+    return new Value<(keyof Values)[], never>(
+      () => ({
+        type: "multiselect" as const,
+        minLength: null,
+        maxLength: null,
+        warning: null,
+        description: null,
+        disabled: false,
+        immutable: a.immutable ?? false,
+        ...a,
+      }),
+      arrayOf(
+        literals(...(Object.keys(a.values) as any as [keyof Values & string])),
+      ),
+    )
+  }
+  static dynamicMultiselect<Store = never>(
+    getA: LazyBuild<
+      Store,
+      {
+        name: string
+        description?: string | null
+        warning?: string | null
+        default: string[]
+        values: Record<string, string>
+        minLength?: number | null
+        maxLength?: number | null
+        /**
+         * Disabled:  false means that there is nothing disabled, good to modify
+         *           string means that this is the message displayed and the whole thing is disabled
+         *           string[] means that the options are disabled
+         */
+        disabled?: false | string | string[]
+      }
+    >,
+  ) {
+    return new Value<string[], Store>(async (options) => {
+      const a = await getA(options)
+      return {
+        type: "multiselect" as const,
+        minLength: null,
+        maxLength: null,
+        warning: null,
+        description: null,
+        disabled: false,
+        immutable: false,
+        ...a,
+      }
+    }, arrayOf(string))
+  }
+  static object<Type extends Record<string, any>, Store>(
+    a: {
+      name: string
+      description?: string | null
+      warning?: string | null
+    },
+    spec: Config<Type, Store>,
+  ) {
+    return new Value<Type, Store>(async (options) => {
+      const built = await spec.build(options as any)
+      return {
+        type: "object" as const,
+        description: null,
+        warning: null,
+        ...a,
+        spec: built,
+      }
+    }, spec.validator)
+  }
+  static file<Required extends RequiredDefault<string>, Store>(a: {
+    name: string
+    description?: string | null
+    warning?: string | null
+    extensions: string[]
+    required: Required
+  }) {
+    const buildValue = {
+      type: "file" as const,
+      description: null,
+      warning: null,
+      ...a,
+    }
+    return new Value<AsRequired<FilePath, Required>, Store>(
+      () => ({
+        ...buildValue,
+ 
+        ...requiredLikeToAbove(a.required),
+      }),
+      asRequiredParser(object({ filePath: string }), a),
+    )
+  }
+  static dynamicFile<Required extends boolean, Store>(
+    a: LazyBuild<
+      Store,
+      {
+        name: string
+        description?: string | null
+        warning?: string | null
+        extensions: string[]
+        required: Required
+      }
+    >,
+  ) {
+    return new Value<string | null | undefined, Store>(
+      async (options) => ({
+        type: "file" as const,
+        description: null,
+        warning: null,
+        ...(await a(options)),
+      }),
+      string.optional(),
+    )
+  }
+  static union<Required extends RequiredDefault<string>, Type, Store>(
+    a: {
+      name: string
+      description?: string | null
+      warning?: string | null
+      required: Required
+      /**  Immutable means it can only be configed at the first config then never again 
+      Default is false */
+      immutable?: boolean
+      /**
+       * Disabled:  false means that there is nothing disabled, good to modify
+       *           string means that this is the message displayed and the whole thing is disabled
+       *           string[] means that the options are disabled
+       */
+      disabled?: false | string | string[]
+    },
+    aVariants: Variants<Type, Store>,
+  ) {
+    return new Value<AsRequired<Type, Required>, Store>(
+      async (options) => ({
+        type: "union" as const,
+        description: null,
+        warning: null,
+        disabled: false,
+        ...a,
+        variants: await aVariants.build(options as any),
+        ...requiredLikeToAbove(a.required),
+        immutable: a.immutable ?? false,
+      }),
+      asRequiredParser(aVariants.validator, a),
+    )
+  }
+  static filteredUnion<
+    Required extends RequiredDefault<string>,
+    Type extends Record<string, any>,
+    Store = never,
+  >(
+    getDisabledFn: LazyBuild<Store, string[] | false | string>,
+    a: {
+      name: string
+      description?: string | null
+      warning?: string | null
+      required: Required
+    },
+    aVariants: Variants<Type, Store> | Variants<Type, never>,
+  ) {
+    return new Value<AsRequired<Type, Required>, Store>(
+      async (options) => ({
+        type: "union" as const,
+        description: null,
+        warning: null,
+        ...a,
+        variants: await aVariants.build(options as any),
+        ...requiredLikeToAbove(a.required),
+        disabled: (await getDisabledFn(options)) || false,
+        immutable: false,
+      }),
+      asRequiredParser(aVariants.validator, a),
+    )
+  }
+  static dynamicUnion<
+    Required extends RequiredDefault<string>,
+    Type extends Record<string, any>,
+    Store = never,
+  >(
+    getA: LazyBuild<
+      Store,
+      {
+        disabled: string[] | false | string
+        name: string
+        description?: string | null
+        warning?: string | null
+        required: Required
+      }
+    >,
+    aVariants: Variants<Type, Store> | Variants<Type, never>,
+  ) {
+    return new Value<Type | null | undefined, Store>(async (options) => {
+      const newValues = await getA(options)
+      return {
+        type: "union" as const,
+        description: null,
+        warning: null,
+        ...newValues,
+        variants: await aVariants.build(options as any),
+        ...requiredLikeToAbove(newValues.required),
+        immutable: false,
+      }
+    }, aVariants.validator.optional())
+  }
+ 
+  static list<Type, Store>(a: List<Type, Store>) {
+    return new Value<Type, Store>((options) => a.build(options), a.validator)
+  }
+ 
+  /**
+   * Use this during the times that the input needs a more specific type.
+   * Used in types that the value/ variant/ list/ config is constructed somewhere else.
+  ```ts
+  const a = Config.text({
+    name: "a",
+    required: false,
+  })
+ 
+  return Config.of<Store>()({
+    myValue: a.withStore(),
+  })
+  ```
+   */
+  withStore<NewStore extends Store extends never ? any : Store>() {
+    return this as any as Value<Type, NewStore>
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/config/configTypes.ts.html b/sdk/lib/coverage/lcov-report/config/configTypes.ts.html new file mode 100644 index 000000000..bfd95deb5 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/config/configTypes.ts.html @@ -0,0 +1,919 @@ + + + + + + Code coverage report for config/configTypes.ts + + + + + + + + + +
+
+

All files / config configTypes.ts

+
+ +
+ 100% + Statements + 4/4 +
+ + +
+ 100% + Branches + 2/2 +
+ + +
+ 100% + Functions + 1/1 +
+ + +
+ 100% + Lines + 4/4 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +3x +  +1x +  +  +1x +  + 
export type InputSpec = Record<string, ValueSpec>
+export type ValueType =
+  | "text"
+  | "textarea"
+  | "number"
+  | "color"
+  | "datetime"
+  | "toggle"
+  | "select"
+  | "multiselect"
+  | "list"
+  | "object"
+  | "file"
+  | "union"
+export type ValueSpec = ValueSpecOf<ValueType>
+/** core spec types. These types provide the metadata for performing validations */
+// prettier-ignore
+export type ValueSpecOf<T extends ValueType> = 
+  T extends "text" ? ValueSpecText : 
+  T extends "textarea" ? ValueSpecTextarea : 
+  T extends "number" ? ValueSpecNumber : 
+  T extends "color" ? ValueSpecColor : 
+  T extends "datetime" ? ValueSpecDatetime : 
+  T extends "toggle" ? ValueSpecToggle : 
+  T extends "select" ? ValueSpecSelect : 
+  T extends "multiselect" ? ValueSpecMultiselect : 
+  T extends "list" ? ValueSpecList : 
+  T extends "object" ? ValueSpecObject : 
+  T extends "file" ? ValueSpecFile : 
+  T extends "union" ? ValueSpecUnion : 
+  never
+ 
+export type ValueSpecText = {
+  name: string
+  description: string | null
+  warning: string | null
+ 
+  type: "text"
+  patterns: Pattern[]
+  minLength: number | null
+  maxLength: number | null
+  masked: boolean
+ 
+  inputmode: "text" | "email" | "tel" | "url"
+  placeholder: string | null
+ 
+  required: boolean
+  default: DefaultString | null
+  disabled: false | string
+  generate: null | RandomString
+  /** Immutable means it can only be configured at the first config then never again */
+  immutable: boolean
+}
+export type ValueSpecTextarea = {
+  name: string
+  description: string | null
+  warning: string | null
+ 
+  type: "textarea"
+  placeholder: string | null
+  minLength: number | null
+  maxLength: number | null
+  required: boolean
+  disabled: false | string
+  /** Immutable means it can only be configured at the first config then never again */
+  immutable: boolean
+}
+ 
+export type FilePath = {
+  filePath: string
+}
+export type ValueSpecNumber = {
+  type: "number"
+  min: number | null
+  max: number | null
+  integer: boolean
+  step: number | null
+  units: string | null
+  placeholder: string | null
+  name: string
+  description: string | null
+  warning: string | null
+  required: boolean
+  default: number | null
+  disabled: false | string
+  /** Immutable means it can only be configured at the first config then never again */
+  immutable: boolean
+}
+export type ValueSpecColor = {
+  name: string
+  description: string | null
+  warning: string | null
+ 
+  type: "color"
+  required: boolean
+  default: string | null
+  disabled: false | string
+  /** Immutable means it can only be configured at the first config then never again */
+  immutable: boolean
+}
+export type ValueSpecDatetime = {
+  name: string
+  description: string | null
+  warning: string | null
+  type: "datetime"
+  required: boolean
+  inputmode: "date" | "time" | "datetime-local"
+  min: string | null
+  max: string | null
+  default: string | null
+  disabled: false | string
+  /** Immutable means it can only be configured at the first config then never again */
+  immutable: boolean
+}
+export type ValueSpecSelect = {
+  values: Record<string, string>
+  name: string
+  description: string | null
+  warning: string | null
+  type: "select"
+  required: boolean
+  default: string | null
+  /**
+   * Disabled:  false means that there is nothing disabled, good to modify
+   *           string means that this is the message displayed and the whole thing is disabled
+   *           string[] means that the options are disabled
+   */
+  disabled: false | string | string[]
+  /** Immutable means it can only be configured at the first config then never again */
+  immutable: boolean
+}
+export type ValueSpecMultiselect = {
+  values: Record<string, string>
+ 
+  name: string
+  description: string | null
+  warning: string | null
+ 
+  type: "multiselect"
+  minLength: number | null
+  maxLength: number | null
+  /**
+   * Disabled:  false means that there is nothing disabled, good to modify
+   *           string means that this is the message displayed and the whole thing is disabled
+   *           string[] means that the options are disabled
+   */
+  disabled: false | string | string[]
+  default: string[]
+  /** Immutable means it can only be configured at the first config then never again */
+  immutable: boolean
+}
+export type ValueSpecToggle = {
+  name: string
+  description: string | null
+  warning: string | null
+ 
+  type: "toggle"
+  default: boolean | null
+  disabled: false | string
+  /** Immutable means it can only be configured at the first config then never again */
+  immutable: boolean
+}
+export type ValueSpecUnion = {
+  name: string
+  description: string | null
+  warning: string | null
+ 
+  type: "union"
+  variants: Record<
+    string,
+    {
+      name: string
+      spec: InputSpec
+    }
+  >
+  /**
+   * Disabled:  false means that there is nothing disabled, good to modify
+   *           string means that this is the message displayed and the whole thing is disabled
+   *           string[] means that the options are disabled
+   */
+  disabled: false | string | string[]
+  required: boolean
+  default: string | null
+  /** Immutable means it can only be configured at the first config then never again */
+  immutable: boolean
+}
+export type ValueSpecFile = {
+  name: string
+  description: string | null
+  warning: string | null
+  type: "file"
+  extensions: string[]
+  required: boolean
+}
+export type ValueSpecObject = {
+  name: string
+  description: string | null
+  warning: string | null
+  type: "object"
+  spec: InputSpec
+}
+export type ListValueSpecType = "text" | "object"
+/** represents a spec for the values of a list */
+// prettier-ignore
+export type ListValueSpecOf<T extends ListValueSpecType> = 
+  T extends "text" ? ListValueSpecText :
+  T extends "object" ? ListValueSpecObject :
+  never
+/** represents a spec for a list */
+export type ValueSpecList = ValueSpecListOf<ListValueSpecType>
+export type ValueSpecListOf<T extends ListValueSpecType> = {
+  name: string
+  description: string | null
+  warning: string | null
+  type: "list"
+  spec: ListValueSpecOf<T>
+  minLength: number | null
+  maxLength: number | null
+  disabled: false | string
+  default:
+    | string[]
+    | DefaultString[]
+    | Record<string, unknown>[]
+    | readonly string[]
+    | readonly DefaultString[]
+    | readonly Record<string, unknown>[]
+}
+export type Pattern = {
+  regex: string
+  description: string
+}
+export type ListValueSpecText = {
+  type: "text"
+  patterns: Pattern[]
+  minLength: number | null
+  maxLength: number | null
+  masked: boolean
+ 
+  generate: null | RandomString
+  inputmode: "text" | "email" | "tel" | "url"
+  placeholder: string | null
+}
+ 
+export type ListValueSpecObject = {
+  type: "object"
+  /** this is a mapped type of the config object at this level, replacing the object's values with specs on those values */
+  spec: InputSpec
+  /** indicates whether duplicates can be permitted in the list */
+  uniqueBy: UniqueBy
+  /** this should be a handlebars template which can make use of the entire config which corresponds to 'spec' */
+  displayAs: string | null
+}
+export type UniqueBy =
+  | null
+  | string
+  | {
+      any: readonly UniqueBy[] | UniqueBy[]
+    }
+  | {
+      all: readonly UniqueBy[] | UniqueBy[]
+    }
+export type DefaultString = string | RandomString
+export type RandomString = {
+  charset: string
+  len: number
+}
+// sometimes the type checker needs just a little bit of help
+export function isValueSpecListOf<S extends ListValueSpecType>(
+  t: ValueSpec,
+  s: S,
+): t is ValueSpecListOf<S> & { spec: ListValueSpecOf<S> } {
+  return "spec" in t && t.spec.type === s
+}
+export const unionSelectKey = "unionSelectKey" as const
+export type UnionSelectKey = typeof unionSelectKey
+ 
+export const unionValueKey = "unionValueKey" as const
+export type UnionValueKey = typeof unionValueKey
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/config/index.html b/sdk/lib/coverage/lcov-report/config/index.html new file mode 100644 index 000000000..2855ae4b0 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/config/index.html @@ -0,0 +1,116 @@ + + + + + + Code coverage report for config + + + + + + + + + +
+
+

All files config

+
+ +
+ 100% + Statements + 4/4 +
+ + +
+ 100% + Branches + 2/2 +
+ + +
+ 100% + Functions + 1/1 +
+ + +
+ 100% + Lines + 4/4 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
configTypes.ts +
+
100%4/4100%2/2100%1/1100%4/4
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/emverLite/index.html b/sdk/lib/coverage/lcov-report/emverLite/index.html new file mode 100644 index 000000000..8a1c7150b --- /dev/null +++ b/sdk/lib/coverage/lcov-report/emverLite/index.html @@ -0,0 +1,116 @@ + + + + + + Code coverage report for emverLite + + + + + + + + + +
+
+

All files emverLite

+
+ +
+ 96.99% + Statements + 129/133 +
+ + +
+ 91.89% + Branches + 34/37 +
+ + +
+ 97.56% + Functions + 40/41 +
+ + +
+ 97.65% + Lines + 125/128 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
mod.ts +
+
96.99%129/13391.89%34/3797.56%40/4197.65%125/128
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/emverLite/mod.ts.html b/sdk/lib/coverage/lcov-report/emverLite/mod.ts.html new file mode 100644 index 000000000..e3f1943e0 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/emverLite/mod.ts.html @@ -0,0 +1,1054 @@ + + + + + + Code coverage report for emverLite/mod.ts + + + + + + + + + +
+
+

All files / emverLite mod.ts

+
+ +
+ 96.99% + Statements + 129/133 +
+ + +
+ 91.89% + Branches + 34/37 +
+ + +
+ 97.56% + Functions + 40/41 +
+ + +
+ 97.65% + Lines + 125/128 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +3241x +  +1x +  +  +  +  +  +  +4x +4x +4x +  +  +  +  +  +  +  +1x +19x +  +  +  +  +  +  +  +1x +6x +1x +  +5x +5x +  +  +  +  +  +  +  +1x +5x +1x +  +4x +4x +  +  +  +  +  +  +  +1x +1x +  +  +  +  +  +1x +  +  +  +  +  +  +124x +  +  +124x +  +  +  +  +  +  +149x +317x +149x +316x +3x +  +  +146x +  +  +150x +150x +  +  +  +  +  +  +4x +  +  +  +106x +220x +18x +  +202x +35x +  +  +167x +19x +  +  +34x +  +  +  +61x +23x +  +38x +74x +18x +  +  +20x +  +  +24x +  +  +9x +  +  +18x +  +  +  +  +  +  +  +  +6x +2x +4x +2x +  +2x +  +  +  +  +  +  +  +  +3x +  +1x +1x +1x +  +  +  +  +7x +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +55x +19x +  +36x +36x +6x +  +33x +8x +  +29x +1x +12x +9x +  +  +28x +28x +3x +22x +  +25x +25x +4x +4x +  +4x +24x +24x +  +  +  +  +  +  +  +21x +  +1x +1x +6x +6x +  +  +  +2x +2x +9x +9x +  +  +  +  +18x +  +7x +7x +30x +30x +  +  +  +4x +4x +18x +18x +  +  +  +7x +7x +21x +21x +  +  +  +  +  +  +  +  +  +  +38x +38x +  +  +  +  +  +  +  +  +  +  +5x +5x +  +20x +8x +  +12x +12x +6x +  +  +6x +  +5x +  +  +  +  +  +  +  +4x +4x +  +17x +4x +  +13x +13x +4x +  +  +9x +  +4x +  +  +  +  +  +  +  +  +1x +1x +  +  + 
import * as matches from "ts-matches"
+ 
+const starSub = /((\d+\.)*\d+)\.\*/
+// prettier-ignore
+export type ValidEmVer = string;
+// prettier-ignore
+export type ValidEmVerRange = string;
+ 
+function incrementLastNumber(list: number[]) {
+  const newList = [...list]
+  newList[newList.length - 1]++
+  return newList
+}
+/**
+ * Will take in a range, like `>1.2` or `<1.2.3.4` or `=1.2` or `1.*`
+ * and return a checker, that has the check function for checking that a version is in the valid
+ * @param range
+ * @returns
+ */
+export function rangeOf(range: string | Checker): Checker {
+  return Checker.parse(range)
+}
+ 
+/**
+ * Used to create a checker that will `and` all the ranges passed in
+ * @param ranges
+ * @returns
+ */
+export function rangeAnd(...ranges: (string | Checker)[]): Checker {
+  if (ranges.length === 0) {
+    throw new Error("No ranges given")
+  }
+  const [firstCheck, ...rest] = ranges
+  return Checker.parse(firstCheck).and(...rest)
+}
+ 
+/**
+ * Used to create a checker that will `or` all the ranges passed in
+ * @param ranges
+ * @returns
+ */
+export function rangeOr(...ranges: (string | Checker)[]): Checker {
+  if (ranges.length === 0) {
+    throw new Error("No ranges given")
+  }
+  const [firstCheck, ...rest] = ranges
+  return Checker.parse(firstCheck).or(...rest)
+}
+ 
+/**
+ * This will negate the checker, so given a checker that checks for >= 1.0.0, it will check for < 1.0.0
+ * @param range
+ * @returns
+ */
+export function notRange(range: string | Checker): Checker {
+  return rangeOf(range).not()
+}
+ 
+/**
+ * EmVer is a set of versioning of any pattern like 1 or 1.2 or 1.2.3 or 1.2.3.4 or ..
+ */
+export class EmVer {
+  /**
+   * Convert the range, should be 1.2.* or * into a emver
+   * Or an already made emver
+   * IsUnsafe
+   */
+  static from(range: string | EmVer): EmVer {
+    Iif (range instanceof EmVer) {
+      return range
+    }
+    return EmVer.parse(range)
+  }
+  /**
+   * Convert the range, should be 1.2.* or * into a emver
+   * IsUnsafe
+   */
+  static parse(rangeExtra: string): EmVer {
+    const [range, extra] = rangeExtra.split("-")
+    const values = range.split(".").map((x) => parseInt(x))
+    for (const value of values) {
+      if (isNaN(value)) {
+        throw new Error(`Couldn't parse range: ${range}`)
+      }
+    }
+    return new EmVer(values, extra)
+  }
+  private constructor(
+    public readonly values: number[],
+    readonly extra: string | null,
+  ) {}
+ 
+  /**
+   * Used when we need a new emver that has the last number incremented, used in the 1.* like things
+   */
+  public withLastIncremented() {
+    return new EmVer(incrementLastNumber(this.values), null)
+  }
+ 
+  public greaterThan(other: EmVer): boolean {
+    for (const i in this.values) {
+      if (other.values[i] == null) {
+        return true
+      }
+      if (this.values[i] > other.values[i]) {
+        return true
+      }
+ 
+      if (this.values[i] < other.values[i]) {
+        return false
+      }
+    }
+    return false
+  }
+ 
+  public equals(other: EmVer): boolean {
+    if (other.values.length !== this.values.length) {
+      return false
+    }
+    for (const i in this.values) {
+      if (this.values[i] !== other.values[i]) {
+        return false
+      }
+    }
+    return true
+  }
+  public greaterThanOrEqual(other: EmVer): boolean {
+    return this.greaterThan(other) || this.equals(other)
+  }
+  public lessThanOrEqual(other: EmVer): boolean {
+    return !this.greaterThan(other)
+  }
+  public lessThan(other: EmVer): boolean {
+    return !this.greaterThanOrEqual(other)
+  }
+  /**
+   * Return a enum string that describes (used for switching/iffs)
+   * to know comparison
+   * @param other
+   * @returns
+   */
+  public compare(other: EmVer) {
+    if (this.equals(other)) {
+      return "equal" as const
+    } else if (this.greaterThan(other)) {
+      return "greater" as const
+    } else {
+      return "less" as const
+    }
+  }
+  /**
+   * Used when sorting emver's in a list using the sort method
+   * @param other
+   * @returns
+   */
+  public compareForSort(other: EmVer) {
+    return matches
+      .matches(this.compare(other))
+      .when("equal", () => 0 as const)
+      .when("greater", () => 1 as const)
+      .when("less", () => -1 as const)
+      .unwrap()
+  }
+ 
+  toString() {
+    return `${this.values.join(".")}${this.extra ? `-${this.extra}` : ""}` as ValidEmVer
+  }
+}
+ 
+/**
+ * A checker is a function that takes a version and returns true if the version matches the checker.
+ * Used when we are doing range checking, like saying ">=1.0.0".check("1.2.3") will be true
+ */
+export class Checker {
+  /**
+   * Will take in a range, like `>1.2` or `<1.2.3.4` or `=1.2` or `1.*`
+   * and return a checker, that has the check function for checking that a version is in the valid
+   * @param range
+   * @returns
+   */
+  static parse(range: string | Checker): Checker {
+    if (range instanceof Checker) {
+      return range
+    }
+    range = range.trim()
+    if (range.indexOf("||") !== -1) {
+      return rangeOr(...range.split("||").map((x) => Checker.parse(x)))
+    }
+    if (range.indexOf("&&") !== -1) {
+      return rangeAnd(...range.split("&&").map((x) => Checker.parse(x)))
+    }
+    if (range === "*") {
+      return new Checker((version) => {
+        EmVer.from(version)
+        return true
+      }, range)
+    }
+    Iif (range.startsWith("!!")) return Checker.parse(range.substring(2))
+    if (range.startsWith("!")) {
+      const tempValue = Checker.parse(range.substring(1))
+      return new Checker((x) => !tempValue.check(x), range)
+    }
+    const starSubMatches = starSub.exec(range)
+    if (starSubMatches != null) {
+      const emVarLower = EmVer.parse(starSubMatches[1])
+      const emVarUpper = emVarLower.withLastIncremented()
+ 
+      return new Checker((version) => {
+        const v = EmVer.from(version)
+        return (
+          (v.greaterThan(emVarLower) || v.equals(emVarLower)) &&
+          !v.greaterThan(emVarUpper) &&
+          !v.equals(emVarUpper)
+        )
+      }, range)
+    }
+ 
+    switch (range.substring(0, 2)) {
+      case ">=": {
+        const emVar = EmVer.parse(range.substring(2))
+        return new Checker((version) => {
+          const v = EmVer.from(version)
+          return v.greaterThanOrEqual(emVar)
+        }, range)
+      }
+      case "<=": {
+        const emVar = EmVer.parse(range.substring(2))
+        return new Checker((version) => {
+          const v = EmVer.from(version)
+          return v.lessThanOrEqual(emVar)
+        }, range)
+      }
+    }
+ 
+    switch (range.substring(0, 1)) {
+      case ">": {
+        const emVar = EmVer.parse(range.substring(1))
+        return new Checker((version) => {
+          const v = EmVer.from(version)
+          return v.greaterThan(emVar)
+        }, range)
+      }
+      case "<": {
+        const emVar = EmVer.parse(range.substring(1))
+        return new Checker((version) => {
+          const v = EmVer.from(version)
+          return v.lessThan(emVar)
+        }, range)
+      }
+      case "=": {
+        const emVar = EmVer.parse(range.substring(1))
+        return new Checker((version) => {
+          const v = EmVer.from(version)
+          return v.equals(emVar)
+        }, `=${emVar.toString()}`)
+      }
+    }
+    throw new Error("Couldn't parse range: " + range)
+  }
+  constructor(
+    /**
+     * Check is the function that will be given a emver or unparsed emver and should give if it follows
+     * a pattern
+     */
+    public readonly check: (value: ValidEmVer | EmVer) => boolean,
+    private readonly _range: string,
+  ) {}
+ 
+  get range() {
+    return this._range as ValidEmVerRange
+  }
+ 
+  /**
+   * Used when we want the `and` condition with another checker
+   */
+  public and(...others: (Checker | string)[]): Checker {
+    const othersCheck = others.map(Checker.parse)
+    return new Checker(
+      (value) => {
+        if (!this.check(value)) {
+          return false
+        }
+        for (const other of othersCheck) {
+          if (!other.check(value)) {
+            return false
+          }
+        }
+        return true
+      },
+      othersCheck.map((x) => x._range).join(" && "),
+    )
+  }
+ 
+  /**
+   * Used when we want the `or` condition with another checker
+   */
+  public or(...others: (Checker | string)[]): Checker {
+    const othersCheck = others.map(Checker.parse)
+    return new Checker(
+      (value) => {
+        if (this.check(value)) {
+          return true
+        }
+        for (const other of othersCheck) {
+          if (other.check(value)) {
+            return true
+          }
+        }
+        return false
+      },
+      othersCheck.map((x) => x._range).join(" || "),
+    )
+  }
+ 
+  /**
+   * A useful example is making sure we don't match an exact version, like !=1.2.3
+   * @returns
+   */
+  public not(): Checker {
+    let newRange = `!${this._range}`
+    return Checker.parse(newRange)
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/favicon.png b/sdk/lib/coverage/lcov-report/favicon.png new file mode 100644 index 000000000..c1525b811 Binary files /dev/null and b/sdk/lib/coverage/lcov-report/favicon.png differ diff --git a/sdk/lib/coverage/lcov-report/health/checkFns/checkPortListening.ts.html b/sdk/lib/coverage/lcov-report/health/checkFns/checkPortListening.ts.html new file mode 100644 index 000000000..91d9639b8 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/health/checkFns/checkPortListening.ts.html @@ -0,0 +1,286 @@ + + + + + + Code coverage report for health/checkFns/checkPortListening.ts + + + + + + + + + +
+
+

All files / health/checkFns checkPortListening.ts

+
+ +
+ 61.11% + Statements + 11/18 +
+ + +
+ 0% + Branches + 0/7 +
+ + +
+ 42.85% + Functions + 3/7 +
+ + +
+ 61.11% + Lines + 11/18 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68  +1x +  +  +1x +1x +  +1x +1x +1x +2x +  +  +  +12x +  +8x +  +2x +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { Effects } from "../../types"
+import { stringFromStdErrOut } from "../../util/stringFromStdErrOut"
+import { CheckResult } from "./CheckResult"
+ 
+import { promisify } from "node:util"
+import * as CP from "node:child_process"
+ 
+const cpExec = promisify(CP.exec)
+const cpExecFile = promisify(CP.execFile)
+export function containsAddress(x: string, port: number) {
+  const readPorts = x
+    .split("\n")
+    .filter(Boolean)
+    .splice(1)
+    .map((x) => x.split(" ").filter(Boolean)[1]?.split(":")?.[1])
+    .filter(Boolean)
+    .map((x) => Number.parseInt(x, 16))
+    .filter(Number.isFinite)
+  return readPorts.indexOf(port) >= 0
+}
+ 
+/**
+ * This is used to check if a port is listening on the system.
+ * Used during the health check fn or the check main fn.
+ */
+export async function checkPortListening(
+  effects: Effects,
+  port: number,
+  options: {
+    errorMessage: string
+    successMessage: string
+    timeoutMessage?: string
+    timeout?: number
+  },
+): Promise<CheckResult> {
+  return Promise.race<CheckResult>([
+    Promise.resolve().then(async () => {
+      const hasAddress =
+        containsAddress(
+          await cpExec(`cat /proc/net/tcp`, {}).then(stringFromStdErrOut),
+          port,
+        ) ||
+        containsAddress(
+          await cpExec("cat /proc/net/udp", {}).then(stringFromStdErrOut),
+          port,
+        )
+      Iif (hasAddress) {
+        return { status: "success", message: options.successMessage }
+      }
+      return {
+        status: "failure",
+        message: options.errorMessage,
+      }
+    }),
+    new Promise((resolve) => {
+      setTimeout(
+        () =>
+          resolve({
+            status: "failure",
+            message:
+              options.timeoutMessage || `Timeout trying to check port ${port}`,
+          }),
+        options.timeout ?? 1_000,
+      )
+    }),
+  ])
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/health/checkFns/index.html b/sdk/lib/coverage/lcov-report/health/checkFns/index.html new file mode 100644 index 000000000..4e7d93016 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/health/checkFns/index.html @@ -0,0 +1,116 @@ + + + + + + Code coverage report for health/checkFns + + + + + + + + + +
+
+

All files health/checkFns

+
+ +
+ 61.11% + Statements + 11/18 +
+ + +
+ 0% + Branches + 0/7 +
+ + +
+ 42.85% + Functions + 3/7 +
+ + +
+ 61.11% + Lines + 11/18 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
checkPortListening.ts +
+
61.11%11/180%0/742.85%3/761.11%11/18
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/index.html b/sdk/lib/coverage/lcov-report/index.html new file mode 100644 index 000000000..91d439364 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/index.html @@ -0,0 +1,371 @@ + + + + + + Code coverage report for All files + + + + + + + + + +
+
+

All files

+
+ +
+ 48.29% + Statements + 1329/2752 +
+ + +
+ 37.19% + Branches + 334/898 +
+ + +
+ 30.54% + Functions + 212/694 +
+ + +
+ 48.21% + Lines + 1256/2605 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
lib +
+
40.27%58/1440%0/1111.76%10/8540.27%58/144
lib/actions +
+
10.71%3/280%0/20%0/1210.71%3/28
lib/backup +
+
8.79%8/910%0/110%0/279.09%8/88
lib/config +
+
46.15%12/2625%2/820%1/546.15%12/26
lib/config/builder +
+
84.61%99/11755.17%16/2978.26%54/6984.34%97/115
lib/dependencies +
+
9.67%9/931.78%1/566.25%2/3210%9/90
lib/exver +
+
71.73%713/99463.29%250/39571.65%91/12771.77%679/946
lib/health +
+
17.24%5/290%0/120%0/619.23%5/26
lib/health/checkFns +
+
53.06%26/490%0/1726.31%5/1950%22/44
lib/inits +
+
20.68%6/290%0/60%0/1120.68%6/29
lib/interfaces +
+
22.44%11/490%0/240%0/1322.22%10/45
lib/mainFn +
+
15.78%36/2280%0/380%0/7715.16%32/211
lib/manifest +
+
25%4/1665.51%19/2920%1/526.66%4/15
lib/store +
+
35.71%10/2820%1/510%1/1032%8/25
lib/test +
+
100%9/9100%0/0100%0/0100%9/9
lib/trigger +
+
30.61%15/490%0/540%4/1026.66%12/45
lib/util +
+
36.83%256/69512.2%26/21317.96%30/16736.29%233/642
lib/version +
+
62.82%49/7851.35%19/3768.42%13/1963.63%49/77
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/interfaces/Host.ts.html b/sdk/lib/coverage/lcov-report/interfaces/Host.ts.html new file mode 100644 index 000000000..938bb72bc --- /dev/null +++ b/sdk/lib/coverage/lcov-report/interfaces/Host.ts.html @@ -0,0 +1,667 @@ + + + + + + Code coverage report for interfaces/Host.ts + + + + + + + + + +
+
+

All files / interfaces Host.ts

+
+ +
+ 22.22% + Statements + 6/27 +
+ + +
+ 0% + Branches + 0/18 +
+ + +
+ 0% + Functions + 0/7 +
+ + +
+ 24% + Lines + 6/25 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +1951x +  +1x +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  + 
import { number, object, string } from "ts-matches"
+import { Effects } from "../types"
+import { Origin } from "./Origin"
+import { AddSslOptions, BindParams } from ".././osBindings"
+import { Security } from ".././osBindings"
+import { BindOptions } from ".././osBindings"
+import { AlpnInfo } from ".././osBindings"
+ 
+export { AddSslOptions, Security, BindOptions }
+ 
+export const knownProtocols = {
+  http: {
+    secure: null,
+    defaultPort: 80,
+    withSsl: "https",
+    alpn: { specified: ["http/1.1"] } as AlpnInfo,
+  },
+  https: {
+    secure: { ssl: true },
+    defaultPort: 443,
+  },
+  ws: {
+    secure: null,
+    defaultPort: 80,
+    withSsl: "wss",
+    alpn: { specified: ["http/1.1"] } as AlpnInfo,
+  },
+  wss: {
+    secure: { ssl: true },
+    defaultPort: 443,
+  },
+  ssh: {
+    secure: { ssl: false },
+    defaultPort: 22,
+  },
+  bitcoin: {
+    secure: { ssl: false },
+    defaultPort: 8333,
+  },
+  lightning: {
+    secure: { ssl: true },
+    defaultPort: 9735,
+  },
+  grpc: {
+    secure: { ssl: true },
+    defaultPort: 50051,
+  },
+  dns: {
+    secure: { ssl: false },
+    defaultPort: 53,
+  },
+} as const
+ 
+export type Scheme = string | null
+ 
+type KnownProtocols = typeof knownProtocols
+type ProtocolsWithSslVariants = {
+  [K in keyof KnownProtocols]: KnownProtocols[K] extends {
+    withSsl: string
+  }
+    ? K
+    : never
+}[keyof KnownProtocols]
+type NotProtocolsWithSslVariants = Exclude<
+  keyof KnownProtocols,
+  ProtocolsWithSslVariants
+>
+ 
+type BindOptionsByKnownProtocol =
+  | {
+      protocol: ProtocolsWithSslVariants
+      preferredExternalPort?: number
+      addSsl?: Partial<AddSslOptions>
+    }
+  | {
+      protocol: NotProtocolsWithSslVariants
+      preferredExternalPort?: number
+      addSsl?: AddSslOptions
+    }
+export type BindOptionsByProtocol = BindOptionsByKnownProtocol | BindOptions
+ 
+export type HostKind = BindParams["kind"]
+ 
+const hasStringProtocol = object({
+  protocol: string,
+}).test
+ 
+export class Host {
+  constructor(
+    readonly options: {
+      effects: Effects
+      kind: HostKind
+      id: string
+    },
+  ) {}
+ 
+  async bindPort(
+    internalPort: number,
+    options: BindOptionsByProtocol,
+  ): Promise<Origin<this>> {
+    if (hasStringProtocol(options)) {
+      return await this.bindPortForKnown(options, internalPort)
+    } else {
+      return await this.bindPortForUnknown(internalPort, options)
+    }
+  }
+ 
+  private async bindPortForUnknown(
+    internalPort: number,
+    options: {
+      preferredExternalPort: number
+      addSsl: AddSslOptions | null
+      secure: { ssl: boolean } | null
+    },
+  ) {
+    const binderOptions = {
+      kind: this.options.kind,
+      id: this.options.id,
+      internalPort,
+      ...options,
+    }
+    await this.options.effects.bind(binderOptions)
+ 
+    return new Origin(this, internalPort, null, null)
+  }
+ 
+  private async bindPortForKnown(
+    options: BindOptionsByKnownProtocol,
+    internalPort: number,
+  ) {
+    const protoInfo = knownProtocols[options.protocol]
+    const preferredExternalPort =
+      options.preferredExternalPort ||
+      knownProtocols[options.protocol].defaultPort
+    const sslProto = this.getSslProto(options, protoInfo)
+    const addSsl =
+      sslProto && "alpn" in protoInfo
+        ? {
+            // addXForwardedHeaders: null,
+            preferredExternalPort: knownProtocols[sslProto].defaultPort,
+            scheme: sslProto,
+            alpn: protoInfo.alpn,
+            ...("addSsl" in options ? options.addSsl : null),
+          }
+        : null
+ 
+    const secure: Security | null = !protoInfo.secure ? null : { ssl: false }
+ 
+    await this.options.effects.bind({
+      kind: this.options.kind,
+      id: this.options.id,
+      internalPort,
+      preferredExternalPort,
+      addSsl,
+      secure,
+    })
+ 
+    return new Origin(this, internalPort, options.protocol, sslProto)
+  }
+ 
+  private getSslProto(
+    options: BindOptionsByKnownProtocol,
+    protoInfo: KnownProtocols[keyof KnownProtocols],
+  ) {
+    Iif (inObject("noAddSsl", options) && options.noAddSsl) return null
+    Iif ("withSsl" in protoInfo && protoInfo.withSsl) return protoInfo.withSsl
+    return null
+  }
+}
+ 
+function inObject<Key extends string>(
+  key: Key,
+  obj: any,
+): obj is { [K in Key]: unknown } {
+  return key in obj
+}
+ 
+// export class StaticHost extends Host {
+//   constructor(options: { effects: Effects; id: string }) {
+//     super({ ...options, kind: "static" })
+//   }
+// }
+ 
+// export class SingleHost extends Host {
+//   constructor(options: { effects: Effects; id: string }) {
+//     super({ ...options, kind: "single" })
+//   }
+// }
+ 
+export class MultiHost extends Host {
+  constructor(options: { effects: Effects; id: string }) {
+    super({ ...options, kind: "multi" })
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/interfaces/Origin.ts.html b/sdk/lib/coverage/lcov-report/interfaces/Origin.ts.html new file mode 100644 index 000000000..f782bfdc4 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/interfaces/Origin.ts.html @@ -0,0 +1,355 @@ + + + + + + Code coverage report for interfaces/Origin.ts + + + + + + + + + +
+
+

All files / interfaces Origin.ts

+
+ +
+ 6.25% + Statements + 1/16 +
+ + +
+ 0% + Branches + 0/6 +
+ + +
+ 0% + Functions + 0/4 +
+ + +
+ 6.25% + Lines + 1/16 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { AddressInfo } from "../types"
+import { AddressReceipt } from "./AddressReceipt"
+import { Host, BindOptions, Scheme } from "./Host"
+import { ServiceInterfaceBuilder } from "./ServiceInterfaceBuilder"
+ 
+export class Origin<T extends Host> {
+  constructor(
+    readonly host: T,
+    readonly internalPort: number,
+    readonly scheme: string | null,
+    readonly sslScheme: string | null,
+  ) {}
+ 
+  build({ username, path, search, schemeOverride }: BuildOptions): AddressInfo {
+    const qpEntries = Object.entries(search)
+      .map(
+        ([key, val]) => `${encodeURIComponent(key)}=${encodeURIComponent(val)}`,
+      )
+      .join("&")
+ 
+    const qp = qpEntries.length ? `?${qpEntries}` : ""
+ 
+    return {
+      hostId: this.host.options.id,
+      internalPort: this.internalPort,
+      scheme: schemeOverride ? schemeOverride.noSsl : this.scheme,
+      sslScheme: schemeOverride ? schemeOverride.ssl : this.sslScheme,
+      suffix: `${path}${qp}`,
+      username,
+    }
+  }
+ 
+  /**
+   * A function to register a group of origins (<PROTOCOL> :// <HOSTNAME> : <PORT>) with StartOS
+   *
+   * The returned addressReceipt serves as proof that the addresses were registered
+   *
+   * @param addressInfo
+   * @returns
+   */
+  async export(
+    serviceInterfaces: ServiceInterfaceBuilder[],
+  ): Promise<AddressInfo[] & AddressReceipt> {
+    const addressesInfo = []
+    for (let serviceInterface of serviceInterfaces) {
+      const {
+        name,
+        description,
+        hasPrimary,
+        disabled,
+        id,
+        type,
+        username,
+        path,
+        search,
+        schemeOverride,
+        masked,
+      } = serviceInterface.options
+ 
+      const addressInfo = this.build({
+        username,
+        path,
+        search,
+        schemeOverride,
+      })
+ 
+      await serviceInterface.options.effects.exportServiceInterface({
+        id,
+        name,
+        description,
+        hasPrimary,
+        disabled,
+        addressInfo,
+        type,
+        masked,
+      })
+ 
+      addressesInfo.push(addressInfo)
+    }
+ 
+    return addressesInfo as AddressInfo[] & AddressReceipt
+  }
+}
+ 
+type BuildOptions = {
+  schemeOverride: { ssl: Scheme; noSsl: Scheme } | null
+  username: string | null
+  path: string
+  search: Record<string, string>
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/interfaces/index.html b/sdk/lib/coverage/lcov-report/interfaces/index.html new file mode 100644 index 000000000..e7b18c2df --- /dev/null +++ b/sdk/lib/coverage/lcov-report/interfaces/index.html @@ -0,0 +1,131 @@ + + + + + + Code coverage report for interfaces + + + + + + + + + +
+
+

All files interfaces

+
+ +
+ 16.27% + Statements + 7/43 +
+ + +
+ 0% + Branches + 0/24 +
+ + +
+ 0% + Functions + 0/11 +
+ + +
+ 17.07% + Lines + 7/41 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
Host.ts +
+
22.22%6/270%0/180%0/724%6/25
Origin.ts +
+
6.25%1/160%0/60%0/46.25%1/16
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/Dependency.ts.html b/sdk/lib/coverage/lcov-report/lib/Dependency.ts.html new file mode 100644 index 000000000..c3cf06329 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/Dependency.ts.html @@ -0,0 +1,139 @@ + + + + + + Code coverage report for lib/Dependency.ts + + + + + + + + + +
+
+

All files / lib Dependency.ts

+
+ +
+ 50% + Statements + 1/2 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 50% + Lines + 1/2 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { VersionRange } from "./exver"
+ 
+export class Dependency {
+  constructor(
+    readonly data:
+      | {
+          type: "running"
+          versionRange: VersionRange
+          registryUrl: string
+          healthChecks: string[]
+        }
+      | {
+          type: "exists"
+          versionRange: VersionRange
+          registryUrl: string
+        },
+  ) {}
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/StartSdk.ts.html b/sdk/lib/coverage/lcov-report/lib/StartSdk.ts.html new file mode 100644 index 000000000..0cb25cff6 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/StartSdk.ts.html @@ -0,0 +1,2497 @@ + + + + + + Code coverage report for lib/StartSdk.ts + + + + + + + + + +
+
+

All files / lib StartSdk.ts

+
+ +
+ 40.14% + Statements + 57/142 +
+ + +
+ 0% + Branches + 0/11 +
+ + +
+ 11.9% + Functions + 10/84 +
+ + +
+ 40.14% + Lines + 57/142 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335 +336 +337 +338 +339 +340 +341 +342 +343 +344 +345 +346 +347 +348 +349 +350 +351 +352 +353 +354 +355 +356 +357 +358 +359 +360 +361 +362 +363 +364 +365 +366 +367 +368 +369 +370 +371 +372 +373 +374 +375 +376 +377 +378 +379 +380 +381 +382 +383 +384 +385 +386 +387 +388 +389 +390 +391 +392 +393 +394 +395 +396 +397 +398 +399 +400 +401 +402 +403 +404 +405 +406 +407 +408 +409 +410 +411 +412 +413 +414 +415 +416 +417 +418 +419 +420 +421 +422 +423 +424 +425 +426 +427 +428 +429 +430 +431 +432 +433 +434 +435 +436 +437 +438 +439 +440 +441 +442 +443 +444 +445 +446 +447 +448 +449 +450 +451 +452 +453 +454 +455 +456 +457 +458 +459 +460 +461 +462 +463 +464 +465 +466 +467 +468 +469 +470 +471 +472 +473 +474 +475 +476 +477 +478 +479 +480 +481 +482 +483 +484 +485 +486 +487 +488 +489 +490 +491 +492 +493 +494 +495 +496 +497 +498 +499 +500 +501 +502 +503 +504 +505 +506 +507 +508 +509 +510 +511 +512 +513 +514 +515 +516 +517 +518 +519 +520 +521 +522 +523 +524 +525 +526 +527 +528 +529 +530 +531 +532 +533 +534 +535 +536 +537 +538 +539 +540 +541 +542 +543 +544 +545 +546 +547 +548 +549 +550 +551 +552 +553 +554 +555 +556 +557 +558 +559 +560 +561 +562 +563 +564 +565 +566 +567 +568 +569 +570 +571 +572 +573 +574 +575 +576 +577 +578 +579 +580 +581 +582 +583 +584 +585 +586 +587 +588 +589 +590 +591 +592 +593 +594 +595 +596 +597 +598 +599 +600 +601 +602 +603 +604 +605 +606 +607 +608 +609 +610 +611 +612 +613 +614 +615 +616 +617 +618 +619 +620 +621 +622 +623 +624 +625 +626 +627 +628 +629 +630 +631 +632 +633 +634 +635 +636 +637 +638 +639 +640 +641 +642 +643 +644 +645 +646 +647 +648 +649 +650 +651 +652 +653 +654 +655 +656 +657 +658 +659 +660 +661 +662 +663 +664 +665 +666 +667 +668 +669 +670 +671 +672 +673 +674 +675 +676 +677 +678 +679 +680 +681 +682 +683 +684 +685 +686 +687 +688 +689 +690 +691 +692 +693 +694 +695 +696 +697 +698 +699 +700 +701 +702 +703 +704 +705 +706 +707 +708 +709 +710 +711 +712 +713 +714 +715 +716 +717 +718 +719 +720 +721 +722 +723 +724 +725 +726 +727 +728 +729 +730 +731 +732 +733 +734 +735 +736 +737 +738 +739 +740 +741 +742 +743 +744 +745 +746 +747 +748 +749 +750 +751 +752 +753 +754 +755 +756 +757 +758 +759 +760 +761 +762 +763 +764 +765 +766 +767 +768 +769 +770 +771 +772 +773 +774 +775 +776 +777 +778 +779 +780 +781 +782 +783 +784 +785 +786 +787 +788 +789 +790 +791 +792 +793 +794 +795 +796 +797 +798 +799 +800 +801 +802 +803 +804 +8055x +5x +  +  +  +  +  +  +  +  +  +5x +5x +  +  +  +  +  +  +  +  +  +  +5x +5x +5x +5x +5x +5x +5x +5x +5x +5x +5x +5x +5x +5x +5x +5x +5x +5x +5x +  +  +  +  +5x +  +  +  +  +5x +  +5x +5x +5x +5x +5x +  +  +  +5x +5x +5x +5x +5x +5x +  +5x +  +5x +5x +  +  +  +  +5x +  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +5x +5x +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +5x +18x +  +6x +  +  +6x +  +  +6x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +6x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +6x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +32x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +4x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +4x +  +  +  +  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { RequiredDefault, Value } from "./config/builder/value"
+import { Config, ExtractConfigType, LazyBuild } from "./config/builder/config"
+import {
+  DefaultString,
+  ListValueSpecText,
+  Pattern,
+  RandomString,
+  UniqueBy,
+  ValueSpecDatetime,
+  ValueSpecText,
+} from "./config/configTypes"
+import { Variants } from "./config/builder/variants"
+import { CreatedAction, createAction } from "./actions/createAction"
+import {
+  ActionMetadata,
+  Effects,
+  ActionResult,
+  BackupOptions,
+  DeepPartial,
+  MaybePromise,
+  ServiceInterfaceId,
+  PackageId,
+} from "./types"
+import * as patterns from "./util/patterns"
+import { DependencyConfig, Update } from "./dependencies/DependencyConfig"
+import { BackupSet, Backups } from "./backup/Backups"
+import { smtpConfig } from "./config/configConstants"
+import { Daemons } from "./mainFn/Daemons"
+import { healthCheck, HealthCheckParams } from "./health/HealthCheck"
+import { checkPortListening } from "./health/checkFns/checkPortListening"
+import { checkWebUrl, runHealthScript } from "./health/checkFns"
+import { List } from "./config/builder/list"
+import { Install, InstallFn } from "./inits/setupInstall"
+import { setupActions } from "./actions/setupActions"
+import { setupDependencyConfig } from "./dependencies/setupDependencyConfig"
+import { SetupBackupsParams, setupBackups } from "./backup/setupBackups"
+import { setupInit } from "./inits/setupInit"
+import { Uninstall, UninstallFn, setupUninstall } from "./inits/setupUninstall"
+import { setupMain } from "./mainFn"
+import { defaultTrigger } from "./trigger/defaultTrigger"
+import { changeOnFirstSuccess, cooldownTrigger } from "./trigger"
+import setupConfig, {
+  DependenciesReceipt,
+  Read,
+  Save,
+} from "./config/setupConfig"
+import {
+  InterfacesReceipt,
+  SetInterfaces,
+  setupInterfaces,
+} from "./interfaces/setupInterfaces"
+import { successFailure } from "./trigger/successFailure"
+import { HealthReceipt } from "./health/HealthReceipt"
+import { MultiHost, Scheme } from "./interfaces/Host"
+import { ServiceInterfaceBuilder } from "./interfaces/ServiceInterfaceBuilder"
+import { GetSystemSmtp } from "./util/GetSystemSmtp"
+import nullIfEmpty from "./util/nullIfEmpty"
+import {
+  GetServiceInterface,
+  getServiceInterface,
+} from "./util/getServiceInterface"
+import { getServiceInterfaces } from "./util/getServiceInterfaces"
+import { getStore } from "./store/getStore"
+import { CommandOptions, MountOptions, SubContainer } from "./util/SubContainer"
+import { splitCommand } from "./util/splitCommand"
+import { Mounts } from "./mainFn/Mounts"
+import { Dependency } from "./Dependency"
+import * as T from "./types"
+import { testTypeVersion, ValidateExVer } from "./exver"
+import { ExposedStorePaths } from "./store/setupExposeStore"
+import { PathBuilder, extractJsonPath, pathBuilder } from "./store/PathBuilder"
+import {
+  CheckDependencies,
+  checkDependencies,
+} from "./dependencies/dependencies"
+import { health } from "."
+import { GetSslCertificate } from "./util/GetSslCertificate"
+import { VersionGraph } from "./version"
+ 
+export const SDKVersion = testTypeVersion("0.3.6")
+ 
+// prettier-ignore
+type AnyNeverCond<T extends any[], Then, Else> = 
+    T extends [] ? Else :
+    T extends [never, ...Array<any>] ? Then :
+    T extends [any, ...infer U] ? AnyNeverCond<U,Then, Else> :
+    never
+ 
+export type ServiceInterfaceType = "ui" | "p2p" | "api"
+export type MainEffects = Effects & {
+  _type: "main"
+  clearCallbacks: () => Promise<void>
+}
+export type Signals = NodeJS.Signals
+export const SIGTERM: Signals = "SIGTERM"
+export const SIGKILL: Signals = "SIGKILL"
+export const NO_TIMEOUT = -1
+ 
+function removeCallbackTypes<E extends Effects>(effects: E) {
+  return <T extends object>(t: T) => {
+    if ("_type" in effects && effects._type === "main") {
+      return t as E extends MainEffects ? T : Omit<T, "const" | "watch">
+    } else {
+      Iif ("const" in t) {
+        delete t.const
+      }
+      Iif ("watch" in t) {
+        delete t.watch
+      }
+      return t as E extends MainEffects ? T : Omit<T, "const" | "watch">
+    }
+  }
+}
+ 
+export class StartSdk<Manifest extends T.Manifest, Store> {
+  private constructor(readonly manifest: Manifest) {}
+  static of() {
+    return new StartSdk<never, never>(null as never)
+  }
+  withManifest<Manifest extends T.Manifest = never>(manifest: Manifest) {
+    return new StartSdk<Manifest, Store>(manifest)
+  }
+  withStore<Store extends Record<string, any>>() {
+    return new StartSdk<Manifest, Store>(this.manifest)
+  }
+ 
+  build(isReady: AnyNeverCond<[Manifest, Store], "Build not ready", true>) {
+    type DependencyType = {
+      [K in keyof {
+        [K in keyof Manifest["dependencies"]]: Manifest["dependencies"][K]["optional"] extends false
+          ? K
+          : never
+      }]: Dependency
+    } & {
+      [K in keyof {
+        [K in keyof Manifest["dependencies"]]: Manifest["dependencies"][K]["optional"] extends true
+          ? K
+          : never
+      }]?: Dependency
+    }
+ 
+    type NestedEffects = "subcontainer" | "store"
+    type InterfaceEffects =
+      | "getServiceInterface"
+      | "listServiceInterfaces"
+      | "exportServiceInterface"
+      | "clearServiceInterfaces"
+      | "bind"
+      | "getHostInfo"
+      | "getPrimaryUrl"
+    type MainUsedEffects = "setMainStatus" | "setHealth"
+    type AlreadyExposed = "getSslCertificate" | "getSystemSmtp"
+ 
+    // prettier-ignore
+    type StartSdkEffectWrapper = {
+      [K in keyof Omit<Effects, NestedEffects | InterfaceEffects | MainUsedEffects| AlreadyExposed>]: (effects: Effects, ...args: Parameters<Effects[K]>) => ReturnType<Effects[K]>
+    }
+    const startSdkEffectWrapper: StartSdkEffectWrapper = {
+      executeAction: (effects, ...args) => effects.executeAction(...args),
+      exportAction: (effects, ...args) => effects.exportAction(...args),
+      clearActions: (effects, ...args) => effects.clearActions(...args),
+      getConfigured: (effects, ...args) => effects.getConfigured(...args),
+      setConfigured: (effects, ...args) => effects.setConfigured(...args),
+      restart: (effects, ...args) => effects.restart(...args),
+      setDependencies: (effects, ...args) => effects.setDependencies(...args),
+      checkDependencies: (effects, ...args) =>
+        effects.checkDependencies(...args),
+      mount: (effects, ...args) => effects.mount(...args),
+      getInstalledPackages: (effects, ...args) =>
+        effects.getInstalledPackages(...args),
+      exposeForDependents: (effects, ...args) =>
+        effects.exposeForDependents(...args),
+      getServicePortForward: (effects, ...args) =>
+        effects.getServicePortForward(...args),
+      clearBindings: (effects, ...args) => effects.clearBindings(...args),
+      getContainerIp: (effects, ...args) => effects.getContainerIp(...args),
+      getSslKey: (effects, ...args) => effects.getSslKey(...args),
+      setDataVersion: (effects, ...args) => effects.setDataVersion(...args),
+      getDataVersion: (effects, ...args) => effects.getDataVersion(...args),
+      shutdown: (effects, ...args) => effects.shutdown(...args),
+      getDependencies: (effects, ...args) => effects.getDependencies(...args),
+    }
+ 
+    return {
+      ...startSdkEffectWrapper,
+ 
+      checkDependencies: checkDependencies as <
+        DependencyId extends keyof Manifest["dependencies"] &
+          PackageId = keyof Manifest["dependencies"] & PackageId,
+      >(
+        effects: Effects,
+        packageIds?: DependencyId[],
+      ) => Promise<CheckDependencies<DependencyId>>,
+      serviceInterface: {
+        getOwn: <E extends Effects>(effects: E, id: ServiceInterfaceId) =>
+          removeCallbackTypes<E>(effects)(
+            getServiceInterface(effects, {
+              id,
+            }),
+          ),
+        get: <E extends Effects>(
+          effects: E,
+          opts: { id: ServiceInterfaceId; packageId: PackageId },
+        ) =>
+          removeCallbackTypes<E>(effects)(getServiceInterface(effects, opts)),
+        getAllOwn: <E extends Effects>(effects: E) =>
+          removeCallbackTypes<E>(effects)(getServiceInterfaces(effects, {})),
+        getAll: <E extends Effects>(
+          effects: E,
+          opts: { packageId: PackageId },
+        ) =>
+          removeCallbackTypes<E>(effects)(getServiceInterfaces(effects, opts)),
+      },
+ 
+      store: {
+        get: <E extends Effects, StoreValue = unknown>(
+          effects: E,
+          packageId: string,
+          path: PathBuilder<Store, StoreValue>,
+        ) =>
+          removeCallbackTypes<E>(effects)(
+            getStore<Store, StoreValue>(effects, path, {
+              packageId,
+            }),
+          ),
+        getOwn: <E extends Effects, StoreValue = unknown>(
+          effects: E,
+          path: PathBuilder<Store, StoreValue>,
+        ) =>
+          removeCallbackTypes<E>(effects)(
+            getStore<Store, StoreValue>(effects, path),
+          ),
+        setOwn: <E extends Effects, Path extends PathBuilder<Store, unknown>>(
+          effects: E,
+          path: Path,
+          value: Path extends PathBuilder<Store, infer Value> ? Value : never,
+        ) =>
+          effects.store.set<Store>({
+            value,
+            path: extractJsonPath(path),
+          }),
+      },
+ 
+      host: {
+        // static: (effects: Effects, id: string) =>
+        //   new StaticHost({ id, effects }),
+        // single: (effects: Effects, id: string) =>
+        //   new SingleHost({ id, effects }),
+        multi: (effects: Effects, id: string) => new MultiHost({ id, effects }),
+      },
+      nullIfEmpty,
+      runCommand: async <A extends string>(
+        effects: Effects,
+        image: {
+          id: keyof Manifest["images"] & T.ImageId
+          sharedRun?: boolean
+        },
+        command: T.CommandType,
+        options: CommandOptions & {
+          mounts?: { path: string; options: MountOptions }[]
+        },
+      ): Promise<{ stdout: string | Buffer; stderr: string | Buffer }> => {
+        return runCommand<Manifest>(effects, image, command, options)
+      },
+ 
+      createAction: <
+        ConfigType extends
+          | Record<string, any>
+          | Config<any, any>
+          | Config<any, never>,
+        Type extends Record<string, any> = ExtractConfigType<ConfigType>,
+      >(
+        id: string,
+        metaData: Omit<ActionMetadata, "input"> & {
+          input: Config<Type, Store> | Config<Type, never>
+        },
+        fn: (options: {
+          effects: Effects
+          input: Type
+        }) => Promise<ActionResult>,
+      ) => {
+        const { input, ...rest } = metaData
+        return createAction<Manifest, Store, ConfigType, Type>(
+          id,
+          rest,
+          fn,
+          input,
+        )
+      },
+      configConstants: { smtpConfig },
+      createInterface: (
+        effects: Effects,
+        options: {
+          name: string
+          id: string
+          description: string
+          hasPrimary: boolean
+          type: ServiceInterfaceType
+          username: null | string
+          path: string
+          search: Record<string, string>
+          schemeOverride: { ssl: Scheme; noSsl: Scheme } | null
+          masked: boolean
+        },
+      ) => new ServiceInterfaceBuilder({ ...options, effects }),
+      getSystemSmtp: <E extends Effects>(effects: E) =>
+        removeCallbackTypes<E>(effects)(new GetSystemSmtp(effects)),
+ 
+      getSslCerificate: <E extends Effects>(
+        effects: E,
+        hostnames: string[],
+        algorithm?: T.Algorithm,
+      ) =>
+        removeCallbackTypes<E>(effects)(
+          new GetSslCertificate(effects, hostnames, algorithm),
+        ),
+ 
+      createDynamicAction: <
+        ConfigType extends
+          | Record<string, any>
+          | Config<any, any>
+          | Config<any, never>,
+        Type extends Record<string, any> = ExtractConfigType<ConfigType>,
+      >(
+        id: string,
+        metaData: (options: {
+          effects: Effects
+        }) => MaybePromise<Omit<ActionMetadata, "input">>,
+        fn: (options: {
+          effects: Effects
+          input: Type
+        }) => Promise<ActionResult>,
+        input: Config<Type, Store> | Config<Type, never>,
+      ) => {
+        return createAction<Manifest, Store, ConfigType, Type>(
+          id,
+          metaData,
+          fn,
+          input,
+        )
+      },
+      HealthCheck: {
+        of(o: HealthCheckParams) {
+          return healthCheck(o)
+        },
+      },
+      Dependency: {
+        of(data: Dependency["data"]) {
+          return new Dependency({ ...data })
+        },
+      },
+      healthCheck: {
+        checkPortListening,
+        checkWebUrl,
+        runHealthScript,
+      },
+      patterns,
+      setupActions: (...createdActions: CreatedAction<any, any, any>[]) =>
+        setupActions<Manifest, Store>(...createdActions),
+      setupBackups: (...args: SetupBackupsParams<Manifest>) =>
+        setupBackups<Manifest>(this.manifest, ...args),
+      setupConfig: <
+        ConfigType extends Config<any, Store> | Config<any, never>,
+        Type extends Record<string, any> = ExtractConfigType<ConfigType>,
+      >(
+        spec: ConfigType,
+        write: Save<Type>,
+        read: Read<Manifest, Store, Type>,
+      ) => setupConfig<Store, ConfigType, Manifest, Type>(spec, write, read),
+      setupConfigRead: <
+        ConfigSpec extends
+          | Config<Record<string, any>, any>
+          | Config<Record<string, never>, never>,
+      >(
+        _configSpec: ConfigSpec,
+        fn: Read<Manifest, Store, ConfigSpec>,
+      ) => fn,
+      setupConfigSave: <
+        ConfigSpec extends
+          | Config<Record<string, any>, any>
+          | Config<Record<string, never>, never>,
+      >(
+        _configSpec: ConfigSpec,
+        fn: Save<ConfigSpec>,
+      ) => fn,
+      setupDependencyConfig: <Input extends Record<string, any>>(
+        config: Config<Input, Store> | Config<Input, never>,
+        autoConfigs: {
+          [K in keyof Manifest["dependencies"]]: DependencyConfig<
+            Manifest,
+            Store,
+            Input,
+            any
+          > | null
+        },
+      ) => setupDependencyConfig<Store, Input, Manifest>(config, autoConfigs),
+      setupDependencies: <Input extends Record<string, any>>(
+        fn: (options: {
+          effects: Effects
+          input: Input | null
+        }) => Promise<DependencyType>,
+      ) => {
+        return async (options: { effects: Effects; input: Input }) => {
+          const dependencyType = await fn(options)
+          return await options.effects.setDependencies({
+            dependencies: Object.entries(dependencyType).map(
+              ([
+                id,
+                {
+                  data: { versionRange, ...x },
+                },
+              ]) => ({
+                id,
+                ...x,
+                ...(x.type === "running"
+                  ? {
+                      kind: "running",
+                      healthChecks: x.healthChecks,
+                    }
+                  : {
+                      kind: "exists",
+                    }),
+                versionRange: versionRange.toString(),
+              }),
+            ),
+          })
+        }
+      },
+      setupInit: (
+        versions: VersionGraph<Manifest["version"]>,
+        install: Install<Manifest, Store>,
+        uninstall: Uninstall<Manifest, Store>,
+        setInterfaces: SetInterfaces<Manifest, Store, any, any>,
+        setDependencies: (options: {
+          effects: Effects
+          input: any
+        }) => Promise<DependenciesReceipt>,
+        exposedStore: ExposedStorePaths,
+      ) =>
+        setupInit<Manifest, Store>(
+          versions,
+          install,
+          uninstall,
+          setInterfaces,
+          setDependencies,
+          exposedStore,
+        ),
+      setupInstall: (fn: InstallFn<Manifest, Store>) => Install.of(fn),
+      setupInterfaces: <
+        ConfigInput extends Record<string, any>,
+        Output extends InterfacesReceipt,
+      >(
+        config: Config<ConfigInput, Store>,
+        fn: SetInterfaces<Manifest, Store, ConfigInput, Output>,
+      ) => setupInterfaces(config, fn),
+      setupMain: (
+        fn: (o: {
+          effects: MainEffects
+          started(onTerm: () => PromiseLike<void>): PromiseLike<void>
+        }) => Promise<Daemons<Manifest, any>>,
+      ) => setupMain<Manifest, Store>(fn),
+      setupProperties:
+        (
+          fn: (options: { effects: Effects }) => Promise<T.SdkPropertiesReturn>,
+        ): T.ExpectedExports.properties =>
+        (options) =>
+          fn(options).then(nullifyProperties),
+      setupUninstall: (fn: UninstallFn<Manifest, Store>) =>
+        setupUninstall<Manifest, Store>(fn),
+      trigger: {
+        defaultTrigger,
+        cooldownTrigger,
+        changeOnFirstSuccess,
+        successFailure,
+      },
+      Mounts: {
+        of() {
+          return Mounts.of<Manifest>()
+        },
+      },
+      Backups: {
+        volumes: (
+          ...volumeNames: Array<Manifest["volumes"][number] & string>
+        ) => Backups.volumes<Manifest>(...volumeNames),
+        addSets: (
+          ...options: BackupSet<Manifest["volumes"][number] & string>[]
+        ) => Backups.addSets<Manifest>(...options),
+        withOptions: (options?: Partial<BackupOptions>) =>
+          Backups.with_options<Manifest>(options),
+      },
+      Config: {
+        of: <
+          Spec extends Record<string, Value<any, Store> | Value<any, never>>,
+        >(
+          spec: Spec,
+        ) => Config.of<Spec, Store>(spec),
+      },
+      Daemons: {
+        of(config: {
+          effects: Effects
+          started: (onTerm: () => PromiseLike<void>) => PromiseLike<void>
+          healthReceipts: HealthReceipt[]
+        }) {
+          return Daemons.of<Manifest>(config)
+        },
+      },
+      DependencyConfig: {
+        of<
+          LocalConfig extends Record<string, any>,
+          RemoteConfig extends Record<string, any>,
+        >({
+          localConfigSpec,
+          remoteConfigSpec,
+          dependencyConfig,
+          update,
+        }: {
+          localConfigSpec:
+            | Config<LocalConfig, Store>
+            | Config<LocalConfig, never>
+          remoteConfigSpec:
+            | Config<RemoteConfig, any>
+            | Config<RemoteConfig, never>
+          dependencyConfig: (options: {
+            effects: Effects
+            localConfig: LocalConfig
+          }) => Promise<void | DeepPartial<RemoteConfig>>
+          update?: Update<void | DeepPartial<RemoteConfig>, RemoteConfig>
+        }) {
+          return new DependencyConfig<
+            Manifest,
+            Store,
+            LocalConfig,
+            RemoteConfig
+          >(dependencyConfig, update)
+        },
+      },
+      List: {
+        text: List.text,
+        obj: <Type extends Record<string, any>>(
+          a: {
+            name: string
+            description?: string | null
+            warning?: string | null
+            /** Default [] */
+            default?: []
+            minLength?: number | null
+            maxLength?: number | null
+          },
+          aSpec: {
+            spec: Config<Type, Store>
+            displayAs?: null | string
+            uniqueBy?: null | UniqueBy
+          },
+        ) => List.obj<Type, Store>(a, aSpec),
+        dynamicText: (
+          getA: LazyBuild<
+            Store,
+            {
+              name: string
+              description?: string | null
+              warning?: string | null
+              /** Default = [] */
+              default?: string[]
+              minLength?: number | null
+              maxLength?: number | null
+              disabled?: false | string
+              generate?: null | RandomString
+              spec: {
+                /** Default = false */
+                masked?: boolean
+                placeholder?: string | null
+                minLength?: number | null
+                maxLength?: number | null
+                patterns: Pattern[]
+                /** Default = "text" */
+                inputmode?: ListValueSpecText["inputmode"]
+              }
+            }
+          >,
+        ) => List.dynamicText<Store>(getA),
+      },
+      StorePath: pathBuilder<Store>(),
+      Value: {
+        toggle: Value.toggle,
+        text: Value.text,
+        textarea: Value.textarea,
+        number: Value.number,
+        color: Value.color,
+        datetime: Value.datetime,
+        select: Value.select,
+        multiselect: Value.multiselect,
+        object: Value.object,
+        union: Value.union,
+        list: Value.list,
+        dynamicToggle: (
+          a: LazyBuild<
+            Store,
+            {
+              name: string
+              description?: string | null
+              warning?: string | null
+              default: boolean
+              disabled?: false | string
+            }
+          >,
+        ) => Value.dynamicToggle<Store>(a),
+        dynamicText: (
+          getA: LazyBuild<
+            Store,
+            {
+              name: string
+              description?: string | null
+              warning?: string | null
+              required: RequiredDefault<DefaultString>
+ 
+              /** Default = false */
+              masked?: boolean
+              placeholder?: string | null
+              minLength?: number | null
+              maxLength?: number | null
+              patterns?: Pattern[]
+              /** Default = 'text' */
+              inputmode?: ValueSpecText["inputmode"]
+              generate?: null | RandomString
+            }
+          >,
+        ) => Value.dynamicText<Store>(getA),
+        dynamicTextarea: (
+          getA: LazyBuild<
+            Store,
+            {
+              name: string
+              description?: string | null
+              warning?: string | null
+              required: boolean
+              minLength?: number | null
+              maxLength?: number | null
+              placeholder?: string | null
+              disabled?: false | string
+              generate?: null | RandomString
+            }
+          >,
+        ) => Value.dynamicTextarea<Store>(getA),
+        dynamicNumber: (
+          getA: LazyBuild<
+            Store,
+            {
+              name: string
+              description?: string | null
+              warning?: string | null
+              required: RequiredDefault<number>
+              min?: number | null
+              max?: number | null
+              /** Default = '1' */
+              step?: number | null
+              integer: boolean
+              units?: string | null
+              placeholder?: string | null
+              disabled?: false | string
+            }
+          >,
+        ) => Value.dynamicNumber<Store>(getA),
+        dynamicColor: (
+          getA: LazyBuild<
+            Store,
+            {
+              name: string
+              description?: string | null
+              warning?: string | null
+              required: RequiredDefault<string>
+ 
+              disabled?: false | string
+            }
+          >,
+        ) => Value.dynamicColor<Store>(getA),
+        dynamicDatetime: (
+          getA: LazyBuild<
+            Store,
+            {
+              name: string
+              description?: string | null
+              warning?: string | null
+              required: RequiredDefault<string>
+              /** Default = 'datetime-local' */
+              inputmode?: ValueSpecDatetime["inputmode"]
+              min?: string | null
+              max?: string | null
+              disabled?: false | string
+            }
+          >,
+        ) => Value.dynamicDatetime<Store>(getA),
+        dynamicSelect: (
+          getA: LazyBuild<
+            Store,
+            {
+              name: string
+              description?: string | null
+              warning?: string | null
+              required: RequiredDefault<string>
+              values: Record<string, string>
+              disabled?: false | string
+            }
+          >,
+        ) => Value.dynamicSelect<Store>(getA),
+        dynamicMultiselect: (
+          getA: LazyBuild<
+            Store,
+            {
+              name: string
+              description?: string | null
+              warning?: string | null
+              default: string[]
+              values: Record<string, string>
+              minLength?: number | null
+              maxLength?: number | null
+              disabled?: false | string
+            }
+          >,
+        ) => Value.dynamicMultiselect<Store>(getA),
+        filteredUnion: <
+          Required extends RequiredDefault<string>,
+          Type extends Record<string, any>,
+        >(
+          getDisabledFn: LazyBuild<Store, string[]>,
+          a: {
+            name: string
+            description?: string | null
+            warning?: string | null
+            required: Required
+          },
+          aVariants: Variants<Type, Store> | Variants<Type, never>,
+        ) =>
+          Value.filteredUnion<Required, Type, Store>(
+            getDisabledFn,
+            a,
+            aVariants,
+          ),
+ 
+        dynamicUnion: <
+          Required extends RequiredDefault<string>,
+          Type extends Record<string, any>,
+        >(
+          getA: LazyBuild<
+            Store,
+            {
+              disabled: string[] | false | string
+              name: string
+              description?: string | null
+              warning?: string | null
+              required: Required
+            }
+          >,
+          aVariants: Variants<Type, Store> | Variants<Type, never>,
+        ) => Value.dynamicUnion<Required, Type, Store>(getA, aVariants),
+      },
+      Variants: {
+        of: <
+          VariantValues extends {
+            [K in string]: {
+              name: string
+              spec: Config<any, Store>
+            }
+          },
+        >(
+          a: VariantValues,
+        ) => Variants.of<VariantValues, Store>(a),
+      },
+    }
+  }
+}
+ 
+export async function runCommand<Manifest extends T.Manifest>(
+  effects: Effects,
+  image: { id: keyof Manifest["images"] & T.ImageId; sharedRun?: boolean },
+  command: string | [string, ...string[]],
+  options: CommandOptions & {
+    mounts?: { path: string; options: MountOptions }[]
+  },
+): Promise<{ stdout: string | Buffer; stderr: string | Buffer }> {
+  const commands = splitCommand(command)
+  return SubContainer.with(
+    effects,
+    image,
+    options.mounts || [],
+    (subcontainer) => subcontainer.exec(commands),
+  )
+}
+function nullifyProperties(value: T.SdkPropertiesReturn): T.PropertiesReturn {
+  return Object.fromEntries(
+    Object.entries(value).map(([k, v]) => [k, nullifyProperties_(v)]),
+  )
+}
+function nullifyProperties_(value: T.SdkPropertiesValue): T.PropertiesValue {
+  Iif (value.type === "string") {
+    return { description: null, copyable: null, qr: null, ...value }
+  }
+  return {
+    description: null,
+    ...value,
+    value: Object.fromEntries(
+      Object.entries(value.value).map(([k, v]) => [k, nullifyProperties_(v)]),
+    ),
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/actions/createAction.ts.html b/sdk/lib/coverage/lcov-report/lib/actions/createAction.ts.html new file mode 100644 index 000000000..3096e8d71 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/actions/createAction.ts.html @@ -0,0 +1,352 @@ + + + + + + Code coverage report for lib/actions/createAction.ts + + + + + + + + + +
+
+

All files / lib/actions createAction.ts

+
+ +
+ 11.76% + Statements + 2/17 +
+ + +
+ 0% + Branches + 0/2 +
+ + +
+ 0% + Functions + 0/7 +
+ + +
+ 11.76% + Lines + 2/17 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90  +  +  +  +  +  +  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +5x + 
import * as T from "../types"
+import { Config, ExtractConfigType } from "../config/builder/config"
+ 
+import { ActionMetadata, ActionResult, Effects, ExportedAction } from "../types"
+ 
+export type MaybeFn<Manifest extends T.Manifest, Store, Value> =
+  | Value
+  | ((options: { effects: Effects }) => Promise<Value> | Value)
+export class CreatedAction<
+  Manifest extends T.Manifest,
+  Store,
+  ConfigType extends
+    | Record<string, any>
+    | Config<any, Store>
+    | Config<any, never>,
+  Type extends Record<string, any> = ExtractConfigType<ConfigType>,
+> {
+  private constructor(
+    public readonly id: string,
+    public readonly myMetadata: MaybeFn<
+      Manifest,
+      Store,
+      Omit<ActionMetadata, "input">
+    >,
+    readonly fn: (options: {
+      effects: Effects
+      input: Type
+    }) => Promise<ActionResult>,
+    readonly input: Config<Type, Store>,
+    public validator = input.validator,
+  ) {}
+ 
+  static of<
+    Manifest extends T.Manifest,
+    Store,
+    ConfigType extends
+      | Record<string, any>
+      | Config<any, any>
+      | Config<any, never>,
+    Type extends Record<string, any> = ExtractConfigType<ConfigType>,
+  >(
+    id: string,
+    metadata: MaybeFn<Manifest, Store, Omit<ActionMetadata, "input">>,
+    fn: (options: { effects: Effects; input: Type }) => Promise<ActionResult>,
+    inputConfig: Config<Type, Store> | Config<Type, never>,
+  ) {
+    return new CreatedAction<Manifest, Store, ConfigType, Type>(
+      id,
+      metadata,
+      fn,
+      inputConfig as Config<Type, Store>,
+    )
+  }
+ 
+  exportedAction: ExportedAction = ({ effects, input }) => {
+    return this.fn({
+      effects,
+      input: this.validator.unsafeCast(input),
+    })
+  }
+ 
+  run = async ({ effects, input }: { effects: Effects; input?: Type }) => {
+    return this.fn({
+      effects,
+      input: this.validator.unsafeCast(input),
+    })
+  }
+ 
+  async metadata(options: { effects: Effects }) {
+    Iif (this.myMetadata instanceof Function)
+      return await this.myMetadata(options)
+    return this.myMetadata
+  }
+ 
+  async ActionMetadata(options: { effects: Effects }): Promise<ActionMetadata> {
+    return {
+      ...(await this.metadata(options)),
+      input: await this.input.build(options),
+    }
+  }
+ 
+  async getConfig({ effects }: { effects: Effects }) {
+    return this.input.build({
+      effects,
+    })
+  }
+}
+ 
+export const createAction = CreatedAction.of
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/actions/index.html b/sdk/lib/coverage/lcov-report/lib/actions/index.html new file mode 100644 index 000000000..243077876 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/actions/index.html @@ -0,0 +1,131 @@ + + + + + + Code coverage report for lib/actions + + + + + + + + + +
+
+

All files lib/actions

+
+ +
+ 10.71% + Statements + 3/28 +
+ + +
+ 0% + Branches + 0/2 +
+ + +
+ 0% + Functions + 0/12 +
+ + +
+ 10.71% + Lines + 3/28 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
createAction.ts +
+
11.76%2/170%0/20%0/711.76%2/17
setupActions.ts +
+
9.09%1/11100%0/00%0/59.09%1/11
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/actions/setupActions.ts.html b/sdk/lib/coverage/lcov-report/lib/actions/setupActions.ts.html new file mode 100644 index 000000000..dc27a3b93 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/actions/setupActions.ts.html @@ -0,0 +1,172 @@ + + + + + + Code coverage report for lib/actions/setupActions.ts + + + + + + + + + +
+
+

All files / lib/actions setupActions.ts

+
+ +
+ 9.09% + Statements + 1/11 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 0% + Functions + 0/5 +
+ + +
+ 9.09% + Lines + 1/11 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30  +  +  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import * as T from "../types"
+import { Effects, ExpectedExports } from "../types"
+import { CreatedAction } from "./createAction"
+ 
+export function setupActions<Manifest extends T.Manifest, Store>(
+  ...createdActions: CreatedAction<Manifest, Store, any>[]
+) {
+  const myActions = async (options: { effects: Effects }) => {
+    const actions: Record<string, CreatedAction<Manifest, Store, any>> = {}
+    for (const action of createdActions) {
+      actions[action.id] = action
+    }
+    return actions
+  }
+  const answer: {
+    actions: ExpectedExports.actions
+    actionsMetadata: ExpectedExports.actionsMetadata
+  } = {
+    actions(options: { effects: Effects }) {
+      return myActions(options)
+    },
+    async actionsMetadata({ effects }: { effects: Effects }) {
+      return Promise.all(
+        createdActions.map((x) => x.ActionMetadata({ effects })),
+      )
+    },
+  }
+  return answer
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/backup/Backups.ts.html b/sdk/lib/coverage/lcov-report/lib/backup/Backups.ts.html new file mode 100644 index 000000000..7fe247c5f --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/backup/Backups.ts.html @@ -0,0 +1,712 @@ + + + + + + Code coverage report for lib/backup/Backups.ts + + + + + + + + + +
+
+

All files / lib/backup Backups.ts

+
+ +
+ 8.21% + Statements + 6/73 +
+ + +
+ 0% + Branches + 0/9 +
+ + +
+ 0% + Functions + 0/22 +
+ + +
+ 8.57% + Lines + 6/70 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210  +  +5x +  +5x +  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +5x +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import * as T from "../types"
+ 
+import * as child_process from "child_process"
+import { promises as fsPromises } from "fs"
+import { asError } from "../util"
+ 
+export type BACKUP = "BACKUP"
+export const DEFAULT_OPTIONS: T.BackupOptions = {
+  delete: true,
+  force: true,
+  ignoreExisting: false,
+  exclude: [],
+}
+export type BackupSet<Volumes extends string> = {
+  srcPath: string
+  srcVolume: Volumes | BACKUP
+  dstPath: string
+  dstVolume: Volumes | BACKUP
+  options?: Partial<T.BackupOptions>
+}
+/**
+ * This utility simplifies the volume backup process.
+ * ```ts
+ * export const { createBackup, restoreBackup } = Backups.volumes("main").build();
+ * ```
+ *
+ * Changing the options of the rsync, (ie exludes) use either
+ * ```ts
+ *  Backups.volumes("main").set_options({exclude: ['bigdata/']}).volumes('excludedVolume').build()
+ * // or
+ *  Backups.with_options({exclude: ['bigdata/']}).volumes('excludedVolume').build()
+ * ```
+ *
+ * Using the more fine control, using the addSets for more control
+ * ```ts
+ * Backups.addSets({
+ * srcVolume: 'main', srcPath:'smallData/', dstPath: 'main/smallData/', dstVolume: : Backups.BACKUP
+ * }, {
+ * srcVolume: 'main', srcPath:'bigData/', dstPath: 'main/bigData/', dstVolume: : Backups.BACKUP, options: {exclude:['bigData/excludeThis']}}
+ * ).build()q
+ * ```
+ */
+export class Backups<M extends T.Manifest> {
+  static BACKUP: BACKUP = "BACKUP"
+ 
+  private constructor(
+    private options = DEFAULT_OPTIONS,
+    private backupSet = [] as BackupSet<M["volumes"][number]>[],
+  ) {}
+  static volumes<M extends T.Manifest = never>(
+    ...volumeNames: Array<M["volumes"][0]>
+  ): Backups<M> {
+    return new Backups<M>().addSets(
+      ...volumeNames.map((srcVolume) => ({
+        srcVolume,
+        srcPath: "./",
+        dstPath: `./${srcVolume}/`,
+        dstVolume: Backups.BACKUP,
+      })),
+    )
+  }
+  static addSets<M extends T.Manifest = never>(
+    ...options: BackupSet<M["volumes"][0]>[]
+  ) {
+    return new Backups().addSets(...options)
+  }
+  static with_options<M extends T.Manifest = never>(
+    options?: Partial<T.BackupOptions>,
+  ) {
+    return new Backups({ ...DEFAULT_OPTIONS, ...options })
+  }
+ 
+  static withOptions = Backups.with_options
+  setOptions(options?: Partial<T.BackupOptions>) {
+    this.options = {
+      ...this.options,
+      ...options,
+    }
+    return this
+  }
+  volumes(...volumeNames: Array<M["volumes"][0]>) {
+    return this.addSets(
+      ...volumeNames.map((srcVolume) => ({
+        srcVolume,
+        srcPath: "./",
+        dstPath: `./${srcVolume}/`,
+        dstVolume: Backups.BACKUP,
+      })),
+    )
+  }
+  addSets(...options: BackupSet<M["volumes"][0]>[]) {
+    options.forEach((x) =>
+      this.backupSet.push({ ...x, options: { ...this.options, ...x.options } }),
+    )
+    return this
+  }
+  build(pathMaker: T.PathMaker) {
+    const createBackup: T.ExpectedExports.createBackup = async ({
+      effects,
+    }) => {
+      for (const item of this.backupSet) {
+        const rsyncResults = await runRsync(
+          {
+            dstPath: item.dstPath,
+            dstVolume: item.dstVolume,
+            options: { ...this.options, ...item.options },
+            srcPath: item.srcPath,
+            srcVolume: item.srcVolume,
+          },
+          pathMaker,
+        )
+        await rsyncResults.wait()
+      }
+      return
+    }
+    const restoreBackup: T.ExpectedExports.restoreBackup = async ({
+      effects,
+    }) => {
+      for (const item of this.backupSet) {
+        const rsyncResults = await runRsync(
+          {
+            dstPath: item.dstPath,
+            dstVolume: item.dstVolume,
+            options: { ...this.options, ...item.options },
+            srcPath: item.srcPath,
+            srcVolume: item.srcVolume,
+          },
+          pathMaker,
+        )
+        await rsyncResults.wait()
+      }
+      return
+    }
+    return { createBackup, restoreBackup }
+  }
+}
+function notEmptyPath(file: string) {
+  return ["", ".", "./"].indexOf(file) === -1
+}
+async function runRsync(
+  rsyncOptions: {
+    srcVolume: string
+    dstVolume: string
+    srcPath: string
+    dstPath: string
+    options: T.BackupOptions
+  },
+  pathMaker: T.PathMaker,
+): Promise<{
+  id: () => Promise<string>
+  wait: () => Promise<null>
+  progress: () => Promise<number>
+}> {
+  const { srcVolume, dstVolume, srcPath, dstPath, options } = rsyncOptions
+ 
+  const command = "rsync"
+  const args: string[] = []
+  Iif (options.delete) {
+    args.push("--delete")
+  }
+  Iif (options.force) {
+    args.push("--force")
+  }
+  Iif (options.ignoreExisting) {
+    args.push("--ignore-existing")
+  }
+  for (const exclude of options.exclude) {
+    args.push(`--exclude=${exclude}`)
+  }
+  args.push("-actAXH")
+  args.push("--info=progress2")
+  args.push("--no-inc-recursive")
+  args.push(pathMaker({ volume: srcVolume, path: srcPath }))
+  args.push(pathMaker({ volume: dstVolume, path: dstPath }))
+  const spawned = child_process.spawn(command, args, { detached: true })
+  let percentage = 0.0
+  spawned.stdout.on("data", (data: unknown) => {
+    const lines = String(data).replace("\r", "\n").split("\n")
+    for (const line of lines) {
+      const parsed = /$([0-9.]+)%/.exec(line)?.[1]
+      Iif (!parsed) continue
+      percentage = Number.parseFloat(parsed)
+    }
+  })
+ 
+  spawned.stderr.on("data", (data: unknown) => {
+    console.error(`Backups.runAsync`, asError(data))
+  })
+ 
+  const id = async () => {
+    const pid = spawned.pid
+    Iif (pid === undefined) {
+      throw new Error("rsync process has no pid")
+    }
+    return String(pid)
+  }
+  const waitPromise = new Promise<null>((resolve, reject) => {
+    spawned.on("exit", (code: any) => {
+      if (code === 0) {
+        resolve(null)
+      } else {
+        reject(new Error(`rsync exited with code ${code}`))
+      }
+    })
+  })
+  const wait = () => waitPromise
+  const progress = () => Promise.resolve(percentage)
+  return { id, wait, progress }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/backup/index.html b/sdk/lib/coverage/lcov-report/lib/backup/index.html new file mode 100644 index 000000000..f0d7d5a50 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/backup/index.html @@ -0,0 +1,131 @@ + + + + + + Code coverage report for lib/backup + + + + + + + + + +
+
+

All files lib/backup

+
+ +
+ 8.79% + Statements + 8/91 +
+ + +
+ 0% + Branches + 0/11 +
+ + +
+ 0% + Functions + 0/27 +
+ + +
+ 9.09% + Lines + 8/88 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
Backups.ts +
+
8.21%6/730%0/90%0/228.57%6/70
setupBackups.ts +
+
11.11%2/180%0/20%0/511.11%2/18
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/backup/setupBackups.ts.html b/sdk/lib/coverage/lcov-report/lib/backup/setupBackups.ts.html new file mode 100644 index 000000000..79fbd3b7e --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/backup/setupBackups.ts.html @@ -0,0 +1,220 @@ + + + + + + Code coverage report for lib/backup/setupBackups.ts + + + + + + + + + +
+
+

All files / lib/backup setupBackups.ts

+
+ +
+ 11.11% + Statements + 2/18 +
+ + +
+ 0% + Branches + 0/2 +
+ + +
+ 0% + Functions + 0/5 +
+ + +
+ 11.11% + Lines + 2/18 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +465x +  +  +  +  +  +  +  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { Backups } from "./Backups"
+ 
+import * as T from "../types"
+import { _ } from "../util"
+ 
+export type SetupBackupsParams<M extends T.Manifest> = Array<
+  M["volumes"][number] | Backups<M>
+>
+ 
+export function setupBackups<M extends T.Manifest>(
+  manifest: M,
+  ...args: _<SetupBackupsParams<M>>
+) {
+  const backups = Array<Backups<M>>()
+  const volumes = new Set<M["volumes"][0]>()
+  for (const arg of args) {
+    if (arg instanceof Backups) {
+      backups.push(arg)
+    } else {
+      volumes.add(arg)
+    }
+  }
+  backups.push(Backups.volumes(...volumes))
+  const answer: {
+    createBackup: T.ExpectedExports.createBackup
+    restoreBackup: T.ExpectedExports.restoreBackup
+  } = {
+    get createBackup() {
+      return (async (options) => {
+        for (const backup of backups) {
+          await backup.build(options.pathMaker).createBackup(options)
+        }
+      }) as T.ExpectedExports.createBackup
+    },
+    get restoreBackup() {
+      return (async (options) => {
+        for (const backup of backups) {
+          await backup.build(options.pathMaker).restoreBackup(options)
+        }
+        await options.effects.setDataVersion({ version: manifest.version })
+      }) as T.ExpectedExports.restoreBackup
+    },
+  }
+  return answer
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/config/builder/config.ts.html b/sdk/lib/coverage/lcov-report/lib/config/builder/config.ts.html new file mode 100644 index 000000000..cc01afc62 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/config/builder/config.ts.html @@ -0,0 +1,496 @@ + + + + + + Code coverage report for lib/config/builder/config.ts + + + + + + + + + +
+
+

All files / lib/config/builder config.ts

+
+ +
+ 92.85% + Statements + 13/14 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 75% + Functions + 3/4 +
+ + +
+ 92.85% + Lines + 13/14 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138  +  +  +  +6x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +6x +  +62x +  +  +62x +  +  +6x +  +  +6x +5x +  +6x +  +  +  +  +  +  +62x +  +  +62x +131x +  +62x +62x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { ValueSpec } from "../configTypes"
+import { Value } from "./value"
+import { _ } from "../../util"
+import { Effects } from "../../types"
+import { Parser, object } from "ts-matches"
+ 
+export type LazyBuildOptions<Store> = {
+  effects: Effects
+}
+export type LazyBuild<Store, ExpectedOut> = (
+  options: LazyBuildOptions<Store>,
+) => Promise<ExpectedOut> | ExpectedOut
+ 
+// prettier-ignore
+export type ExtractConfigType<A extends Record<string, any> | Config<Record<string, any>, any> | Config<Record<string, any>, never>> = 
+  A extends Config<infer B, any> | Config<infer B, never> ? B :
+  A
+ 
+export type ConfigSpecOf<A extends Record<string, any>, Store = never> = {
+  [K in keyof A]: Value<A[K], Store>
+}
+ 
+export type MaybeLazyValues<A> = LazyBuild<any, A> | A
+/**
+ * Configs are the specs that are used by the os configuration form for this service.
+ * Here is an example of a simple configuration
+  ```ts
+    const smallConfig = Config.of({
+      test: Value.boolean({
+        name: "Test",
+        description: "This is the description for the test",
+        warning: null,
+        default: false,
+      }),
+    });
+  ```
+ 
+  The idea of a config is that now the form is going to ask for
+  Test: [ ] and the value is going to be checked as a boolean.
+  There are more complex values like selects, lists, and objects. See {@link Value}
+ 
+  Also, there is the ability to get a validator/parser from this config spec.
+  ```ts
+  const matchSmallConfig = smallConfig.validator();
+  type SmallConfig = typeof matchSmallConfig._TYPE;
+  ```
+ 
+  Here is an example of a more complex configuration which came from a configuration for a service
+  that works with bitcoin, like c-lightning.
+  ```ts
+ 
+    export const hostname = Value.string({
+  name: "Hostname",
+  default: null,
+  description: "Domain or IP address of bitcoin peer",
+  warning: null,
+  required: true,
+  masked: false,
+  placeholder: null,
+  pattern:
+    "(^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$)|((^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$)|(^[a-z2-7]{16}\\.onion$)|(^([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]$))",
+  patternDescription:
+    "Must be either a domain name, or an IPv4 or IPv6 address. Do not include protocol scheme (eg 'http://') or port.",
+});
+export const port = Value.number({
+  name: "Port",
+  default: null,
+  description: "Port that peer is listening on for inbound p2p connections",
+  warning: null,
+  required: false,
+  range: "[0,65535]",
+  integral: true,
+  units: null,
+  placeholder: null,
+});
+export const addNodesSpec = Config.of({ hostname: hostname, port: port });
+ 
+  ```
+ */
+export class Config<Type extends Record<string, any>, Store = never> {
+  private constructor(
+    private readonly spec: {
+      [K in keyof Type]: Value<Type[K], Store> | Value<Type[K], never>
+    },
+    public validator: Parser<unknown, Type>,
+  ) {}
+  async build(options: LazyBuildOptions<Store>) {
+    const answer = {} as {
+      [K in keyof Type]: ValueSpec
+    }
+    for (const k in this.spec) {
+      answer[k] = await this.spec[k].build(options as any)
+    }
+    return answer
+  }
+ 
+  static of<
+    Spec extends Record<string, Value<any, Store> | Value<any, never>>,
+    Store = never,
+  >(spec: Spec) {
+    const validatorObj = {} as {
+      [K in keyof Spec]: Parser<unknown, any>
+    }
+    for (const key in spec) {
+      validatorObj[key] = spec[key].validator
+    }
+    const validator = object(validatorObj)
+    return new Config<
+      {
+        [K in keyof Spec]: Spec[K] extends
+          | Value<infer T, Store>
+          | Value<infer T, never>
+          ? T
+          : never
+      },
+      Store
+    >(spec, validator as any)
+  }
+ 
+  /**
+   * Use this during the times that the input needs a more specific type.
+   * Used in types that the value/ variant/ list/ config is constructed somewhere else.
+  ```ts
+  const a = Config.text({
+    name: "a",
+    required: false,
+  })
+ 
+  return Config.of<Store>()({
+    myValue: a.withStore(),
+  })
+  ```
+   */
+  withStore<NewStore extends Store extends never ? any : Store>() {
+    return this as any as Config<Type, NewStore>
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/config/builder/index.html b/sdk/lib/coverage/lcov-report/lib/config/builder/index.html new file mode 100644 index 000000000..e43ffb4b2 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/config/builder/index.html @@ -0,0 +1,161 @@ + + + + + + Code coverage report for lib/config/builder + + + + + + + + + +
+
+

All files lib/config/builder

+
+ +
+ 84.61% + Statements + 99/117 +
+ + +
+ 55.17% + Branches + 16/29 +
+ + +
+ 78.26% + Functions + 54/69 +
+ + +
+ 84.34% + Lines + 97/115 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
config.ts +
+
92.85%13/14100%0/075%3/492.85%13/14
list.ts +
+
95%19/20100%0/087.5%7/895%19/20
value.ts +
+
78.57%55/7055.17%16/2976.92%40/5277.94%53/68
variants.ts +
+
92.3%12/13100%0/080%4/592.3%12/13
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/config/builder/list.ts.html b/sdk/lib/coverage/lcov-report/lib/config/builder/list.ts.html new file mode 100644 index 000000000..50934aa2b --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/config/builder/list.ts.html @@ -0,0 +1,649 @@ + + + + + + Code coverage report for lib/config/builder/list.ts + + + + + + + + + +
+
+

All files / lib/config/builder list.ts

+
+ +
+ 95% + Statements + 19/20 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 87.5% + Functions + 7/8 +
+ + +
+ 95% + Lines + 19/20 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189  +  +  +  +  +  +  +  +  +6x +  +  +  +  +  +  +  +  +  +  +  +  +  +6x +  +11x +11x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +4x +1x +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +1x +1x +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +6x +1x +1x +1x +  +  +  +  +  +  +1x +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { Config, LazyBuild } from "./config"
+import {
+  ListValueSpecText,
+  Pattern,
+  RandomString,
+  UniqueBy,
+  ValueSpecList,
+  ValueSpecListOf,
+} from "../configTypes"
+import { Parser, arrayOf, number, string } from "ts-matches"
+/**
+ * Used as a subtype of Value.list
+```ts
+export const authorizationList = List.string({
+  "name": "Authorization",
+  "range": "[0,*)",
+  "default": [],
+  "description": "Username and hashed password for JSON-RPC connections. RPC clients connect using the usual http basic authentication.",
+  "warning": null
+}, {"masked":false,"placeholder":null,"pattern":"^[a-zA-Z0-9_-]+:([0-9a-fA-F]{2})+\\$([0-9a-fA-F]{2})+$","patternDescription":"Each item must be of the form \"<USERNAME>:<SALT>$<HASH>\"."});
+export const auth = Value.list(authorizationList);
+```
+*/
+export class List<Type, Store> {
+  private constructor(
+    public build: LazyBuild<Store, ValueSpecList>,
+    public validator: Parser<unknown, Type>,
+  ) {}
+  static text(
+    a: {
+      name: string
+      description?: string | null
+      warning?: string | null
+      /** Default = [] */
+      default?: string[]
+      minLength?: number | null
+      maxLength?: number | null
+    },
+    aSpec: {
+      /** Default = false */
+      masked?: boolean
+      placeholder?: string | null
+      minLength?: number | null
+      maxLength?: number | null
+      patterns: Pattern[]
+      /** Default = "text" */
+      inputmode?: ListValueSpecText["inputmode"]
+      generate?: null | RandomString
+    },
+  ) {
+    return new List<string[], never>(() => {
+      const spec = {
+        type: "text" as const,
+        placeholder: null,
+        minLength: null,
+        maxLength: null,
+        masked: false,
+        inputmode: "text" as const,
+        generate: null,
+        ...aSpec,
+      }
+      const built: ValueSpecListOf<"text"> = {
+        description: null,
+        warning: null,
+        default: [],
+        type: "list" as const,
+        minLength: null,
+        maxLength: null,
+        disabled: false,
+        ...a,
+        spec,
+      }
+      return built
+    }, arrayOf(string))
+  }
+  static dynamicText<Store = never>(
+    getA: LazyBuild<
+      Store,
+      {
+        name: string
+        description?: string | null
+        warning?: string | null
+        /** Default = [] */
+        default?: string[]
+        minLength?: number | null
+        maxLength?: number | null
+        disabled?: false | string
+        generate?: null | RandomString
+        spec: {
+          /** Default = false */
+          masked?: boolean
+          placeholder?: string | null
+          minLength?: number | null
+          maxLength?: number | null
+          patterns: Pattern[]
+          /** Default = "text" */
+          inputmode?: ListValueSpecText["inputmode"]
+        }
+      }
+    >,
+  ) {
+    return new List<string[], Store>(async (options) => {
+      const { spec: aSpec, ...a } = await getA(options)
+      const spec = {
+        type: "text" as const,
+        placeholder: null,
+        minLength: null,
+        maxLength: null,
+        masked: false,
+        inputmode: "text" as const,
+        generate: null,
+        ...aSpec,
+      }
+      const built: ValueSpecListOf<"text"> = {
+        description: null,
+        warning: null,
+        default: [],
+        type: "list" as const,
+        minLength: null,
+        maxLength: null,
+        disabled: false,
+        ...a,
+        spec,
+      }
+      return built
+    }, arrayOf(string))
+  }
+  static obj<Type extends Record<string, any>, Store>(
+    a: {
+      name: string
+      description?: string | null
+      warning?: string | null
+      /** Default [] */
+      default?: []
+      minLength?: number | null
+      maxLength?: number | null
+    },
+    aSpec: {
+      spec: Config<Type, Store>
+      displayAs?: null | string
+      uniqueBy?: null | UniqueBy
+    },
+  ) {
+    return new List<Type[], Store>(async (options) => {
+      const { spec: previousSpecSpec, ...restSpec } = aSpec
+      const specSpec = await previousSpecSpec.build(options)
+      const spec = {
+        type: "object" as const,
+        displayAs: null,
+        uniqueBy: null,
+        ...restSpec,
+        spec: specSpec,
+      }
+      const value = {
+        spec,
+        default: [],
+        ...a,
+      }
+      return {
+        description: null,
+        warning: null,
+        minLength: null,
+        maxLength: null,
+        type: "list" as const,
+        disabled: false,
+        ...value,
+      }
+    }, arrayOf(aSpec.spec.validator))
+  }
+ 
+  /**
+   * Use this during the times that the input needs a more specific type.
+   * Used in types that the value/ variant/ list/ config is constructed somewhere else.
+  ```ts
+  const a = Config.text({
+    name: "a",
+    required: false,
+  })
+ 
+  return Config.of<Store>()({
+    myValue: a.withStore(),
+  })
+  ```
+   */
+  withStore<NewStore extends Store extends never ? any : Store>() {
+    return this as any as List<Type, NewStore>
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/config/builder/value.ts.html b/sdk/lib/coverage/lcov-report/lib/config/builder/value.ts.html new file mode 100644 index 000000000..dd982b15c --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/config/builder/value.ts.html @@ -0,0 +1,2434 @@ + + + + + + Code coverage report for lib/config/builder/value.ts + + + + + + + + + +
+
+

All files / lib/config/builder value.ts

+
+ +
+ 78.57% + Statements + 55/70 +
+ + +
+ 55.17% + Branches + 16/29 +
+ + +
+ 76.92% + Functions + 40/52 +
+ + +
+ 77.94% + Lines + 53/68 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335 +336 +337 +338 +339 +340 +341 +342 +343 +344 +345 +346 +347 +348 +349 +350 +351 +352 +353 +354 +355 +356 +357 +358 +359 +360 +361 +362 +363 +364 +365 +366 +367 +368 +369 +370 +371 +372 +373 +374 +375 +376 +377 +378 +379 +380 +381 +382 +383 +384 +385 +386 +387 +388 +389 +390 +391 +392 +393 +394 +395 +396 +397 +398 +399 +400 +401 +402 +403 +404 +405 +406 +407 +408 +409 +410 +411 +412 +413 +414 +415 +416 +417 +418 +419 +420 +421 +422 +423 +424 +425 +426 +427 +428 +429 +430 +431 +432 +433 +434 +435 +436 +437 +438 +439 +440 +441 +442 +443 +444 +445 +446 +447 +448 +449 +450 +451 +452 +453 +454 +455 +456 +457 +458 +459 +460 +461 +462 +463 +464 +465 +466 +467 +468 +469 +470 +471 +472 +473 +474 +475 +476 +477 +478 +479 +480 +481 +482 +483 +484 +485 +486 +487 +488 +489 +490 +491 +492 +493 +494 +495 +496 +497 +498 +499 +500 +501 +502 +503 +504 +505 +506 +507 +508 +509 +510 +511 +512 +513 +514 +515 +516 +517 +518 +519 +520 +521 +522 +523 +524 +525 +526 +527 +528 +529 +530 +531 +532 +533 +534 +535 +536 +537 +538 +539 +540 +541 +542 +543 +544 +545 +546 +547 +548 +549 +550 +551 +552 +553 +554 +555 +556 +557 +558 +559 +560 +561 +562 +563 +564 +565 +566 +567 +568 +569 +570 +571 +572 +573 +574 +575 +576 +577 +578 +579 +580 +581 +582 +583 +584 +585 +586 +587 +588 +589 +590 +591 +592 +593 +594 +595 +596 +597 +598 +599 +600 +601 +602 +603 +604 +605 +606 +607 +608 +609 +610 +611 +612 +613 +614 +615 +616 +617 +618 +619 +620 +621 +622 +623 +624 +625 +626 +627 +628 +629 +630 +631 +632 +633 +634 +635 +636 +637 +638 +639 +640 +641 +642 +643 +644 +645 +646 +647 +648 +649 +650 +651 +652 +653 +654 +655 +656 +657 +658 +659 +660 +661 +662 +663 +664 +665 +666 +667 +668 +669 +670 +671 +672 +673 +674 +675 +676 +677 +678 +679 +680 +681 +682 +683 +684 +685 +686 +687 +688 +689 +690 +691 +692 +693 +694 +695 +696 +697 +698 +699 +700 +701 +702 +703 +704 +705 +706 +707 +708 +709 +710 +711 +712 +713 +714 +715 +716 +717 +718 +719 +720 +721 +722 +723 +724 +725 +726 +727 +728 +729 +730 +731 +732 +733 +734 +735 +736 +737 +738 +739 +740 +741 +742 +743 +744 +745 +746 +747 +748 +749 +750 +751 +752 +753 +754 +755 +756 +757 +758 +759 +760 +761 +762 +763 +764 +765 +766 +767 +768 +769 +770 +771 +772 +773 +774 +775 +776 +777 +778 +779 +780 +781 +782 +783 +784  +  +  +  +  +  +  +  +  +  +  +  +  +  +6x +  +  +  +  +  +  +  +  +  +  +  +6x +  +  +  +  +  +  +  +  +  +  +  +16x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +6x +5x +  +  +  +  +  +  +  +  +89x +28x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +6x +  +169x +169x +  +  +  +  +  +  +  +  +  +  +34x +4x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +40x +4x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +3x +5x +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +3x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +1x +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +28x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +1x +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +2x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +1x +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +2x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +1x +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +6x +1x +  +  +  +  +  +  +  +  +  +  +10x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +1x +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +4x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +1x +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +17x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +6x +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +1x +1x +  +  +  +  +  +  +  +  +  +  +  +  +11x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { Config, LazyBuild, LazyBuildOptions } from "./config"
+import { List } from "./list"
+import { Variants } from "./variants"
+import {
+  FilePath,
+  Pattern,
+  RandomString,
+  ValueSpec,
+  ValueSpecDatetime,
+  ValueSpecText,
+  ValueSpecTextarea,
+} from "../configTypes"
+import { DefaultString } from "../configTypes"
+import { _ } from "../../util"
+import {
+  Parser,
+  anyOf,
+  arrayOf,
+  boolean,
+  literal,
+  literals,
+  number,
+  object,
+  string,
+  unknown,
+} from "ts-matches"
+import { once } from "../../util/once"
+ 
+export type RequiredDefault<A> =
+  | false
+  | {
+      default: A | null
+    }
+ 
+function requiredLikeToAbove<Input extends RequiredDefault<A>, A>(
+  requiredLike: Input,
+) {
+  // prettier-ignore
+  return {
+    required: (typeof requiredLike === 'object' ? true : requiredLike) as (
+      Input extends { default: unknown} ? true:
+      Input extends true ? true :
+      false
+    ),
+    default:(typeof requiredLike === 'object' ? requiredLike.default : null) as (
+      Input extends { default: infer Default } ? Default :
+      null
+    )
+  };
+}
+type AsRequired<Type, MaybeRequiredType> = MaybeRequiredType extends
+  | { default: unknown }
+  | never
+  ? Type
+  : Type | null | undefined
+ 
+type InputAsRequired<A, Type> = A extends
+  | { required: { default: any } | never }
+  | never
+  ? Type
+  : Type | null | undefined
+const testForAsRequiredParser = once(
+  () => object({ required: object({ default: unknown }) }).test,
+)
+function asRequiredParser<
+  Type,
+  Input,
+  Return extends
+    | Parser<unknown, Type>
+    | Parser<unknown, Type | null | undefined>,
+>(parser: Parser<unknown, Type>, input: Input): Return {
+  if (testForAsRequiredParser()(input)) return parser as any
+  return parser.optional() as any
+}
+ 
+/**
+ * A value is going to be part of the form in the FE of the OS.
+ * Something like a boolean, a string, a number, etc.
+ * in the fe it will ask for the name of value, and use the rest of the value to determine how to render it.
+ * While writing with a value, you will start with `Value.` then let the IDE suggest the rest.
+ * for things like string, the options are going to be in {}.
+ * Keep an eye out for another config builder types as params.
+ * Note, usually this is going to be used in a `Config` {@link Config} builder.
+ ```ts
+const username = Value.string({
+  name: "Username",
+  default: "bitcoin",
+  description: "The username for connecting to Bitcoin over RPC.",
+  warning: null,
+  required: true,
+  masked: true,
+  placeholder: null,
+  pattern: "^[a-zA-Z0-9_]+$",
+  patternDescription: "Must be alphanumeric (can contain underscore).",
+});
+ ```
+ */
+export class Value<Type, Store> {
+  protected constructor(
+    public build: LazyBuild<Store, ValueSpec>,
+    public validator: Parser<unknown, Type>,
+  ) {}
+  static toggle(a: {
+    name: string
+    description?: string | null
+    warning?: string | null
+    default: boolean
+    /**  Immutable means it can only be configed at the first config then never again 
+    Default is false */
+    immutable?: boolean
+  }) {
+    return new Value<boolean, never>(
+      async () => ({
+        description: null,
+        warning: null,
+        type: "toggle" as const,
+        disabled: false,
+        immutable: a.immutable ?? false,
+        ...a,
+      }),
+      boolean,
+    )
+  }
+  static dynamicToggle<Store = never>(
+    a: LazyBuild<
+      Store,
+      {
+        name: string
+        description?: string | null
+        warning?: string | null
+        default: boolean
+        disabled?: false | string
+      }
+    >,
+  ) {
+    return new Value<boolean, Store>(
+      async (options) => ({
+        description: null,
+        warning: null,
+        type: "toggle" as const,
+        disabled: false,
+        immutable: false,
+        ...(await a(options)),
+      }),
+      boolean,
+    )
+  }
+  static text<Required extends RequiredDefault<DefaultString>>(a: {
+    name: string
+    description?: string | null
+    warning?: string | null
+    required: Required
+ 
+    /** Default = false */
+    masked?: boolean
+    placeholder?: string | null
+    minLength?: number | null
+    maxLength?: number | null
+    patterns?: Pattern[]
+    /** Default = 'text' */
+    inputmode?: ValueSpecText["inputmode"]
+    /**  Immutable means it can only be configured at the first config then never again
+     * Default is false
+     */
+    immutable?: boolean
+    generate?: null | RandomString
+  }) {
+    return new Value<AsRequired<string, Required>, never>(
+      async () => ({
+        type: "text" as const,
+        description: null,
+        warning: null,
+        masked: false,
+        placeholder: null,
+        minLength: null,
+        maxLength: null,
+        patterns: [],
+        inputmode: "text",
+        disabled: false,
+        immutable: a.immutable ?? false,
+        generate: a.generate ?? null,
+        ...a,
+        ...requiredLikeToAbove(a.required),
+      }),
+      asRequiredParser(string, a),
+    )
+  }
+  static dynamicText<Store = never>(
+    getA: LazyBuild<
+      Store,
+      {
+        name: string
+        description?: string | null
+        warning?: string | null
+        required: RequiredDefault<DefaultString>
+ 
+        /** Default = false */
+        masked?: boolean
+        placeholder?: string | null
+        minLength?: number | null
+        maxLength?: number | null
+        patterns?: Pattern[]
+        /** Default = 'text' */
+        inputmode?: ValueSpecText["inputmode"]
+        disabled?: string | false
+        /**  Immutable means it can only be configured at the first config then never again
+         * Default is false
+         */
+        generate?: null | RandomString
+      }
+    >,
+  ) {
+    return new Value<string | null | undefined, Store>(async (options) => {
+      const a = await getA(options)
+      return {
+        type: "text" as const,
+        description: null,
+        warning: null,
+        masked: false,
+        placeholder: null,
+        minLength: null,
+        maxLength: null,
+        patterns: [],
+        inputmode: "text",
+        disabled: false,
+        immutable: false,
+        generate: a.generate ?? null,
+        ...a,
+        ...requiredLikeToAbove(a.required),
+      }
+    }, string.optional())
+  }
+  static textarea(a: {
+    name: string
+    description?: string | null
+    warning?: string | null
+    required: boolean
+    minLength?: number | null
+    maxLength?: number | null
+    placeholder?: string | null
+    /**  Immutable means it can only be configed at the first config then never again 
+    Default is false */
+    immutable?: boolean
+  }) {
+    return new Value<string, never>(async () => {
+      const built: ValueSpecTextarea = {
+        description: null,
+        warning: null,
+        minLength: null,
+        maxLength: null,
+        placeholder: null,
+        type: "textarea" as const,
+        disabled: false,
+        immutable: a.immutable ?? false,
+        ...a,
+      }
+      return built
+    }, string)
+  }
+  static dynamicTextarea<Store = never>(
+    getA: LazyBuild<
+      Store,
+      {
+        name: string
+        description?: string | null
+        warning?: string | null
+        required: boolean
+        minLength?: number | null
+        maxLength?: number | null
+        placeholder?: string | null
+        disabled?: false | string
+      }
+    >,
+  ) {
+    return new Value<string, Store>(async (options) => {
+      const a = await getA(options)
+      return {
+        description: null,
+        warning: null,
+        minLength: null,
+        maxLength: null,
+        placeholder: null,
+        type: "textarea" as const,
+        disabled: false,
+        immutable: false,
+        ...a,
+      }
+    }, string)
+  }
+  static number<Required extends RequiredDefault<number>>(a: {
+    name: string
+    description?: string | null
+    warning?: string | null
+    required: Required
+    min?: number | null
+    max?: number | null
+    /** Default = '1' */
+    step?: number | null
+    integer: boolean
+    units?: string | null
+    placeholder?: string | null
+    /**  Immutable means it can only be configed at the first config then never again 
+    Default is false */
+    immutable?: boolean
+  }) {
+    return new Value<AsRequired<number, Required>, never>(
+      () => ({
+        type: "number" as const,
+        description: null,
+        warning: null,
+        min: null,
+        max: null,
+        step: null,
+        units: null,
+        placeholder: null,
+        disabled: false,
+        immutable: a.immutable ?? false,
+        ...a,
+        ...requiredLikeToAbove(a.required),
+      }),
+      asRequiredParser(number, a),
+    )
+  }
+  static dynamicNumber<Store = never>(
+    getA: LazyBuild<
+      Store,
+      {
+        name: string
+        description?: string | null
+        warning?: string | null
+        required: RequiredDefault<number>
+        min?: number | null
+        max?: number | null
+        /** Default = '1' */
+        step?: number | null
+        integer: boolean
+        units?: string | null
+        placeholder?: string | null
+        disabled?: false | string
+      }
+    >,
+  ) {
+    return new Value<number | null | undefined, Store>(async (options) => {
+      const a = await getA(options)
+      return {
+        type: "number" as const,
+        description: null,
+        warning: null,
+        min: null,
+        max: null,
+        step: null,
+        units: null,
+        placeholder: null,
+        disabled: false,
+        immutable: false,
+        ...a,
+        ...requiredLikeToAbove(a.required),
+      }
+    }, number.optional())
+  }
+  static color<Required extends RequiredDefault<string>>(a: {
+    name: string
+    description?: string | null
+    warning?: string | null
+    required: Required
+    /**  Immutable means it can only be configed at the first config then never again 
+    Default is false */
+    immutable?: boolean
+  }) {
+    return new Value<AsRequired<string, Required>, never>(
+      () => ({
+        type: "color" as const,
+        description: null,
+        warning: null,
+        disabled: false,
+        immutable: a.immutable ?? false,
+        ...a,
+        ...requiredLikeToAbove(a.required),
+      }),
+ 
+      asRequiredParser(string, a),
+    )
+  }
+ 
+  static dynamicColor<Store = never>(
+    getA: LazyBuild<
+      Store,
+      {
+        name: string
+        description?: string | null
+        warning?: string | null
+        required: RequiredDefault<string>
+        disabled?: false | string
+      }
+    >,
+  ) {
+    return new Value<string | null | undefined, Store>(async (options) => {
+      const a = await getA(options)
+      return {
+        type: "color" as const,
+        description: null,
+        warning: null,
+        disabled: false,
+        immutable: false,
+        ...a,
+        ...requiredLikeToAbove(a.required),
+      }
+    }, string.optional())
+  }
+  static datetime<Required extends RequiredDefault<string>>(a: {
+    name: string
+    description?: string | null
+    warning?: string | null
+    required: Required
+    /** Default = 'datetime-local' */
+    inputmode?: ValueSpecDatetime["inputmode"]
+    min?: string | null
+    max?: string | null
+    /**  Immutable means it can only be configed at the first config then never again 
+    Default is false */
+    immutable?: boolean
+  }) {
+    return new Value<AsRequired<string, Required>, never>(
+      () => ({
+        type: "datetime" as const,
+        description: null,
+        warning: null,
+        inputmode: "datetime-local",
+        min: null,
+        max: null,
+        step: null,
+        disabled: false,
+        immutable: a.immutable ?? false,
+        ...a,
+        ...requiredLikeToAbove(a.required),
+      }),
+      asRequiredParser(string, a),
+    )
+  }
+  static dynamicDatetime<Store = never>(
+    getA: LazyBuild<
+      Store,
+      {
+        name: string
+        description?: string | null
+        warning?: string | null
+        required: RequiredDefault<string>
+        /** Default = 'datetime-local' */
+        inputmode?: ValueSpecDatetime["inputmode"]
+        min?: string | null
+        max?: string | null
+        disabled?: false | string
+      }
+    >,
+  ) {
+    return new Value<string | null | undefined, Store>(async (options) => {
+      const a = await getA(options)
+      return {
+        type: "datetime" as const,
+        description: null,
+        warning: null,
+        inputmode: "datetime-local",
+        min: null,
+        max: null,
+        disabled: false,
+        immutable: false,
+        ...a,
+        ...requiredLikeToAbove(a.required),
+      }
+    }, string.optional())
+  }
+  static select<
+    Required extends RequiredDefault<string>,
+    B extends Record<string, string>,
+  >(a: {
+    name: string
+    description?: string | null
+    warning?: string | null
+    required: Required
+    values: B
+    /**
+     * Disabled:  false means that there is nothing disabled, good to modify
+     *           string means that this is the message displayed and the whole thing is disabled
+     *           string[] means that the options are disabled
+     */
+    disabled?: false | string | (string & keyof B)[]
+    /**  Immutable means it can only be configed at the first config then never again 
+    Default is false */
+    immutable?: boolean
+  }) {
+    return new Value<AsRequired<keyof B, Required>, never>(
+      () => ({
+        description: null,
+        warning: null,
+        type: "select" as const,
+        disabled: false,
+        immutable: a.immutable ?? false,
+        ...a,
+        ...requiredLikeToAbove(a.required),
+      }),
+      asRequiredParser(
+        anyOf(
+          ...Object.keys(a.values).map((x: keyof B & string) => literal(x)),
+        ),
+        a,
+      ) as any,
+    )
+  }
+  static dynamicSelect<Store = never>(
+    getA: LazyBuild<
+      Store,
+      {
+        name: string
+        description?: string | null
+        warning?: string | null
+        required: RequiredDefault<string>
+        values: Record<string, string>
+        /**
+         * Disabled:  false means that there is nothing disabled, good to modify
+         *           string means that this is the message displayed and the whole thing is disabled
+         *           string[] means that the options are disabled
+         */
+        disabled?: false | string | string[]
+      }
+    >,
+  ) {
+    return new Value<string | null | undefined, Store>(async (options) => {
+      const a = await getA(options)
+      return {
+        description: null,
+        warning: null,
+        type: "select" as const,
+        disabled: false,
+        immutable: false,
+        ...a,
+        ...requiredLikeToAbove(a.required),
+      }
+    }, string.optional())
+  }
+  static multiselect<Values extends Record<string, string>>(a: {
+    name: string
+    description?: string | null
+    warning?: string | null
+    default: string[]
+    values: Values
+    minLength?: number | null
+    maxLength?: number | null
+    /**  Immutable means it can only be configed at the first config then never again 
+    Default is false */
+    immutable?: boolean
+    /**
+     * Disabled:  false means that there is nothing disabled, good to modify
+     *           string means that this is the message displayed and the whole thing is disabled
+     *           string[] means that the options are disabled
+     */
+    disabled?: false | string | (string & keyof Values)[]
+  }) {
+    return new Value<(keyof Values)[], never>(
+      () => ({
+        type: "multiselect" as const,
+        minLength: null,
+        maxLength: null,
+        warning: null,
+        description: null,
+        disabled: false,
+        immutable: a.immutable ?? false,
+        ...a,
+      }),
+      arrayOf(
+        literals(...(Object.keys(a.values) as any as [keyof Values & string])),
+      ),
+    )
+  }
+  static dynamicMultiselect<Store = never>(
+    getA: LazyBuild<
+      Store,
+      {
+        name: string
+        description?: string | null
+        warning?: string | null
+        default: string[]
+        values: Record<string, string>
+        minLength?: number | null
+        maxLength?: number | null
+        /**
+         * Disabled:  false means that there is nothing disabled, good to modify
+         *           string means that this is the message displayed and the whole thing is disabled
+         *           string[] means that the options are disabled
+         */
+        disabled?: false | string | string[]
+      }
+    >,
+  ) {
+    return new Value<string[], Store>(async (options) => {
+      const a = await getA(options)
+      return {
+        type: "multiselect" as const,
+        minLength: null,
+        maxLength: null,
+        warning: null,
+        description: null,
+        disabled: false,
+        immutable: false,
+        ...a,
+      }
+    }, arrayOf(string))
+  }
+  static object<Type extends Record<string, any>, Store>(
+    a: {
+      name: string
+      description?: string | null
+      warning?: string | null
+    },
+    spec: Config<Type, Store>,
+  ) {
+    return new Value<Type, Store>(async (options) => {
+      const built = await spec.build(options as any)
+      return {
+        type: "object" as const,
+        description: null,
+        warning: null,
+        ...a,
+        spec: built,
+      }
+    }, spec.validator)
+  }
+  static file<Required extends RequiredDefault<string>, Store>(a: {
+    name: string
+    description?: string | null
+    warning?: string | null
+    extensions: string[]
+    required: Required
+  }) {
+    const buildValue = {
+      type: "file" as const,
+      description: null,
+      warning: null,
+      ...a,
+    }
+    return new Value<AsRequired<FilePath, Required>, Store>(
+      () => ({
+        ...buildValue,
+ 
+        ...requiredLikeToAbove(a.required),
+      }),
+      asRequiredParser(object({ filePath: string }), a),
+    )
+  }
+  static dynamicFile<Required extends boolean, Store>(
+    a: LazyBuild<
+      Store,
+      {
+        name: string
+        description?: string | null
+        warning?: string | null
+        extensions: string[]
+        required: Required
+      }
+    >,
+  ) {
+    return new Value<string | null | undefined, Store>(
+      async (options) => ({
+        type: "file" as const,
+        description: null,
+        warning: null,
+        ...(await a(options)),
+      }),
+      string.optional(),
+    )
+  }
+  static union<Required extends RequiredDefault<string>, Type, Store>(
+    a: {
+      name: string
+      description?: string | null
+      warning?: string | null
+      required: Required
+      /**  Immutable means it can only be configed at the first config then never again 
+      Default is false */
+      immutable?: boolean
+      /**
+       * Disabled:  false means that there is nothing disabled, good to modify
+       *           string means that this is the message displayed and the whole thing is disabled
+       *           string[] means that the options are disabled
+       */
+      disabled?: false | string | string[]
+    },
+    aVariants: Variants<Type, Store>,
+  ) {
+    return new Value<AsRequired<Type, Required>, Store>(
+      async (options) => ({
+        type: "union" as const,
+        description: null,
+        warning: null,
+        disabled: false,
+        ...a,
+        variants: await aVariants.build(options as any),
+        ...requiredLikeToAbove(a.required),
+        immutable: a.immutable ?? false,
+      }),
+      asRequiredParser(aVariants.validator, a),
+    )
+  }
+  static filteredUnion<
+    Required extends RequiredDefault<string>,
+    Type extends Record<string, any>,
+    Store = never,
+  >(
+    getDisabledFn: LazyBuild<Store, string[] | false | string>,
+    a: {
+      name: string
+      description?: string | null
+      warning?: string | null
+      required: Required
+    },
+    aVariants: Variants<Type, Store> | Variants<Type, never>,
+  ) {
+    return new Value<AsRequired<Type, Required>, Store>(
+      async (options) => ({
+        type: "union" as const,
+        description: null,
+        warning: null,
+        ...a,
+        variants: await aVariants.build(options as any),
+        ...requiredLikeToAbove(a.required),
+        disabled: (await getDisabledFn(options)) || false,
+        immutable: false,
+      }),
+      asRequiredParser(aVariants.validator, a),
+    )
+  }
+  static dynamicUnion<
+    Required extends RequiredDefault<string>,
+    Type extends Record<string, any>,
+    Store = never,
+  >(
+    getA: LazyBuild<
+      Store,
+      {
+        disabled: string[] | false | string
+        name: string
+        description?: string | null
+        warning?: string | null
+        required: Required
+      }
+    >,
+    aVariants: Variants<Type, Store> | Variants<Type, never>,
+  ) {
+    return new Value<Type | null | undefined, Store>(async (options) => {
+      const newValues = await getA(options)
+      return {
+        type: "union" as const,
+        description: null,
+        warning: null,
+        ...newValues,
+        variants: await aVariants.build(options as any),
+        ...requiredLikeToAbove(newValues.required),
+        immutable: false,
+      }
+    }, aVariants.validator.optional())
+  }
+ 
+  static list<Type, Store>(a: List<Type, Store>) {
+    return new Value<Type, Store>((options) => a.build(options), a.validator)
+  }
+ 
+  /**
+   * Use this during the times that the input needs a more specific type.
+   * Used in types that the value/ variant/ list/ config is constructed somewhere else.
+  ```ts
+  const a = Config.text({
+    name: "a",
+    required: false,
+  })
+ 
+  return Config.of<Store>()({
+    myValue: a.withStore(),
+  })
+  ```
+   */
+  withStore<NewStore extends Store extends never ? any : Store>() {
+    return this as any as Value<Type, NewStore>
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/config/builder/variants.ts.html b/sdk/lib/coverage/lcov-report/lib/config/builder/variants.ts.html new file mode 100644 index 000000000..be1fdfeef --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/config/builder/variants.ts.html @@ -0,0 +1,445 @@ + + + + + + Code coverage report for lib/config/builder/variants.ts + + + + + + + + + +
+
+

All files / lib/config/builder variants.ts

+
+ +
+ 92.3% + Statements + 12/13 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 80% + Functions + 4/5 +
+ + +
+ 92.3% + Lines + 12/13 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +5x +  +  +12x +12x +  +  +  +  +  +  +  +  +  +  +12x +  +28x +  +  +  +  +  +  +12x +  +  +  +  +  +  +  +  +  +  +  +2x +  +  +2x +4x +4x +  +  +  +  +2x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { InputSpec, ValueSpecUnion } from "../configTypes"
+import { LazyBuild, Config } from "./config"
+import { Parser, anyOf, literals, object } from "ts-matches"
+ 
+/**
+ * Used in the the Value.select { @link './value.ts' }
+ * to indicate the type of select variants that are available. The key for the record passed in will be the
+ * key to the tag.id in the Value.select
+```ts
+ 
+export const disabled = Config.of({});
+export const size = Value.number({
+  name: "Max Chain Size",
+  default: 550,
+  description: "Limit of blockchain size on disk.",
+  warning: "Increasing this value will require re-syncing your node.",
+  required: true,
+  range: "[550,1000000)",
+  integral: true,
+  units: "MiB",
+  placeholder: null,
+});
+export const automatic = Config.of({ size: size });
+export const size1 = Value.number({
+  name: "Failsafe Chain Size",
+  default: 65536,
+  description: "Prune blockchain if size expands beyond this.",
+  warning: null,
+  required: true,
+  range: "[550,1000000)",
+  integral: true,
+  units: "MiB",
+  placeholder: null,
+});
+export const manual = Config.of({ size: size1 });
+export const pruningSettingsVariants = Variants.of({
+  disabled: { name: "Disabled", spec: disabled },
+  automatic: { name: "Automatic", spec: automatic },
+  manual: { name: "Manual", spec: manual },
+});
+export const pruning = Value.union(
+  {
+    name: "Pruning Settings",
+    description:
+      '- Disabled: Disable pruning\n- Automatic: Limit blockchain size on disk to a certain number of megabytes\n- Manual: Prune blockchain with the "pruneblockchain" RPC\n',
+    warning: null,
+    required: true,
+    default: "disabled",
+  },
+  pruningSettingsVariants
+);
+```
+ */
+export class Variants<Type, Store> {
+  static text: any
+  private constructor(
+    public build: LazyBuild<Store, ValueSpecUnion["variants"]>,
+    public validator: Parser<unknown, Type>,
+  ) {}
+  static of<
+    VariantValues extends {
+      [K in string]: {
+        name: string
+        spec: Config<any, Store> | Config<any, never>
+      }
+    },
+    Store = never,
+  >(a: VariantValues) {
+    const validator = anyOf(
+      ...Object.entries(a).map(([name, { spec }]) =>
+        object({
+          selection: literals(name),
+          value: spec.validator,
+        }),
+      ),
+    ) as Parser<unknown, any>
+ 
+    return new Variants<
+      {
+        [K in keyof VariantValues]: {
+          selection: K
+          // prettier-ignore
+          value: 
+            VariantValues[K]["spec"] extends (Config<infer B, Store> | Config<infer B, never>) ? B :
+            never
+        }
+      }[keyof VariantValues],
+      Store
+    >(async (options) => {
+      const variants = {} as {
+        [K in keyof VariantValues]: { name: string; spec: InputSpec }
+      }
+      for (const key in a) {
+        const value = a[key]
+        variants[key] = {
+          name: value.name,
+          spec: await value.spec.build(options as any),
+        }
+      }
+      return variants
+    }, validator)
+  }
+  /**
+   * Use this during the times that the input needs a more specific type.
+   * Used in types that the value/ variant/ list/ config is constructed somewhere else.
+  ```ts
+  const a = Config.text({
+    name: "a",
+    required: false,
+  })
+ 
+  return Config.of<Store>()({
+    myValue: a.withStore(),
+  })
+  ```
+   */
+  withStore<NewStore extends Store extends never ? any : Store>() {
+    return this as any as Variants<Type, NewStore>
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/config/configConstants.ts.html b/sdk/lib/coverage/lcov-report/lib/config/configConstants.ts.html new file mode 100644 index 000000000..9003a1cf5 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/config/configConstants.ts.html @@ -0,0 +1,328 @@ + + + + + + Code coverage report for lib/config/configConstants.ts + + + + + + + + + +
+
+

All files / lib/config configConstants.ts

+
+ +
+ 77.77% + Statements + 7/9 +
+ + +
+ 0% + Branches + 0/2 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 77.77% + Lines + 7/9 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82  +5x +5x +5x +5x +5x +  +  +  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { SmtpValue } from "../types"
+import { GetSystemSmtp } from "../util/GetSystemSmtp"
+import { email } from "../util/patterns"
+import { Config, ConfigSpecOf } from "./builder/config"
+import { Value } from "./builder/value"
+import { Variants } from "./builder/variants"
+ 
+/**
+ * Base SMTP settings, to be used by StartOS for system wide SMTP
+ */
+export const customSmtp = Config.of<ConfigSpecOf<SmtpValue>, never>({
+  server: Value.text({
+    name: "SMTP Server",
+    required: {
+      default: null,
+    },
+  }),
+  port: Value.number({
+    name: "Port",
+    required: { default: 587 },
+    min: 1,
+    max: 65535,
+    integer: true,
+  }),
+  from: Value.text({
+    name: "From Address",
+    required: {
+      default: null,
+    },
+    placeholder: "<name>test@example.com",
+    inputmode: "email",
+    patterns: [email],
+  }),
+  login: Value.text({
+    name: "Login",
+    required: {
+      default: null,
+    },
+  }),
+  password: Value.text({
+    name: "Password",
+    required: false,
+    masked: true,
+  }),
+})
+ 
+/**
+ * For service config. Gives users 3 options for SMTP: (1) disabled, (2) use system SMTP settings, (3) use custom SMTP settings
+ */
+export const smtpConfig = Value.filteredUnion(
+  async ({ effects }) => {
+    const smtp = await new GetSystemSmtp(effects).once()
+    return smtp ? [] : ["system"]
+  },
+  {
+    name: "SMTP",
+    description: "Optionally provide an SMTP server for sending emails",
+    required: { default: "disabled" },
+  },
+  Variants.of({
+    disabled: { name: "Disabled", spec: Config.of({}) },
+    system: {
+      name: "System Credentials",
+      spec: Config.of({
+        customFrom: Value.text({
+          name: "Custom From Address",
+          description:
+            "A custom from address for this service. If not provided, the system from address will be used.",
+          required: false,
+          placeholder: "<name>test@example.com",
+          inputmode: "email",
+          patterns: [email],
+        }),
+      }),
+    },
+    custom: {
+      name: "Custom Credentials",
+      spec: customSmtp,
+    },
+  }),
+)
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/config/configDependencies.ts.html b/sdk/lib/coverage/lcov-report/lib/config/configDependencies.ts.html new file mode 100644 index 000000000..035276a61 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/config/configDependencies.ts.html @@ -0,0 +1,163 @@ + + + + + + Code coverage report for lib/config/configDependencies.ts + + + + + + + + + +
+
+

All files / lib/config configDependencies.ts

+
+ +
+ 40% + Statements + 2/5 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 0% + Functions + 0/3 +
+ + +
+ 25% + Lines + 1/4 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27  +  +  +  +  +  +  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { SDKManifest } from "../manifest/ManifestTypes"
+import { Dependency } from "../types"
+ 
+export type ConfigDependencies<T extends SDKManifest> = {
+  exists(id: keyof T["dependencies"]): Dependency
+  running(id: keyof T["dependencies"], healthChecks: string[]): Dependency
+}
+ 
+export const configDependenciesSet = <
+  T extends SDKManifest,
+>(): ConfigDependencies<T> => ({
+  exists(id: keyof T["dependencies"]) {
+    return {
+      id,
+      kind: "exists",
+    } as Dependency
+  },
+ 
+  running(id: keyof T["dependencies"], healthChecks: string[]) {
+    return {
+      id,
+      kind: "running",
+      healthChecks,
+    } as Dependency
+  },
+})
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/config/configTypes.ts.html b/sdk/lib/coverage/lcov-report/lib/config/configTypes.ts.html new file mode 100644 index 000000000..dc198cc5f --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/config/configTypes.ts.html @@ -0,0 +1,901 @@ + + + + + + Code coverage report for lib/config/configTypes.ts + + + + + + + + + +
+
+

All files / lib/config configTypes.ts

+
+ +
+ 100% + Statements + 2/2 +
+ + +
+ 100% + Branches + 2/2 +
+ + +
+ 100% + Functions + 1/1 +
+ + +
+ 100% + Lines + 2/2 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +3x +  + 
export type InputSpec = Record<string, ValueSpec>
+export type ValueType =
+  | "text"
+  | "textarea"
+  | "number"
+  | "color"
+  | "datetime"
+  | "toggle"
+  | "select"
+  | "multiselect"
+  | "list"
+  | "object"
+  | "file"
+  | "union"
+export type ValueSpec = ValueSpecOf<ValueType>
+/** core spec types. These types provide the metadata for performing validations */
+// prettier-ignore
+export type ValueSpecOf<T extends ValueType> = 
+  T extends "text" ? ValueSpecText : 
+  T extends "textarea" ? ValueSpecTextarea : 
+  T extends "number" ? ValueSpecNumber : 
+  T extends "color" ? ValueSpecColor : 
+  T extends "datetime" ? ValueSpecDatetime : 
+  T extends "toggle" ? ValueSpecToggle : 
+  T extends "select" ? ValueSpecSelect : 
+  T extends "multiselect" ? ValueSpecMultiselect : 
+  T extends "list" ? ValueSpecList : 
+  T extends "object" ? ValueSpecObject : 
+  T extends "file" ? ValueSpecFile : 
+  T extends "union" ? ValueSpecUnion : 
+  never
+ 
+export type ValueSpecText = {
+  name: string
+  description: string | null
+  warning: string | null
+ 
+  type: "text"
+  patterns: Pattern[]
+  minLength: number | null
+  maxLength: number | null
+  masked: boolean
+ 
+  inputmode: "text" | "email" | "tel" | "url"
+  placeholder: string | null
+ 
+  required: boolean
+  default: DefaultString | null
+  disabled: false | string
+  generate: null | RandomString
+  /** Immutable means it can only be configured at the first config then never again */
+  immutable: boolean
+}
+export type ValueSpecTextarea = {
+  name: string
+  description: string | null
+  warning: string | null
+ 
+  type: "textarea"
+  placeholder: string | null
+  minLength: number | null
+  maxLength: number | null
+  required: boolean
+  disabled: false | string
+  /** Immutable means it can only be configured at the first config then never again */
+  immutable: boolean
+}
+ 
+export type FilePath = {
+  filePath: string
+}
+export type ValueSpecNumber = {
+  type: "number"
+  min: number | null
+  max: number | null
+  integer: boolean
+  step: number | null
+  units: string | null
+  placeholder: string | null
+  name: string
+  description: string | null
+  warning: string | null
+  required: boolean
+  default: number | null
+  disabled: false | string
+  /** Immutable means it can only be configured at the first config then never again */
+  immutable: boolean
+}
+export type ValueSpecColor = {
+  name: string
+  description: string | null
+  warning: string | null
+ 
+  type: "color"
+  required: boolean
+  default: string | null
+  disabled: false | string
+  /** Immutable means it can only be configured at the first config then never again */
+  immutable: boolean
+}
+export type ValueSpecDatetime = {
+  name: string
+  description: string | null
+  warning: string | null
+  type: "datetime"
+  required: boolean
+  inputmode: "date" | "time" | "datetime-local"
+  min: string | null
+  max: string | null
+  default: string | null
+  disabled: false | string
+  /** Immutable means it can only be configured at the first config then never again */
+  immutable: boolean
+}
+export type ValueSpecSelect = {
+  values: Record<string, string>
+  name: string
+  description: string | null
+  warning: string | null
+  type: "select"
+  required: boolean
+  default: string | null
+  /**
+   * Disabled:  false means that there is nothing disabled, good to modify
+   *           string means that this is the message displayed and the whole thing is disabled
+   *           string[] means that the options are disabled
+   */
+  disabled: false | string | string[]
+  /** Immutable means it can only be configured at the first config then never again */
+  immutable: boolean
+}
+export type ValueSpecMultiselect = {
+  values: Record<string, string>
+ 
+  name: string
+  description: string | null
+  warning: string | null
+ 
+  type: "multiselect"
+  minLength: number | null
+  maxLength: number | null
+  /**
+   * Disabled:  false means that there is nothing disabled, good to modify
+   *           string means that this is the message displayed and the whole thing is disabled
+   *           string[] means that the options are disabled
+   */
+  disabled: false | string | string[]
+  default: string[]
+  /** Immutable means it can only be configured at the first config then never again */
+  immutable: boolean
+}
+export type ValueSpecToggle = {
+  name: string
+  description: string | null
+  warning: string | null
+ 
+  type: "toggle"
+  default: boolean | null
+  disabled: false | string
+  /** Immutable means it can only be configured at the first config then never again */
+  immutable: boolean
+}
+export type ValueSpecUnion = {
+  name: string
+  description: string | null
+  warning: string | null
+ 
+  type: "union"
+  variants: Record<
+    string,
+    {
+      name: string
+      spec: InputSpec
+    }
+  >
+  /**
+   * Disabled:  false means that there is nothing disabled, good to modify
+   *           string means that this is the message displayed and the whole thing is disabled
+   *           string[] means that the options are disabled
+   */
+  disabled: false | string | string[]
+  required: boolean
+  default: string | null
+  /** Immutable means it can only be configured at the first config then never again */
+  immutable: boolean
+}
+export type ValueSpecFile = {
+  name: string
+  description: string | null
+  warning: string | null
+  type: "file"
+  extensions: string[]
+  required: boolean
+}
+export type ValueSpecObject = {
+  name: string
+  description: string | null
+  warning: string | null
+  type: "object"
+  spec: InputSpec
+}
+export type ListValueSpecType = "text" | "object"
+/** represents a spec for the values of a list */
+// prettier-ignore
+export type ListValueSpecOf<T extends ListValueSpecType> = 
+  T extends "text" ? ListValueSpecText :
+  T extends "object" ? ListValueSpecObject :
+  never
+/** represents a spec for a list */
+export type ValueSpecList = ValueSpecListOf<ListValueSpecType>
+export type ValueSpecListOf<T extends ListValueSpecType> = {
+  name: string
+  description: string | null
+  warning: string | null
+  type: "list"
+  spec: ListValueSpecOf<T>
+  minLength: number | null
+  maxLength: number | null
+  disabled: false | string
+  default:
+    | string[]
+    | DefaultString[]
+    | Record<string, unknown>[]
+    | readonly string[]
+    | readonly DefaultString[]
+    | readonly Record<string, unknown>[]
+}
+export type Pattern = {
+  regex: string
+  description: string
+}
+export type ListValueSpecText = {
+  type: "text"
+  patterns: Pattern[]
+  minLength: number | null
+  maxLength: number | null
+  masked: boolean
+ 
+  generate: null | RandomString
+  inputmode: "text" | "email" | "tel" | "url"
+  placeholder: string | null
+}
+export type ListValueSpecObject = {
+  type: "object"
+  /** this is a mapped type of the config object at this level, replacing the object's values with specs on those values */
+  spec: InputSpec
+  /** indicates whether duplicates can be permitted in the list */
+  uniqueBy: UniqueBy
+  /** this should be a handlebars template which can make use of the entire config which corresponds to 'spec' */
+  displayAs: string | null
+}
+export type UniqueBy =
+  | null
+  | string
+  | {
+      any: readonly UniqueBy[] | UniqueBy[]
+    }
+  | {
+      all: readonly UniqueBy[] | UniqueBy[]
+    }
+export type DefaultString = string | RandomString
+export type RandomString = {
+  charset: string
+  len: number
+}
+// sometimes the type checker needs just a little bit of help
+export function isValueSpecListOf<S extends ListValueSpecType>(
+  t: ValueSpec,
+  s: S,
+): t is ValueSpecListOf<S> & { spec: ListValueSpecOf<S> } {
+  return "spec" in t && t.spec.type === s
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/config/index.html b/sdk/lib/coverage/lcov-report/lib/config/index.html new file mode 100644 index 000000000..1daae9f88 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/config/index.html @@ -0,0 +1,146 @@ + + + + + + Code coverage report for lib/config + + + + + + + + + +
+
+

All files lib/config

+
+ +
+ 46.15% + Statements + 12/26 +
+ + +
+ 25% + Branches + 2/8 +
+ + +
+ 20% + Functions + 1/5 +
+ + +
+ 46.15% + Lines + 12/26 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
configConstants.ts +
+
77.77%7/90%0/20%0/177.77%7/9
configTypes.ts +
+
100%2/2100%2/2100%1/1100%2/2
setupConfig.ts +
+
20%3/150%0/40%0/320%3/15
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/config/setupConfig.ts.html b/sdk/lib/coverage/lcov-report/lib/config/setupConfig.ts.html new file mode 100644 index 000000000..8bac76fc7 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/config/setupConfig.ts.html @@ -0,0 +1,346 @@ + + + + + + Code coverage report for lib/config/setupConfig.ts + + + + + + + + + +
+
+

All files / lib/config setupConfig.ts

+
+ +
+ 20% + Statements + 3/15 +
+ + +
+ 0% + Branches + 0/4 +
+ + +
+ 0% + Functions + 0/3 +
+ + +
+ 20% + Lines + 3/15 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88  +  +  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +5x + 
import * as T from "../types"
+ 
+import * as D from "./configDependencies"
+import { Config, ExtractConfigType } from "./builder/config"
+import nullIfEmpty from "../util/nullIfEmpty"
+import { InterfacesReceipt as InterfacesReceipt } from "../interfaces/setupInterfaces"
+ 
+declare const dependencyProof: unique symbol
+export type DependenciesReceipt = void & {
+  [dependencyProof]: never
+}
+ 
+export type Save<
+  A extends
+    | Record<string, any>
+    | Config<Record<string, any>, any>
+    | Config<Record<string, never>, never>,
+> = (options: {
+  effects: T.Effects
+  input: ExtractConfigType<A> & Record<string, any>
+}) => Promise<{
+  dependenciesReceipt: DependenciesReceipt
+  interfacesReceipt: InterfacesReceipt
+  restart: boolean
+}>
+export type Read<
+  Manifest extends T.Manifest,
+  Store,
+  A extends
+    | Record<string, any>
+    | Config<Record<string, any>, any>
+    | Config<Record<string, any>, never>,
+> = (options: {
+  effects: T.Effects
+}) => Promise<void | (ExtractConfigType<A> & Record<string, any>)>
+/**
+ * We want to setup a config export with a get and set, this
+ * is going to be the default helper to setup config, because it will help
+ * enforce that we have a spec, write, and reading.
+ * @param options
+ * @returns
+ */
+export function setupConfig<
+  Store,
+  ConfigType extends
+    | Record<string, any>
+    | Config<any, any>
+    | Config<any, never>,
+  Manifest extends T.Manifest,
+  Type extends Record<string, any> = ExtractConfigType<ConfigType>,
+>(
+  spec: Config<Type, Store> | Config<Type, never>,
+  write: Save<Type>,
+  read: Read<Manifest, Store, Type>,
+) {
+  const validator = spec.validator
+  return {
+    setConfig: (async ({ effects, input }) => {
+      Iif (!validator.test(input)) {
+        await console.error(
+          new Error(validator.errorMessage(input)?.toString()),
+        )
+        return { error: "Set config type error for config" }
+      }
+      await effects.clearBindings()
+      await effects.clearServiceInterfaces()
+      const { restart } = await write({
+        input: JSON.parse(JSON.stringify(input)) as any,
+        effects,
+      })
+      Iif (restart) {
+        await effects.restart()
+      }
+    }) as T.ExpectedExports.setConfig,
+    getConfig: (async ({ effects }) => {
+      const configValue = nullIfEmpty((await read({ effects })) || null)
+      return {
+        spec: await spec.build({
+          effects,
+        }),
+        config: configValue,
+      }
+    }) as T.ExpectedExports.getConfig,
+  }
+}
+ 
+export default setupConfig
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/dependencies/DependencyConfig.ts.html b/sdk/lib/coverage/lcov-report/lib/dependencies/DependencyConfig.ts.html new file mode 100644 index 000000000..cf3dc0252 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/dependencies/DependencyConfig.ts.html @@ -0,0 +1,202 @@ + + + + + + Code coverage report for lib/dependencies/DependencyConfig.ts + + + + + + + + + +
+
+

All files / lib/dependencies DependencyConfig.ts

+
+ +
+ 71.42% + Statements + 5/7 +
+ + +
+ 33.33% + Branches + 1/3 +
+ + +
+ 33.33% + Functions + 1/3 +
+ + +
+ 71.42% + Lines + 5/7 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40  +  +5x +  +  +  +  +  +  +5x +  +  +  +  +  +5x +  +  +  +  +  +  +1x +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  + 
import * as T from "../types"
+import { deepEqual } from "../util/deepEqual"
+import { deepMerge } from "../util/deepMerge"
+ 
+export type Update<QueryResults, RemoteConfig> = (options: {
+  remoteConfig: RemoteConfig
+  queryResults: QueryResults
+}) => Promise<RemoteConfig>
+ 
+export class DependencyConfig<
+  Manifest extends T.Manifest,
+  Store,
+  Input extends Record<string, any>,
+  RemoteConfig extends Record<string, any>,
+> {
+  static defaultUpdate = async (options: {
+    queryResults: unknown
+    remoteConfig: unknown
+  }): Promise<unknown> => {
+    return deepMerge({}, options.remoteConfig, options.queryResults || {})
+  }
+  constructor(
+    readonly dependencyConfig: (options: {
+      effects: T.Effects
+      localConfig: Input
+    }) => Promise<void | T.DeepPartial<RemoteConfig>>,
+    readonly update: Update<
+      void | T.DeepPartial<RemoteConfig>,
+      RemoteConfig
+    > = DependencyConfig.defaultUpdate as any,
+  ) {}
+ 
+  async query(options: { effects: T.Effects; localConfig: unknown }) {
+    return this.dependencyConfig({
+      localConfig: options.localConfig as Input,
+      effects: options.effects,
+    })
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/dependencies/dependencies.ts.html b/sdk/lib/coverage/lcov-report/lib/dependencies/dependencies.ts.html new file mode 100644 index 000000000..a0532d789 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/dependencies/dependencies.ts.html @@ -0,0 +1,703 @@ + + + + + + Code coverage report for lib/dependencies/dependencies.ts + + + + + + + + + +
+
+

All files / lib/dependencies dependencies.ts

+
+ +
+ 2.38% + Statements + 2/84 +
+ + +
+ 0% + Branches + 0/53 +
+ + +
+ 0% + Functions + 0/28 +
+ + +
+ 2.46% + Lines + 2/81 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +2075x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { ExtendedVersion, VersionRange } from "../exver"
+import {
+  Effects,
+  PackageId,
+  DependencyRequirement,
+  SetHealth,
+  CheckDependenciesResult,
+  HealthCheckId,
+} from "../types"
+ 
+export type CheckDependencies<DependencyId extends PackageId = PackageId> = {
+  installedSatisfied: (packageId: DependencyId) => boolean
+  installedVersionSatisfied: (packageId: DependencyId) => boolean
+  runningSatisfied: (packageId: DependencyId) => boolean
+  configSatisfied: (packageId: DependencyId) => boolean
+  healthCheckSatisfied: (
+    packageId: DependencyId,
+    healthCheckId: HealthCheckId,
+  ) => boolean
+  satisfied: () => boolean
+ 
+  throwIfInstalledNotSatisfied: (packageId: DependencyId) => void
+  throwIfInstalledVersionNotSatisfied: (packageId: DependencyId) => void
+  throwIfRunningNotSatisfied: (packageId: DependencyId) => void
+  throwIfConfigNotSatisfied: (packageId: DependencyId) => void
+  throwIfHealthNotSatisfied: (
+    packageId: DependencyId,
+    healthCheckId?: HealthCheckId,
+  ) => void
+  throwIfNotSatisfied: (packageId?: DependencyId) => void
+}
+export async function checkDependencies<
+  DependencyId extends PackageId = PackageId,
+>(
+  effects: Effects,
+  packageIds?: DependencyId[],
+): Promise<CheckDependencies<DependencyId>> {
+  let [dependencies, results] = await Promise.all([
+    effects.getDependencies(),
+    effects.checkDependencies({
+      packageIds,
+    }),
+  ])
+  Iif (packageIds) {
+    dependencies = dependencies.filter((d) =>
+      (packageIds as PackageId[]).includes(d.id),
+    )
+  }
+ 
+  const find = (packageId: DependencyId) => {
+    const dependencyRequirement = dependencies.find((d) => d.id === packageId)
+    const dependencyResult = results.find((d) => d.packageId === packageId)
+    Iif (!dependencyRequirement || !dependencyResult) {
+      throw new Error(`Unknown DependencyId ${packageId}`)
+    }
+    return { requirement: dependencyRequirement, result: dependencyResult }
+  }
+ 
+  const installedSatisfied = (packageId: DependencyId) =>
+    !!find(packageId).result.installedVersion
+  const installedVersionSatisfied = (packageId: DependencyId) => {
+    const dep = find(packageId)
+    return (
+      !!dep.result.installedVersion &&
+      ExtendedVersion.parse(dep.result.installedVersion).satisfies(
+        VersionRange.parse(dep.requirement.versionRange),
+      )
+    )
+  }
+  const runningSatisfied = (packageId: DependencyId) => {
+    const dep = find(packageId)
+    return dep.requirement.kind !== "running" || dep.result.isRunning
+  }
+  const configSatisfied = (packageId: DependencyId) =>
+    find(packageId).result.configSatisfied
+  const healthCheckSatisfied = (
+    packageId: DependencyId,
+    healthCheckId?: HealthCheckId,
+  ) => {
+    const dep = find(packageId)
+    Iif (
+      healthCheckId &&
+      (dep.requirement.kind !== "running" ||
+        !dep.requirement.healthChecks.includes(healthCheckId))
+    ) {
+      throw new Error(`Unknown HealthCheckId ${healthCheckId}`)
+    }
+    const errors = Object.entries(dep.result.healthChecks)
+      .filter(([id, _]) => (healthCheckId ? id === healthCheckId : true))
+      .filter(([_, res]) => res.result !== "success")
+    return errors.length === 0
+  }
+  const pkgSatisfied = (packageId: DependencyId) =>
+    installedSatisfied(packageId) &&
+    installedVersionSatisfied(packageId) &&
+    runningSatisfied(packageId) &&
+    configSatisfied(packageId) &&
+    healthCheckSatisfied(packageId)
+  const satisfied = (packageId?: DependencyId) =>
+    packageId
+      ? pkgSatisfied(packageId)
+      : dependencies.every((d) => pkgSatisfied(d.id as DependencyId))
+ 
+  const throwIfInstalledNotSatisfied = (packageId: DependencyId) => {
+    const dep = find(packageId)
+    Iif (!dep.result.installedVersion) {
+      throw new Error(`${dep.result.title || packageId} is not installed`)
+    }
+  }
+  const throwIfInstalledVersionNotSatisfied = (packageId: DependencyId) => {
+    const dep = find(packageId)
+    Iif (!dep.result.installedVersion) {
+      throw new Error(`${dep.result.title || packageId} is not installed`)
+    }
+    Iif (
+      ![dep.result.installedVersion, ...dep.result.satisfies].find((v) =>
+        ExtendedVersion.parse(v).satisfies(
+          VersionRange.parse(dep.requirement.versionRange),
+        ),
+      )
+    ) {
+      throw new Error(
+        `Installed version ${dep.result.installedVersion} of ${dep.result.title || packageId} does not match expected version range ${dep.requirement.versionRange}`,
+      )
+    }
+  }
+  const throwIfRunningNotSatisfied = (packageId: DependencyId) => {
+    const dep = find(packageId)
+    Iif (dep.requirement.kind === "running" && !dep.result.isRunning) {
+      throw new Error(`${dep.result.title || packageId} is not running`)
+    }
+  }
+  const throwIfConfigNotSatisfied = (packageId: DependencyId) => {
+    const dep = find(packageId)
+    Iif (!dep.result.configSatisfied) {
+      throw new Error(
+        `${dep.result.title || packageId}'s configuration does not satisfy requirements`,
+      )
+    }
+  }
+  const throwIfHealthNotSatisfied = (
+    packageId: DependencyId,
+    healthCheckId?: HealthCheckId,
+  ) => {
+    const dep = find(packageId)
+    Iif (
+      healthCheckId &&
+      (dep.requirement.kind !== "running" ||
+        !dep.requirement.healthChecks.includes(healthCheckId))
+    ) {
+      throw new Error(`Unknown HealthCheckId ${healthCheckId}`)
+    }
+    const errors = Object.entries(dep.result.healthChecks)
+      .filter(([id, _]) => (healthCheckId ? id === healthCheckId : true))
+      .filter(([_, res]) => res.result !== "success")
+    Iif (errors.length) {
+      throw new Error(
+        errors
+          .map(
+            ([_, e]) =>
+              `Health Check ${e.name} of ${dep.result.title || packageId} failed with status ${e.result}${e.message ? `: ${e.message}` : ""}`,
+          )
+          .join("; "),
+      )
+    }
+  }
+  const throwIfPkgNotSatisfied = (packageId: DependencyId) => {
+    throwIfInstalledNotSatisfied(packageId)
+    throwIfInstalledVersionNotSatisfied(packageId)
+    throwIfRunningNotSatisfied(packageId)
+    throwIfConfigNotSatisfied(packageId)
+    throwIfHealthNotSatisfied(packageId)
+  }
+  const throwIfNotSatisfied = (packageId?: DependencyId) =>
+    packageId
+      ? throwIfPkgNotSatisfied(packageId)
+      : (() => {
+          const err = dependencies.flatMap((d) => {
+            try {
+              throwIfPkgNotSatisfied(d.id as DependencyId)
+            } catch (e) {
+              Iif (e instanceof Error) return [e.message]
+              throw e
+            }
+            return []
+          })
+          Iif (err.length) {
+            throw new Error(err.join("; "))
+          }
+        })()
+ 
+  return {
+    installedSatisfied,
+    installedVersionSatisfied,
+    runningSatisfied,
+    configSatisfied,
+    healthCheckSatisfied,
+    satisfied,
+    throwIfInstalledNotSatisfied,
+    throwIfInstalledVersionNotSatisfied,
+    throwIfRunningNotSatisfied,
+    throwIfConfigNotSatisfied,
+    throwIfHealthNotSatisfied,
+    throwIfNotSatisfied,
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/dependencies/index.html b/sdk/lib/coverage/lcov-report/lib/dependencies/index.html new file mode 100644 index 000000000..9aef57931 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/dependencies/index.html @@ -0,0 +1,146 @@ + + + + + + Code coverage report for lib/dependencies + + + + + + + + + +
+
+

All files lib/dependencies

+
+ +
+ 9.67% + Statements + 9/93 +
+ + +
+ 1.78% + Branches + 1/56 +
+ + +
+ 6.25% + Functions + 2/32 +
+ + +
+ 10% + Lines + 9/90 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
DependencyConfig.ts +
+
71.42%5/733.33%1/333.33%1/371.42%5/7
dependencies.ts +
+
2.38%2/840%0/530%0/282.46%2/81
setupDependencyConfig.ts +
+
100%2/2100%0/0100%1/1100%2/2
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/dependencies/setupDependencyConfig.ts.html b/sdk/lib/coverage/lcov-report/lib/dependencies/setupDependencyConfig.ts.html new file mode 100644 index 000000000..a7bb86a55 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/dependencies/setupDependencyConfig.ts.html @@ -0,0 +1,151 @@ + + + + + + Code coverage report for lib/dependencies/setupDependencyConfig.ts + + + + + + + + + +
+
+

All files / lib/dependencies setupDependencyConfig.ts

+
+ +
+ 100% + Statements + 2/2 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 100% + Functions + 1/1 +
+ + +
+ 100% + Lines + 2/2 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23  +  +  +  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  + 
import { Config } from "../config/builder/config"
+ 
+import * as T from "../types"
+import { DependencyConfig } from "./DependencyConfig"
+ 
+export function setupDependencyConfig<
+  Store,
+  Input extends Record<string, any>,
+  Manifest extends T.Manifest,
+>(
+  _config: Config<Input, Store> | Config<Input, never>,
+  autoConfigs: {
+    [key in keyof Manifest["dependencies"] & string]: DependencyConfig<
+      Manifest,
+      Store,
+      Input,
+      any
+    > | null
+  },
+): T.ExpectedExports.dependencyConfig {
+  return autoConfigs
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/dependencyConfig/DependencyConfig.ts.html b/sdk/lib/coverage/lcov-report/lib/dependencyConfig/DependencyConfig.ts.html new file mode 100644 index 000000000..db1b498e4 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/dependencyConfig/DependencyConfig.ts.html @@ -0,0 +1,217 @@ + + + + + + Code coverage report for lib/dependencyConfig/DependencyConfig.ts + + + + + + + + + +
+
+

All files / lib/dependencyConfig DependencyConfig.ts

+
+ +
+ 71.42% + Statements + 5/7 +
+ + +
+ 33.33% + Branches + 1/3 +
+ + +
+ 33.33% + Functions + 1/3 +
+ + +
+ 71.42% + Lines + 5/7 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45  +  +  +  +  +  +5x +  +  +  +  +  +  +  +5x +  +  +  +  +  +5x +  +  +  +  +  +  +1x +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  + 
import {
+  DependencyConfig as DependencyConfigType,
+  DeepPartial,
+  Effects,
+} from "../types"
+import { deepEqual } from "../util/deepEqual"
+import { deepMerge } from "../util/deepMerge"
+import { SDKManifest } from "../manifest/ManifestTypes"
+ 
+export type Update<QueryResults, RemoteConfig> = (options: {
+  remoteConfig: RemoteConfig
+  queryResults: QueryResults
+}) => Promise<RemoteConfig>
+ 
+export class DependencyConfig<
+  Manifest extends SDKManifest,
+  Store,
+  Input extends Record<string, any>,
+  RemoteConfig extends Record<string, any>,
+> {
+  static defaultUpdate = async (options: {
+    queryResults: unknown
+    remoteConfig: unknown
+  }): Promise<unknown> => {
+    return deepMerge({}, options.remoteConfig, options.queryResults || {})
+  }
+  constructor(
+    readonly dependencyConfig: (options: {
+      effects: Effects
+      localConfig: Input
+    }) => Promise<void | DeepPartial<RemoteConfig>>,
+    readonly update: Update<
+      void | DeepPartial<RemoteConfig>,
+      RemoteConfig
+    > = DependencyConfig.defaultUpdate as any,
+  ) {}
+ 
+  async query(options: { effects: Effects; localConfig: unknown }) {
+    return this.dependencyConfig({
+      localConfig: options.localConfig as Input,
+      effects: options.effects,
+    })
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/dependencyConfig/index.html b/sdk/lib/coverage/lcov-report/lib/dependencyConfig/index.html new file mode 100644 index 000000000..42606d331 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/dependencyConfig/index.html @@ -0,0 +1,131 @@ + + + + + + Code coverage report for lib/dependencyConfig + + + + + + + + + +
+
+

All files lib/dependencyConfig

+
+ +
+ 77.77% + Statements + 7/9 +
+ + +
+ 33.33% + Branches + 1/3 +
+ + +
+ 50% + Functions + 2/4 +
+ + +
+ 77.77% + Lines + 7/9 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
DependencyConfig.ts +
+
71.42%5/733.33%1/333.33%1/371.42%5/7
setupDependencyConfig.ts +
+
100%2/2100%0/0100%1/1100%2/2
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/dependencyConfig/setupDependencyConfig.ts.html b/sdk/lib/coverage/lcov-report/lib/dependencyConfig/setupDependencyConfig.ts.html new file mode 100644 index 000000000..255381bb0 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/dependencyConfig/setupDependencyConfig.ts.html @@ -0,0 +1,151 @@ + + + + + + Code coverage report for lib/dependencyConfig/setupDependencyConfig.ts + + + + + + + + + +
+
+

All files / lib/dependencyConfig setupDependencyConfig.ts

+
+ +
+ 100% + Statements + 2/2 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 100% + Functions + 1/1 +
+ + +
+ 100% + Lines + 2/2 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23  +  +  +  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  + 
import { Config } from "../config/builder/config"
+import { SDKManifest } from "../manifest/ManifestTypes"
+import { ExpectedExports } from "../types"
+import { DependencyConfig } from "./DependencyConfig"
+ 
+export function setupDependencyConfig<
+  Store,
+  Input extends Record<string, any>,
+  Manifest extends SDKManifest,
+>(
+  _config: Config<Input, Store> | Config<Input, never>,
+  autoConfigs: {
+    [key in keyof Manifest["dependencies"] & string]: DependencyConfig<
+      Manifest,
+      Store,
+      Input,
+      any
+    > | null
+  },
+): ExpectedExports.dependencyConfig {
+  return autoConfigs
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/emverLite/index.html b/sdk/lib/coverage/lcov-report/lib/emverLite/index.html new file mode 100644 index 000000000..407727220 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/emverLite/index.html @@ -0,0 +1,116 @@ + + + + + + Code coverage report for lib/emverLite + + + + + + + + + +
+
+

All files lib/emverLite

+
+ +
+ 96.99% + Statements + 129/133 +
+ + +
+ 91.89% + Branches + 34/37 +
+ + +
+ 97.56% + Functions + 40/41 +
+ + +
+ 97.65% + Lines + 125/128 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
mod.ts +
+
96.99%129/13391.89%34/3797.56%40/4197.65%125/128
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/emverLite/mod.ts.html b/sdk/lib/coverage/lcov-report/lib/emverLite/mod.ts.html new file mode 100644 index 000000000..94030817d --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/emverLite/mod.ts.html @@ -0,0 +1,1054 @@ + + + + + + Code coverage report for lib/emverLite/mod.ts + + + + + + + + + +
+
+

All files / lib/emverLite mod.ts

+
+ +
+ 96.99% + Statements + 129/133 +
+ + +
+ 91.89% + Branches + 34/37 +
+ + +
+ 97.56% + Functions + 40/41 +
+ + +
+ 97.65% + Lines + 125/128 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +3246x +  +6x +  +  +  +  +  +  +4x +4x +4x +  +  +  +  +  +  +  +6x +19x +  +  +  +  +  +  +  +6x +6x +1x +  +5x +5x +  +  +  +  +  +  +  +6x +5x +1x +  +4x +4x +  +  +  +  +  +  +  +6x +1x +  +  +  +  +  +6x +  +  +  +  +  +  +124x +  +  +124x +  +  +  +  +  +  +149x +317x +149x +316x +3x +  +  +146x +  +  +150x +150x +  +  +  +  +  +  +4x +  +  +  +106x +220x +18x +  +202x +35x +  +  +167x +19x +  +  +34x +  +  +  +61x +23x +  +38x +74x +18x +  +  +20x +  +  +24x +  +  +9x +  +  +18x +  +  +  +  +  +  +  +  +6x +2x +4x +2x +  +2x +  +  +  +  +  +  +  +  +3x +  +1x +1x +1x +  +  +  +  +7x +  +  +  +  +  +  +  +6x +  +  +  +  +  +  +  +55x +19x +  +36x +36x +6x +  +33x +8x +  +29x +1x +12x +9x +  +  +28x +28x +3x +22x +  +25x +25x +4x +4x +  +4x +24x +24x +  +  +  +  +  +  +  +21x +  +1x +1x +6x +6x +  +  +  +2x +2x +9x +9x +  +  +  +  +18x +  +7x +7x +30x +30x +  +  +  +4x +4x +18x +18x +  +  +  +7x +7x +21x +21x +  +  +  +  +  +  +  +  +  +  +38x +38x +  +  +  +  +  +  +  +  +  +  +5x +5x +  +20x +8x +  +12x +12x +6x +  +  +6x +  +5x +  +  +  +  +  +  +  +4x +4x +  +17x +4x +  +13x +13x +4x +  +  +9x +  +4x +  +  +  +  +  +  +  +  +1x +1x +  +  + 
import * as matches from "ts-matches"
+ 
+const starSub = /((\d+\.)*\d+)\.\*/
+// prettier-ignore
+export type ValidEmVer = `${number}${`.${number}` | ""}${`.${number}` | ""}${`-${string}` | ""}`;
+// prettier-ignore
+export type ValidEmVerRange = `${'>=' | '<='| '<' | '>' | ''}${'^' | '~' | ''}${number | '*'}${`.${number | '*'}` | ""}${`.${number | '*'}` | ""}${`-${string}` | ""}`;
+ 
+function incrementLastNumber(list: number[]) {
+  const newList = [...list]
+  newList[newList.length - 1]++
+  return newList
+}
+/**
+ * Will take in a range, like `>1.2` or `<1.2.3.4` or `=1.2` or `1.*`
+ * and return a checker, that has the check function for checking that a version is in the valid
+ * @param range
+ * @returns
+ */
+export function rangeOf(range: string | Checker): Checker {
+  return Checker.parse(range)
+}
+ 
+/**
+ * Used to create a checker that will `and` all the ranges passed in
+ * @param ranges
+ * @returns
+ */
+export function rangeAnd(...ranges: (string | Checker)[]): Checker {
+  if (ranges.length === 0) {
+    throw new Error("No ranges given")
+  }
+  const [firstCheck, ...rest] = ranges
+  return Checker.parse(firstCheck).and(...rest)
+}
+ 
+/**
+ * Used to create a checker that will `or` all the ranges passed in
+ * @param ranges
+ * @returns
+ */
+export function rangeOr(...ranges: (string | Checker)[]): Checker {
+  if (ranges.length === 0) {
+    throw new Error("No ranges given")
+  }
+  const [firstCheck, ...rest] = ranges
+  return Checker.parse(firstCheck).or(...rest)
+}
+ 
+/**
+ * This will negate the checker, so given a checker that checks for >= 1.0.0, it will check for < 1.0.0
+ * @param range
+ * @returns
+ */
+export function notRange(range: string | Checker): Checker {
+  return rangeOf(range).not()
+}
+ 
+/**
+ * EmVer is a set of versioning of any pattern like 1 or 1.2 or 1.2.3 or 1.2.3.4 or ..
+ */
+export class EmVer {
+  /**
+   * Convert the range, should be 1.2.* or * into a emver
+   * Or an already made emver
+   * IsUnsafe
+   */
+  static from(range: string | EmVer): EmVer {
+    Iif (range instanceof EmVer) {
+      return range
+    }
+    return EmVer.parse(range)
+  }
+  /**
+   * Convert the range, should be 1.2.* or * into a emver
+   * IsUnsafe
+   */
+  static parse(rangeExtra: string): EmVer {
+    const [range, extra] = rangeExtra.split("-")
+    const values = range.split(".").map((x) => parseInt(x))
+    for (const value of values) {
+      if (isNaN(value)) {
+        throw new Error(`Couldn't parse range: ${range}`)
+      }
+    }
+    return new EmVer(values, extra)
+  }
+  private constructor(
+    public readonly values: number[],
+    readonly extra: string | null,
+  ) {}
+ 
+  /**
+   * Used when we need a new emver that has the last number incremented, used in the 1.* like things
+   */
+  public withLastIncremented() {
+    return new EmVer(incrementLastNumber(this.values), null)
+  }
+ 
+  public greaterThan(other: EmVer): boolean {
+    for (const i in this.values) {
+      if (other.values[i] == null) {
+        return true
+      }
+      if (this.values[i] > other.values[i]) {
+        return true
+      }
+ 
+      if (this.values[i] < other.values[i]) {
+        return false
+      }
+    }
+    return false
+  }
+ 
+  public equals(other: EmVer): boolean {
+    if (other.values.length !== this.values.length) {
+      return false
+    }
+    for (const i in this.values) {
+      if (this.values[i] !== other.values[i]) {
+        return false
+      }
+    }
+    return true
+  }
+  public greaterThanOrEqual(other: EmVer): boolean {
+    return this.greaterThan(other) || this.equals(other)
+  }
+  public lessThanOrEqual(other: EmVer): boolean {
+    return !this.greaterThan(other)
+  }
+  public lessThan(other: EmVer): boolean {
+    return !this.greaterThanOrEqual(other)
+  }
+  /**
+   * Return a enum string that describes (used for switching/iffs)
+   * to know comparison
+   * @param other
+   * @returns
+   */
+  public compare(other: EmVer) {
+    if (this.equals(other)) {
+      return "equal" as const
+    } else if (this.greaterThan(other)) {
+      return "greater" as const
+    } else {
+      return "less" as const
+    }
+  }
+  /**
+   * Used when sorting emver's in a list using the sort method
+   * @param other
+   * @returns
+   */
+  public compareForSort(other: EmVer) {
+    return matches
+      .matches(this.compare(other))
+      .when("equal", () => 0 as const)
+      .when("greater", () => 1 as const)
+      .when("less", () => -1 as const)
+      .unwrap()
+  }
+ 
+  toString() {
+    return `${this.values.join(".")}${this.extra ? `-${this.extra}` : ""}` as ValidEmVer
+  }
+}
+ 
+/**
+ * A checker is a function that takes a version and returns true if the version matches the checker.
+ * Used when we are doing range checking, like saying ">=1.0.0".check("1.2.3") will be true
+ */
+export class Checker {
+  /**
+   * Will take in a range, like `>1.2` or `<1.2.3.4` or `=1.2` or `1.*`
+   * and return a checker, that has the check function for checking that a version is in the valid
+   * @param range
+   * @returns
+   */
+  static parse(range: string | Checker): Checker {
+    if (range instanceof Checker) {
+      return range
+    }
+    range = range.trim()
+    if (range.indexOf("||") !== -1) {
+      return rangeOr(...range.split("||").map((x) => Checker.parse(x)))
+    }
+    if (range.indexOf("&&") !== -1) {
+      return rangeAnd(...range.split("&&").map((x) => Checker.parse(x)))
+    }
+    if (range === "*") {
+      return new Checker((version) => {
+        EmVer.from(version)
+        return true
+      }, range)
+    }
+    Iif (range.startsWith("!!")) return Checker.parse(range.substring(2))
+    if (range.startsWith("!")) {
+      const tempValue = Checker.parse(range.substring(1))
+      return new Checker((x) => !tempValue.check(x), range)
+    }
+    const starSubMatches = starSub.exec(range)
+    if (starSubMatches != null) {
+      const emVarLower = EmVer.parse(starSubMatches[1])
+      const emVarUpper = emVarLower.withLastIncremented()
+ 
+      return new Checker((version) => {
+        const v = EmVer.from(version)
+        return (
+          (v.greaterThan(emVarLower) || v.equals(emVarLower)) &&
+          !v.greaterThan(emVarUpper) &&
+          !v.equals(emVarUpper)
+        )
+      }, range)
+    }
+ 
+    switch (range.substring(0, 2)) {
+      case ">=": {
+        const emVar = EmVer.parse(range.substring(2))
+        return new Checker((version) => {
+          const v = EmVer.from(version)
+          return v.greaterThanOrEqual(emVar)
+        }, range)
+      }
+      case "<=": {
+        const emVar = EmVer.parse(range.substring(2))
+        return new Checker((version) => {
+          const v = EmVer.from(version)
+          return v.lessThanOrEqual(emVar)
+        }, range)
+      }
+    }
+ 
+    switch (range.substring(0, 1)) {
+      case ">": {
+        const emVar = EmVer.parse(range.substring(1))
+        return new Checker((version) => {
+          const v = EmVer.from(version)
+          return v.greaterThan(emVar)
+        }, range)
+      }
+      case "<": {
+        const emVar = EmVer.parse(range.substring(1))
+        return new Checker((version) => {
+          const v = EmVer.from(version)
+          return v.lessThan(emVar)
+        }, range)
+      }
+      case "=": {
+        const emVar = EmVer.parse(range.substring(1))
+        return new Checker((version) => {
+          const v = EmVer.from(version)
+          return v.equals(emVar)
+        }, `=${emVar.toString()}`)
+      }
+    }
+    throw new Error("Couldn't parse range: " + range)
+  }
+  constructor(
+    /**
+     * Check is the function that will be given a emver or unparsed emver and should give if it follows
+     * a pattern
+     */
+    public readonly check: (value: ValidEmVer | EmVer) => boolean,
+    private readonly _range: string,
+  ) {}
+ 
+  get range() {
+    return this._range as ValidEmVerRange
+  }
+ 
+  /**
+   * Used when we want the `and` condition with another checker
+   */
+  public and(...others: (Checker | string)[]): Checker {
+    const othersCheck = others.map(Checker.parse)
+    return new Checker(
+      (value) => {
+        if (!this.check(value)) {
+          return false
+        }
+        for (const other of othersCheck) {
+          if (!other.check(value)) {
+            return false
+          }
+        }
+        return true
+      },
+      othersCheck.map((x) => x._range).join(" && "),
+    )
+  }
+ 
+  /**
+   * Used when we want the `or` condition with another checker
+   */
+  public or(...others: (Checker | string)[]): Checker {
+    const othersCheck = others.map(Checker.parse)
+    return new Checker(
+      (value) => {
+        if (this.check(value)) {
+          return true
+        }
+        for (const other of othersCheck) {
+          if (other.check(value)) {
+            return true
+          }
+        }
+        return false
+      },
+      othersCheck.map((x) => x._range).join(" || "),
+    )
+  }
+ 
+  /**
+   * A useful example is making sure we don't match an exact version, like !=1.2.3
+   * @returns
+   */
+  public not(): Checker {
+    let newRange = `!${this._range}`
+    return Checker.parse(newRange)
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/exver/exver.ts.html b/sdk/lib/coverage/lcov-report/lib/exver/exver.ts.html new file mode 100644 index 000000000..493ef10b4 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/exver/exver.ts.html @@ -0,0 +1,7606 @@ + + + + + + Code coverage report for lib/exver/exver.ts + + + + + + + + + +
+
+

All files / lib/exver exver.ts

+
+ +
+ 73.61% + Statements + 611/830 +
+ + +
+ 62.5% + Branches + 185/296 +
+ + +
+ 69.31% + Functions + 61/88 +
+ + +
+ 73.76% + Lines + 582/789 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335 +336 +337 +338 +339 +340 +341 +342 +343 +344 +345 +346 +347 +348 +349 +350 +351 +352 +353 +354 +355 +356 +357 +358 +359 +360 +361 +362 +363 +364 +365 +366 +367 +368 +369 +370 +371 +372 +373 +374 +375 +376 +377 +378 +379 +380 +381 +382 +383 +384 +385 +386 +387 +388 +389 +390 +391 +392 +393 +394 +395 +396 +397 +398 +399 +400 +401 +402 +403 +404 +405 +406 +407 +408 +409 +410 +411 +412 +413 +414 +415 +416 +417 +418 +419 +420 +421 +422 +423 +424 +425 +426 +427 +428 +429 +430 +431 +432 +433 +434 +435 +436 +437 +438 +439 +440 +441 +442 +443 +444 +445 +446 +447 +448 +449 +450 +451 +452 +453 +454 +455 +456 +457 +458 +459 +460 +461 +462 +463 +464 +465 +466 +467 +468 +469 +470 +471 +472 +473 +474 +475 +476 +477 +478 +479 +480 +481 +482 +483 +484 +485 +486 +487 +488 +489 +490 +491 +492 +493 +494 +495 +496 +497 +498 +499 +500 +501 +502 +503 +504 +505 +506 +507 +508 +509 +510 +511 +512 +513 +514 +515 +516 +517 +518 +519 +520 +521 +522 +523 +524 +525 +526 +527 +528 +529 +530 +531 +532 +533 +534 +535 +536 +537 +538 +539 +540 +541 +542 +543 +544 +545 +546 +547 +548 +549 +550 +551 +552 +553 +554 +555 +556 +557 +558 +559 +560 +561 +562 +563 +564 +565 +566 +567 +568 +569 +570 +571 +572 +573 +574 +575 +576 +577 +578 +579 +580 +581 +582 +583 +584 +585 +586 +587 +588 +589 +590 +591 +592 +593 +594 +595 +596 +597 +598 +599 +600 +601 +602 +603 +604 +605 +606 +607 +608 +609 +610 +611 +612 +613 +614 +615 +616 +617 +618 +619 +620 +621 +622 +623 +624 +625 +626 +627 +628 +629 +630 +631 +632 +633 +634 +635 +636 +637 +638 +639 +640 +641 +642 +643 +644 +645 +646 +647 +648 +649 +650 +651 +652 +653 +654 +655 +656 +657 +658 +659 +660 +661 +662 +663 +664 +665 +666 +667 +668 +669 +670 +671 +672 +673 +674 +675 +676 +677 +678 +679 +680 +681 +682 +683 +684 +685 +686 +687 +688 +689 +690 +691 +692 +693 +694 +695 +696 +697 +698 +699 +700 +701 +702 +703 +704 +705 +706 +707 +708 +709 +710 +711 +712 +713 +714 +715 +716 +717 +718 +719 +720 +721 +722 +723 +724 +725 +726 +727 +728 +729 +730 +731 +732 +733 +734 +735 +736 +737 +738 +739 +740 +741 +742 +743 +744 +745 +746 +747 +748 +749 +750 +751 +752 +753 +754 +755 +756 +757 +758 +759 +760 +761 +762 +763 +764 +765 +766 +767 +768 +769 +770 +771 +772 +773 +774 +775 +776 +777 +778 +779 +780 +781 +782 +783 +784 +785 +786 +787 +788 +789 +790 +791 +792 +793 +794 +795 +796 +797 +798 +799 +800 +801 +802 +803 +804 +805 +806 +807 +808 +809 +810 +811 +812 +813 +814 +815 +816 +817 +818 +819 +820 +821 +822 +823 +824 +825 +826 +827 +828 +829 +830 +831 +832 +833 +834 +835 +836 +837 +838 +839 +840 +841 +842 +843 +844 +845 +846 +847 +848 +849 +850 +851 +852 +853 +854 +855 +856 +857 +858 +859 +860 +861 +862 +863 +864 +865 +866 +867 +868 +869 +870 +871 +872 +873 +874 +875 +876 +877 +878 +879 +880 +881 +882 +883 +884 +885 +886 +887 +888 +889 +890 +891 +892 +893 +894 +895 +896 +897 +898 +899 +900 +901 +902 +903 +904 +905 +906 +907 +908 +909 +910 +911 +912 +913 +914 +915 +916 +917 +918 +919 +920 +921 +922 +923 +924 +925 +926 +927 +928 +929 +930 +931 +932 +933 +934 +935 +936 +937 +938 +939 +940 +941 +942 +943 +944 +945 +946 +947 +948 +949 +950 +951 +952 +953 +954 +955 +956 +957 +958 +959 +960 +961 +962 +963 +964 +965 +966 +967 +968 +969 +970 +971 +972 +973 +974 +975 +976 +977 +978 +979 +980 +981 +982 +983 +984 +985 +986 +987 +988 +989 +990 +991 +992 +993 +994 +995 +996 +997 +998 +999 +1000 +1001 +1002 +1003 +1004 +1005 +1006 +1007 +1008 +1009 +1010 +1011 +1012 +1013 +1014 +1015 +1016 +1017 +1018 +1019 +1020 +1021 +1022 +1023 +1024 +1025 +1026 +1027 +1028 +1029 +1030 +1031 +1032 +1033 +1034 +1035 +1036 +1037 +1038 +1039 +1040 +1041 +1042 +1043 +1044 +1045 +1046 +1047 +1048 +1049 +1050 +1051 +1052 +1053 +1054 +1055 +1056 +1057 +1058 +1059 +1060 +1061 +1062 +1063 +1064 +1065 +1066 +1067 +1068 +1069 +1070 +1071 +1072 +1073 +1074 +1075 +1076 +1077 +1078 +1079 +1080 +1081 +1082 +1083 +1084 +1085 +1086 +1087 +1088 +1089 +1090 +1091 +1092 +1093 +1094 +1095 +1096 +1097 +1098 +1099 +1100 +1101 +1102 +1103 +1104 +1105 +1106 +1107 +1108 +1109 +1110 +1111 +1112 +1113 +1114 +1115 +1116 +1117 +1118 +1119 +1120 +1121 +1122 +1123 +1124 +1125 +1126 +1127 +1128 +1129 +1130 +1131 +1132 +1133 +1134 +1135 +1136 +1137 +1138 +1139 +1140 +1141 +1142 +1143 +1144 +1145 +1146 +1147 +1148 +1149 +1150 +1151 +1152 +1153 +1154 +1155 +1156 +1157 +1158 +1159 +1160 +1161 +1162 +1163 +1164 +1165 +1166 +1167 +1168 +1169 +1170 +1171 +1172 +1173 +1174 +1175 +1176 +1177 +1178 +1179 +1180 +1181 +1182 +1183 +1184 +1185 +1186 +1187 +1188 +1189 +1190 +1191 +1192 +1193 +1194 +1195 +1196 +1197 +1198 +1199 +1200 +1201 +1202 +1203 +1204 +1205 +1206 +1207 +1208 +1209 +1210 +1211 +1212 +1213 +1214 +1215 +1216 +1217 +1218 +1219 +1220 +1221 +1222 +1223 +1224 +1225 +1226 +1227 +1228 +1229 +1230 +1231 +1232 +1233 +1234 +1235 +1236 +1237 +1238 +1239 +1240 +1241 +1242 +1243 +1244 +1245 +1246 +1247 +1248 +1249 +1250 +1251 +1252 +1253 +1254 +1255 +1256 +1257 +1258 +1259 +1260 +1261 +1262 +1263 +1264 +1265 +1266 +1267 +1268 +1269 +1270 +1271 +1272 +1273 +1274 +1275 +1276 +1277 +1278 +1279 +1280 +1281 +1282 +1283 +1284 +1285 +1286 +1287 +1288 +1289 +1290 +1291 +1292 +1293 +1294 +1295 +1296 +1297 +1298 +1299 +1300 +1301 +1302 +1303 +1304 +1305 +1306 +1307 +1308 +1309 +1310 +1311 +1312 +1313 +1314 +1315 +1316 +1317 +1318 +1319 +1320 +1321 +1322 +1323 +1324 +1325 +1326 +1327 +1328 +1329 +1330 +1331 +1332 +1333 +1334 +1335 +1336 +1337 +1338 +1339 +1340 +1341 +1342 +1343 +1344 +1345 +1346 +1347 +1348 +1349 +1350 +1351 +1352 +1353 +1354 +1355 +1356 +1357 +1358 +1359 +1360 +1361 +1362 +1363 +1364 +1365 +1366 +1367 +1368 +1369 +1370 +1371 +1372 +1373 +1374 +1375 +1376 +1377 +1378 +1379 +1380 +1381 +1382 +1383 +1384 +1385 +1386 +1387 +1388 +1389 +1390 +1391 +1392 +1393 +1394 +1395 +1396 +1397 +1398 +1399 +1400 +1401 +1402 +1403 +1404 +1405 +1406 +1407 +1408 +1409 +1410 +1411 +1412 +1413 +1414 +1415 +1416 +1417 +1418 +1419 +1420 +1421 +1422 +1423 +1424 +1425 +1426 +1427 +1428 +1429 +1430 +1431 +1432 +1433 +1434 +1435 +1436 +1437 +1438 +1439 +1440 +1441 +1442 +1443 +1444 +1445 +1446 +1447 +1448 +1449 +1450 +1451 +1452 +1453 +1454 +1455 +1456 +1457 +1458 +1459 +1460 +1461 +1462 +1463 +1464 +1465 +1466 +1467 +1468 +1469 +1470 +1471 +1472 +1473 +1474 +1475 +1476 +1477 +1478 +1479 +1480 +1481 +1482 +1483 +1484 +1485 +1486 +1487 +1488 +1489 +1490 +1491 +1492 +1493 +1494 +1495 +1496 +1497 +1498 +1499 +1500 +1501 +1502 +1503 +1504 +1505 +1506 +1507 +1508 +1509 +1510 +1511 +1512 +1513 +1514 +1515 +1516 +1517 +1518 +1519 +1520 +1521 +1522 +1523 +1524 +1525 +1526 +1527 +1528 +1529 +1530 +1531 +1532 +1533 +1534 +1535 +1536 +1537 +1538 +1539 +1540 +1541 +1542 +1543 +1544 +1545 +1546 +1547 +1548 +1549 +1550 +1551 +1552 +1553 +1554 +1555 +1556 +1557 +1558 +1559 +1560 +1561 +1562 +1563 +1564 +1565 +1566 +1567 +1568 +1569 +1570 +1571 +1572 +1573 +1574 +1575 +1576 +1577 +1578 +1579 +1580 +1581 +1582 +1583 +1584 +1585 +1586 +1587 +1588 +1589 +1590 +1591 +1592 +1593 +1594 +1595 +1596 +1597 +1598 +1599 +1600 +1601 +1602 +1603 +1604 +1605 +1606 +1607 +1608 +1609 +1610 +1611 +1612 +1613 +1614 +1615 +1616 +1617 +1618 +1619 +1620 +1621 +1622 +1623 +1624 +1625 +1626 +1627 +1628 +1629 +1630 +1631 +1632 +1633 +1634 +1635 +1636 +1637 +1638 +1639 +1640 +1641 +1642 +1643 +1644 +1645 +1646 +1647 +1648 +1649 +1650 +1651 +1652 +1653 +1654 +1655 +1656 +1657 +1658 +1659 +1660 +1661 +1662 +1663 +1664 +1665 +1666 +1667 +1668 +1669 +1670 +1671 +1672 +1673 +1674 +1675 +1676 +1677 +1678 +1679 +1680 +1681 +1682 +1683 +1684 +1685 +1686 +1687 +1688 +1689 +1690 +1691 +1692 +1693 +1694 +1695 +1696 +1697 +1698 +1699 +1700 +1701 +1702 +1703 +1704 +1705 +1706 +1707 +1708 +1709 +1710 +1711 +1712 +1713 +1714 +1715 +1716 +1717 +1718 +1719 +1720 +1721 +1722 +1723 +1724 +1725 +1726 +1727 +1728 +1729 +1730 +1731 +1732 +1733 +1734 +1735 +1736 +1737 +1738 +1739 +1740 +1741 +1742 +1743 +1744 +1745 +1746 +1747 +1748 +1749 +1750 +1751 +1752 +1753 +1754 +1755 +1756 +1757 +1758 +1759 +1760 +1761 +1762 +1763 +1764 +1765 +1766 +1767 +1768 +1769 +1770 +1771 +1772 +1773 +1774 +1775 +1776 +1777 +1778 +1779 +1780 +1781 +1782 +1783 +1784 +1785 +1786 +1787 +1788 +1789 +1790 +1791 +1792 +1793 +1794 +1795 +1796 +1797 +1798 +1799 +1800 +1801 +1802 +1803 +1804 +1805 +1806 +1807 +1808 +1809 +1810 +1811 +1812 +1813 +1814 +1815 +1816 +1817 +1818 +1819 +1820 +1821 +1822 +1823 +1824 +1825 +1826 +1827 +1828 +1829 +1830 +1831 +1832 +1833 +1834 +1835 +1836 +1837 +1838 +1839 +1840 +1841 +1842 +1843 +1844 +1845 +1846 +1847 +1848 +1849 +1850 +1851 +1852 +1853 +1854 +1855 +1856 +1857 +1858 +1859 +1860 +1861 +1862 +1863 +1864 +1865 +1866 +1867 +1868 +1869 +1870 +1871 +1872 +1873 +1874 +1875 +1876 +1877 +1878 +1879 +1880 +1881 +1882 +1883 +1884 +1885 +1886 +1887 +1888 +1889 +1890 +1891 +1892 +1893 +1894 +1895 +1896 +1897 +1898 +1899 +1900 +1901 +1902 +1903 +1904 +1905 +1906 +1907 +1908 +1909 +1910 +1911 +1912 +1913 +1914 +1915 +1916 +1917 +1918 +1919 +1920 +1921 +1922 +1923 +1924 +1925 +1926 +1927 +1928 +1929 +1930 +1931 +1932 +1933 +1934 +1935 +1936 +1937 +1938 +1939 +1940 +1941 +1942 +1943 +1944 +1945 +1946 +1947 +1948 +1949 +1950 +1951 +1952 +1953 +1954 +1955 +1956 +1957 +1958 +1959 +1960 +1961 +1962 +1963 +1964 +1965 +1966 +1967 +1968 +1969 +1970 +1971 +1972 +1973 +1974 +1975 +1976 +1977 +1978 +1979 +1980 +1981 +1982 +1983 +1984 +1985 +1986 +1987 +1988 +1989 +1990 +1991 +1992 +1993 +1994 +1995 +1996 +1997 +1998 +1999 +2000 +2001 +2002 +2003 +2004 +2005 +2006 +2007 +2008 +2009 +2010 +2011 +2012 +2013 +2014 +2015 +2016 +2017 +2018 +2019 +2020 +2021 +2022 +2023 +2024 +2025 +2026 +2027 +2028 +2029 +2030 +2031 +2032 +2033 +2034 +2035 +2036 +2037 +2038 +2039 +2040 +2041 +2042 +2043 +2044 +2045 +2046 +2047 +2048 +2049 +2050 +2051 +2052 +2053 +2054 +2055 +2056 +2057 +2058 +2059 +2060 +2061 +2062 +2063 +2064 +2065 +2066 +2067 +2068 +2069 +2070 +2071 +2072 +2073 +2074 +2075 +2076 +2077 +2078 +2079 +2080 +2081 +2082 +2083 +2084 +2085 +2086 +2087 +2088 +2089 +2090 +2091 +2092 +2093 +2094 +2095 +2096 +2097 +2098 +2099 +2100 +2101 +2102 +2103 +2104 +2105 +2106 +2107 +2108 +2109 +2110 +2111 +2112 +2113 +2114 +2115 +2116 +2117 +2118 +2119 +2120 +2121 +2122 +2123 +2124 +2125 +2126 +2127 +2128 +2129 +2130 +2131 +2132 +2133 +2134 +2135 +2136 +2137 +2138 +2139 +2140 +2141 +2142 +2143 +2144 +2145 +2146 +2147 +2148 +2149 +2150 +2151 +2152 +2153 +2154 +2155 +2156 +2157 +2158 +2159 +2160 +2161 +2162 +2163 +2164 +2165 +2166 +2167 +2168 +2169 +2170 +2171 +2172 +2173 +2174 +2175 +2176 +2177 +2178 +2179 +2180 +2181 +2182 +2183 +2184 +2185 +2186 +2187 +2188 +2189 +2190 +2191 +2192 +2193 +2194 +2195 +2196 +2197 +2198 +2199 +2200 +2201 +2202 +2203 +2204 +2205 +2206 +2207 +2208 +2209 +2210 +2211 +2212 +2213 +2214 +2215 +2216 +2217 +2218 +2219 +2220 +2221 +2222 +2223 +2224 +2225 +2226 +2227 +2228 +2229 +2230 +2231 +2232 +2233 +2234 +2235 +2236 +2237 +2238 +2239 +2240 +2241 +2242 +2243 +2244 +2245 +2246 +2247 +2248 +2249 +2250 +2251 +2252 +2253 +2254 +2255 +2256 +2257 +2258 +2259 +2260 +2261 +2262 +2263 +2264 +2265 +2266 +2267 +2268 +2269 +2270 +2271 +2272 +2273 +2274 +2275 +2276 +2277 +2278 +2279 +2280 +2281 +2282 +2283 +2284 +2285 +2286 +2287 +2288 +2289 +2290 +2291 +2292 +2293 +2294 +2295 +2296 +2297 +2298 +2299 +2300 +2301 +2302 +2303 +2304 +2305 +2306 +2307 +2308 +2309 +2310 +2311 +2312 +2313 +2314 +2315 +2316 +2317 +2318 +2319 +2320 +2321 +2322 +2323 +2324 +2325 +2326 +2327 +2328 +2329 +2330 +2331 +2332 +2333 +2334 +2335 +2336 +2337 +2338 +2339 +2340 +2341 +2342 +2343 +2344 +2345 +2346 +2347 +2348 +2349 +2350 +2351 +2352 +2353 +2354 +2355 +2356 +2357 +2358 +2359 +2360 +2361 +2362 +2363 +2364 +2365 +2366 +2367 +2368 +2369 +2370 +2371 +2372 +2373 +2374 +2375 +2376 +2377 +2378 +2379 +2380 +2381 +2382 +2383 +2384 +2385 +2386 +2387 +2388 +2389 +2390 +2391 +2392 +2393 +2394 +2395 +2396 +2397 +2398 +2399 +2400 +2401 +2402 +2403 +2404 +2405 +2406 +2407 +2408 +2409 +2410 +2411 +2412 +2413 +2414 +2415 +2416 +2417 +2418 +2419 +2420 +2421 +2422 +2423 +2424 +2425 +2426 +2427 +2428 +2429 +2430 +2431 +2432 +2433 +2434 +2435 +2436 +2437 +2438 +2439 +2440 +2441 +2442 +2443 +2444 +2445 +2446 +2447 +2448 +2449 +2450 +2451 +2452 +2453 +2454 +2455 +2456 +2457 +2458 +2459 +2460 +2461 +2462 +2463 +2464 +2465 +2466 +2467 +2468 +2469 +2470 +2471 +2472 +2473 +2474 +2475 +2476 +2477 +2478 +2479 +2480 +2481 +2482 +2483 +2484 +2485 +2486 +2487 +2488 +2489 +2490 +2491 +2492 +2493 +2494 +2495 +2496 +2497 +2498 +2499 +2500 +2501 +2502 +2503 +2504 +2505 +2506 +2507 +2508  +  +  +  +  +  +  +  +6x +  +  +  +  +  +  +6x +  +6x +  +6x +  +  +  +  +  +3x +  +  +  +  +  +  +  +3x +  +3x +  +3x +  +3x +  +3x +  +  +  +6x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +6x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +6x +  +3x +  +  +  +2x +  +  +  +  +  +3x +  +3x +  +  +  +  +  +  +  +3x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +4x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +6x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +5x +  +  +  +  +  +3x +  +  +  +  +3x +  +  +3x +  +3x +  +2x +  +2x +  +2x +  +  +  +3x +  +  +  +3x +  +  +  +1x +  +  +  +  +2x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +3x +  +  +  +3x +  +  +  +  +  +127x +  +  +127x +  +127x +  +  +127x +  +127x +  +  +127x +127x +127x +127x +127x +127x +127x +127x +127x +127x +127x +127x +127x +127x +127x +127x +127x +127x +  +127x +127x +127x +127x +  +127x +127x +127x +127x +127x +127x +127x +127x +127x +127x +127x +127x +127x +127x +127x +127x +127x +127x +127x +127x +127x +127x +127x +  +  +127x +  +  +127x +24x +  +127x +24x +  +127x +2x +  +127x +1x +  +127x +  +  +127x +1x +  +127x +2x +  +127x +7x +  +127x +4x +  +127x +7x +  +127x +  +  +127x +  +  +127x +3x +  +127x +  +106x +  +  +127x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +127x +  +  +127x +  +  +127x +1x +  +127x +  +242x +  +  +  +  +  +  +  +127x +  +1x +  +  +127x +  +2x +  +  +127x +  +242x +  +  +127x +393x +  +127x +  +127x +  +127x +  +127x +  +127x +  +127x +  +  +  +  +  +127x +  +127x +  +  +  +  +  +127x +  +  +  +  +  +394x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +2286x +  +  +  +  +  +508x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +127x +  +  +  +  +  +6x +  +  +  +  +6x +  +3x +  +  +  +3x +  +3x +  +1x +  +  +  +3x +  +3x +  +  +  +  +  +  +  +3x +  +4x +  +  +  +  +  +  +  +4x +  +  +  +4x +  +  +  +3x +  +  +3x +  +  +  +  +  +  +3x +  +3x +  +  +3x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +3x +  +  +  +  +  +  +3x +  +  +  +  +  +1542x +  +  +1540x +  +438x +  +438x +  +  +  +1540x +  +  +  +  +  +  +  +  +  +  +  +3x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +18x +  +18x +  +18x +  +18x +  +18x +  +18x +  +18x +  +18x +  +18x +  +17x +  +  +18x +  +4x +  +4x +  +4x +  +  +  +14x +  +14x +  +  +18x +  +14x +  +  +18x +  +18x +  +4x +  +4x +  +  +  +14x +  +14x +  +  +18x +  +7x +  +7x +  +7x +  +7x +  +7x +  +7x +  +5x +  +  +7x +  +3x +  +3x +  +3x +  +  +  +4x +  +4x +  +  +7x +  +4x +  +  +7x +  +7x +  +3x +  +3x +  +  +  +4x +  +4x +  +  +  +18x +  +18x +  +  +  +  +  +  +  +  +  +18x +  +  +  +  +  +  +  +  +  +25x +  +3x +  +3x +  +  +  +22x +  +22x +  +  +  +25x +  +  +  +  +  +  +  +  +  +22x +  +4x +  +4x +  +  +  +18x +  +18x +  +  +  +22x +  +  +  +  +  +  +  +  +  +45x +  +45x +  +45x +  +45x +  +21x +  +21x +  +19x +  +19x +  +18x +  +  +  +  +  +  +45x +  +  +  +  +  +  +  +  +  +45x +  +45x +  +  +  +  +  +  +  +45x +  +45x +  +  +45x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +45x +  +45x +  +  +  +45x +  +  +  +  +  +  +  +  +  +45x +  +45x +  +45x +  +21x +  +  +45x +  +45x +  +45x +  +24x +  +24x +  +  +  +21x +  +21x +  +  +  +45x +  +  +  +  +  +  +  +  +  +45x +  +45x +  +45x +  +45x +  +  +45x +  +45x +  +24x +  +24x +  +5x +  +5x +  +  +  +19x +  +19x +  +  +24x +  +5x +  +5x +  +5x +  +5x +  +  +  +  +  +  +  +  +  +  +19x +  +19x +  +  +24x +  +19x +  +  +24x +  +24x +  +  +  +21x +  +21x +  +  +  +45x +  +  +  +  +  +  +  +  +  +21x +  +21x +  +2x +  +2x +  +  +  +19x +  +19x +  +  +21x +  +2x +  +2x +  +2x +  +2x +  +2x +  +  +  +  +  +  +  +  +  +  +19x +  +19x +  +  +  +21x +  +  +  +  +  +  +  +  +  +19x +  +19x +  +1x +  +1x +  +  +  +18x +  +18x +  +  +19x +  +1x +  +1x +  +  +19x +  +  +19x +  +  +  +  +  +  +  +  +  +18x +  +18x +  +  +  +  +  +  +  +18x +  +18x +  +  +18x +  +  +  +  +  +  +18x +  +  +18x +  +  +  +  +  +  +  +  +  +45x +  +45x +  +1x +  +1x +  +  +  +44x +  +44x +  +  +45x +  +1x +  +1x +  +  +45x +  +45x +  +44x +  +44x +  +2x +  +2x +  +  +  +42x +  +42x +  +  +44x +  +2x +  +2x +  +  +44x +  +44x +  +42x +  +42x +  +7x +  +7x +  +  +  +35x +  +35x +  +  +42x +  +7x +  +7x +  +  +42x +  +42x +  +35x +  +35x +  +4x +  +4x +  +  +  +31x +  +31x +  +  +35x +  +4x +  +4x +  +  +35x +  +35x +  +31x +  +31x +  +7x +  +7x +  +  +  +24x +  +24x +  +  +31x +  +7x +  +7x +  +  +31x +  +31x +  +24x +  +24x +  +  +  +  +  +  +  +24x +  +24x +  +  +24x +  +  +  +  +  +  +24x +  +24x +  +24x +  +24x +  +  +  +  +  +  +  +24x +  +24x +  +  +24x +  +  +  +  +  +  +24x +  +24x +  +24x +  +24x +  +3x +  +3x +  +  +  +21x +  +21x +  +  +24x +  +3x +  +3x +  +  +24x +  +  +  +  +  +  +  +  +  +45x +  +  +  +  +  +  +  +  +  +109x +  +109x +  +109x +  +109x +  +  +109x +  +109x +  +107x +  +106x +  +106x +  +  +  +1x +  +1x +  +  +107x +  +106x +  +106x +  +106x +  +106x +  +  +  +  +  +  +  +  +  +  +1x +  +1x +  +  +  +  +2x +  +2x +  +  +  +109x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +154x +  +154x +  +  +  +  +  +  +  +154x +  +154x +  +  +154x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +154x +  +154x +  +  +  +154x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +1x +  +1x +  +1x +  +1x +  +  +  +  +  +  +  +  +1x +  +1x +  +4x +  +4x +  +3x +  +3x +  +  +  +1x +  +1x +  +  +  +  +  +  +  +  +1x +  +1x +  +1x +  +  +1x +  +  +1x +  +  +  +  +  +  +  +  +  +265x +  +265x +  +265x +  +242x +  +242x +  +241x +  +  +242x +  +242x +  +  +  +23x +  +23x +  +  +  +265x +  +  +  +  +  +  +  +  +  +242x +  +242x +  +1x +  +1x +  +  +  +241x +  +241x +  +  +242x +  +1x +  +1x +  +1x +  +1x +  +1x +  +1x +  +1x +  +  +  +  +  +  +  +  +1x +  +1x +  +1x +  +1x +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +1x +  +1x +  +1x +  +  +  +  +  +  +  +1x +  +1x +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +1x +  +  +  +1x +  +1x +  +  +  +  +  +  +  +  +  +  +241x +  +241x +  +  +  +242x +  +  +  +  +  +  +  +  +  +2x +  +2x +  +  +  +  +  +  +  +2x +  +2x +  +  +2x +  +2x +  +  +2x +  +2x +  +1x +  +  +2x +  +2x +  +2x +  +  +  +  +  +  +  +  +  +2x +  +  +  +  +  +  +  +  +  +265x +  +265x +  +265x +  +242x +  +242x +  +242x +  +93x +  +93x +  +  +  +149x +  +149x +  +  +242x +  +93x +  +93x +  +92x +  +92x +  +  +  +1x +  +1x +  +  +  +  +149x +  +149x +  +  +242x +  +150x +  +150x +  +150x +  +58x +  +58x +  +  +  +92x +  +92x +  +  +150x +  +58x +  +58x +  +58x +  +58x +  +  +  +  +  +  +  +  +  +  +92x +  +92x +  +  +  +242x +  +242x +  +  +  +23x +  +23x +  +  +  +265x +  +  +  +  +  +  +  +  +  +418x +  +418x +  +418x +  +393x +  +393x +  +  +  +25x +  +25x +  +  +418x +  +393x +  +395x +  +395x +  +2x +  +2x +  +  +  +393x +  +393x +  +  +  +  +  +25x +  +  +418x +  +393x +  +393x +  +  +418x +  +  +418x +  +  +  +  +  +  +  +  +  +79x +  +79x +  +79x +  +14x +  +14x +  +  +  +65x +  +65x +  +  +79x +  +14x +  +14x +  +  +  +  +  +  +  +14x +  +14x +  +  +  +79x +  +79x +  +79x +  +  +79x +  +  +  +127x +  +  +127x +  +124x +  +  +  +3x +  +  +  +  +  +3x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +6x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +6x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +6x +  +6x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
/* eslint-disable */
+ 
+ 
+ 
+const peggyParser: {parse: any, SyntaxError: any, DefaultTracer?: any} = // Generated by Peggy 3.0.2.
+//
+// https://peggyjs.org/
+// @ts-ignore
+(function() {
+// @ts-ignore
+  "use strict";
+ 
+// @ts-ignore
+function peg$subclass(child, parent) {
+// @ts-ignore
+  function C() { this.constructor = child; }
+// @ts-ignore
+  C.prototype = parent.prototype;
+// @ts-ignore
+  child.prototype = new C();
+}
+ 
+// @ts-ignore
+function peg$SyntaxError(message, expected, found, location) {
+// @ts-ignore
+  var self = Error.call(this, message);
+  // istanbul ignore next Check is a necessary evil to support older environments
+// @ts-ignore
+  if (Object.setPrototypeOf) {
+// @ts-ignore
+    Object.setPrototypeOf(self, peg$SyntaxError.prototype);
+  }
+// @ts-ignore
+  self.expected = expected;
+// @ts-ignore
+  self.found = found;
+// @ts-ignore
+  self.location = location;
+// @ts-ignore
+  self.name = "SyntaxError";
+// @ts-ignore
+  return self;
+}
+ 
+// @ts-ignore
+peg$subclass(peg$SyntaxError, Error);
+ 
+// @ts-ignore
+function peg$padEnd(str, targetLength, padString) {
+// @ts-ignore
+  padString = padString || " ";
+// @ts-ignore
+  Iif (str.length > targetLength) { return str; }
+// @ts-ignore
+  targetLength -= str.length;
+// @ts-ignore
+  padString += padString.repeat(targetLength);
+// @ts-ignore
+  return str + padString.slice(0, targetLength);
+}
+ 
+// @ts-ignore
+peg$SyntaxError.prototype.format = function(sources) {
+// @ts-ignore
+  var str = "Error: " + this.message;
+// @ts-ignore
+  Iif (this.location) {
+// @ts-ignore
+    var src = null;
+// @ts-ignore
+    var k;
+// @ts-ignore
+    for (k = 0; k < sources.length; k++) {
+// @ts-ignore
+      Iif (sources[k].source === this.location.source) {
+// @ts-ignore
+        src = sources[k].text.split(/\r\n|\n|\r/g);
+// @ts-ignore
+        break;
+      }
+    }
+// @ts-ignore
+    var s = this.location.start;
+// @ts-ignore
+    var offset_s = (this.location.source && (typeof this.location.source.offset === "function"))
+// @ts-ignore
+      ? this.location.source.offset(s)
+// @ts-ignore
+      : s;
+// @ts-ignore
+    var loc = this.location.source + ":" + offset_s.line + ":" + offset_s.column;
+// @ts-ignore
+    if (src) {
+// @ts-ignore
+      var e = this.location.end;
+// @ts-ignore
+      var filler = peg$padEnd("", offset_s.line.toString().length, ' ');
+// @ts-ignore
+      var line = src[s.line - 1];
+// @ts-ignore
+      var last = s.line === e.line ? e.column : line.length + 1;
+// @ts-ignore
+      var hatLen = (last - s.column) || 1;
+// @ts-ignore
+      str += "\n --> " + loc + "\n"
+// @ts-ignore
+          + filler + " |\n"
+// @ts-ignore
+          + offset_s.line + " | " + line + "\n"
+// @ts-ignore
+          + filler + " | " + peg$padEnd("", s.column - 1, ' ')
+// @ts-ignore
+          + peg$padEnd("", hatLen, "^");
+// @ts-ignore
+    } else {
+// @ts-ignore
+      str += "\n at " + loc;
+    }
+  }
+// @ts-ignore
+  return str;
+};
+ 
+// @ts-ignore
+peg$SyntaxError.buildMessage = function(expected, found) {
+// @ts-ignore
+  var DESCRIBE_EXPECTATION_FNS = {
+// @ts-ignore
+    literal: function(expectation) {
+// @ts-ignore
+      return "\"" + literalEscape(expectation.text) + "\"";
+    },
+ 
+// @ts-ignore
+    class: function(expectation) {
+// @ts-ignore
+      var escapedParts = expectation.parts.map(function(part) {
+// @ts-ignore
+        return Array.isArray(part)
+// @ts-ignore
+          ? classEscape(part[0]) + "-" + classEscape(part[1])
+// @ts-ignore
+          : classEscape(part);
+      });
+ 
+// @ts-ignore
+      return "[" + (expectation.inverted ? "^" : "") + escapedParts.join("") + "]";
+    },
+ 
+// @ts-ignore
+    any: function() {
+// @ts-ignore
+      return "any character";
+    },
+ 
+// @ts-ignore
+    end: function() {
+// @ts-ignore
+      return "end of input";
+    },
+ 
+// @ts-ignore
+    other: function(expectation) {
+// @ts-ignore
+      return expectation.description;
+    }
+  };
+ 
+// @ts-ignore
+  function hex(ch) {
+// @ts-ignore
+    return ch.charCodeAt(0).toString(16).toUpperCase();
+  }
+ 
+// @ts-ignore
+  function literalEscape(s) {
+// @ts-ignore
+    return s
+// @ts-ignore
+      .replace(/\\/g, "\\\\")
+// @ts-ignore
+      .replace(/"/g,  "\\\"")
+// @ts-ignore
+      .replace(/\0/g, "\\0")
+// @ts-ignore
+      .replace(/\t/g, "\\t")
+// @ts-ignore
+      .replace(/\n/g, "\\n")
+// @ts-ignore
+      .replace(/\r/g, "\\r")
+// @ts-ignore
+      .replace(/[\x00-\x0F]/g,          function(ch) { return "\\x0" + hex(ch); })
+// @ts-ignore
+      .replace(/[\x10-\x1F\x7F-\x9F]/g, function(ch) { return "\\x"  + hex(ch); });
+  }
+ 
+// @ts-ignore
+  function classEscape(s) {
+// @ts-ignore
+    return s
+// @ts-ignore
+      .replace(/\\/g, "\\\\")
+// @ts-ignore
+      .replace(/\]/g, "\\]")
+// @ts-ignore
+      .replace(/\^/g, "\\^")
+// @ts-ignore
+      .replace(/-/g,  "\\-")
+// @ts-ignore
+      .replace(/\0/g, "\\0")
+// @ts-ignore
+      .replace(/\t/g, "\\t")
+// @ts-ignore
+      .replace(/\n/g, "\\n")
+// @ts-ignore
+      .replace(/\r/g, "\\r")
+// @ts-ignore
+      .replace(/[\x00-\x0F]/g,          function(ch) { return "\\x0" + hex(ch); })
+// @ts-ignore
+      .replace(/[\x10-\x1F\x7F-\x9F]/g, function(ch) { return "\\x"  + hex(ch); });
+  }
+ 
+// @ts-ignore
+  function describeExpectation(expectation) {
+// @ts-ignore
+    return DESCRIBE_EXPECTATION_FNS[expectation.type](expectation);
+  }
+ 
+// @ts-ignore
+  function describeExpected(expected) {
+// @ts-ignore
+    var descriptions = expected.map(describeExpectation);
+// @ts-ignore
+    var i, j;
+ 
+// @ts-ignore
+    descriptions.sort();
+ 
+// @ts-ignore
+    if (descriptions.length > 0) {
+// @ts-ignore
+      for (i = 1, j = 1; i < descriptions.length; i++) {
+// @ts-ignore
+        if (descriptions[i - 1] !== descriptions[i]) {
+// @ts-ignore
+          descriptions[j] = descriptions[i];
+// @ts-ignore
+          j++;
+        }
+      }
+// @ts-ignore
+      descriptions.length = j;
+    }
+ 
+// @ts-ignore
+    switch (descriptions.length) {
+// @ts-ignore
+      case 1:
+// @ts-ignore
+        return descriptions[0];
+ 
+// @ts-ignore
+      case 2:
+// @ts-ignore
+        return descriptions[0] + " or " + descriptions[1];
+ 
+// @ts-ignore
+      default:
+// @ts-ignore
+        return descriptions.slice(0, -1).join(", ")
+// @ts-ignore
+          + ", or "
+// @ts-ignore
+          + descriptions[descriptions.length - 1];
+    }
+  }
+ 
+// @ts-ignore
+  function describeFound(found) {
+// @ts-ignore
+    return found ? "\"" + literalEscape(found) + "\"" : "end of input";
+  }
+ 
+// @ts-ignore
+  return "Expected " + describeExpected(expected) + " but " + describeFound(found) + " found.";
+};
+ 
+// @ts-ignore
+function peg$parse(input, options) {
+// @ts-ignore
+  options = options !== undefined ? options : {};
+ 
+// @ts-ignore
+  var peg$FAILED = {};
+// @ts-ignore
+  var peg$source = options.grammarSource;
+ 
+// @ts-ignore
+  var peg$startRuleFunctions = { VersionRange: peg$parseVersionRange, Or: peg$parseOr, And: peg$parseAnd, VersionRangeAtom: peg$parseVersionRangeAtom, Parens: peg$parseParens, Anchor: peg$parseAnchor, VersionSpec: peg$parseVersionSpec, Not: peg$parseNot, Any: peg$parseAny, None: peg$parseNone, CmpOp: peg$parseCmpOp, ExtendedVersion: peg$parseExtendedVersion, EmVer: peg$parseEmVer, Flavor: peg$parseFlavor, Lowercase: peg$parseLowercase, String: peg$parseString, Version: peg$parseVersion, PreRelease: peg$parsePreRelease, PreReleaseSegment: peg$parsePreReleaseSegment, VersionNumber: peg$parseVersionNumber, Digit: peg$parseDigit, _: peg$parse_ };
+// @ts-ignore
+  var peg$startRuleFunction = peg$parseVersionRange;
+ 
+// @ts-ignore
+  var peg$c0 = "||";
+  var peg$c1 = "&&";
+  var peg$c2 = "(";
+  var peg$c3 = ")";
+  var peg$c4 = ":";
+  var peg$c5 = "!";
+  var peg$c6 = "*";
+  var peg$c7 = ">=";
+  var peg$c8 = "<=";
+  var peg$c9 = ">";
+  var peg$c10 = "<";
+  var peg$c11 = "=";
+  var peg$c12 = "!=";
+  var peg$c13 = "^";
+  var peg$c14 = "~";
+  var peg$c15 = ".";
+  var peg$c16 = "#";
+  var peg$c17 = "-";
+ 
+  var peg$r0 = /^[a-z]/;
+  var peg$r1 = /^[a-zA-Z]/;
+  var peg$r2 = /^[0-9]/;
+  var peg$r3 = /^[ \t\n\r]/;
+ 
+  var peg$e0 = peg$literalExpectation("||", false);
+  var peg$e1 = peg$literalExpectation("&&", false);
+  var peg$e2 = peg$literalExpectation("(", false);
+  var peg$e3 = peg$literalExpectation(")", false);
+  var peg$e4 = peg$literalExpectation(":", false);
+  var peg$e5 = peg$literalExpectation("!", false);
+  var peg$e6 = peg$literalExpectation("*", false);
+  var peg$e7 = peg$literalExpectation(">=", false);
+  var peg$e8 = peg$literalExpectation("<=", false);
+  var peg$e9 = peg$literalExpectation(">", false);
+  var peg$e10 = peg$literalExpectation("<", false);
+  var peg$e11 = peg$literalExpectation("=", false);
+  var peg$e12 = peg$literalExpectation("!=", false);
+  var peg$e13 = peg$literalExpectation("^", false);
+  var peg$e14 = peg$literalExpectation("~", false);
+  var peg$e15 = peg$literalExpectation(".", false);
+  var peg$e16 = peg$literalExpectation("#", false);
+  var peg$e17 = peg$classExpectation([["a", "z"]], false, false);
+  var peg$e18 = peg$classExpectation([["a", "z"], ["A", "Z"]], false, false);
+  var peg$e19 = peg$literalExpectation("-", false);
+  var peg$e20 = peg$classExpectation([["0", "9"]], false, false);
+  var peg$e21 = peg$otherExpectation("whitespace");
+  var peg$e22 = peg$classExpectation([" ", "\t", "\n", "\r"], false, false);
+// @ts-ignore
+ 
+  var peg$f0 = function(expr) {// @ts-ignore
+ return { type: "Parens", expr } };// @ts-ignore
+ 
+  var peg$f1 = function(operator, version) {// @ts-ignore
+ return { type: "Anchor", operator, version } };// @ts-ignore
+ 
+  var peg$f2 = function(flavor, upstream, downstream) {// @ts-ignore
+ return { flavor: flavor || null, upstream, downstream: downstream ? downstream[1] : { number: [0], prerelease: [] } } };// @ts-ignore
+ 
+  var peg$f3 = function(value) {// @ts-ignore
+ return { type: "Not", value: value }};// @ts-ignore
+ 
+  var peg$f4 = function() {// @ts-ignore
+ return { type: "Any" } };// @ts-ignore
+ 
+  var peg$f5 = function() {// @ts-ignore
+ return { type: "None" } };// @ts-ignore
+ 
+  var peg$f6 = function() {// @ts-ignore
+ return ">="; };// @ts-ignore
+ 
+  var peg$f7 = function() {// @ts-ignore
+ return "<="; };// @ts-ignore
+ 
+  var peg$f8 = function() {// @ts-ignore
+ return ">"; };// @ts-ignore
+ 
+  var peg$f9 = function() {// @ts-ignore
+ return "<"; };// @ts-ignore
+ 
+  var peg$f10 = function() {// @ts-ignore
+ return "="; };// @ts-ignore
+ 
+  var peg$f11 = function() {// @ts-ignore
+ return "!="; };// @ts-ignore
+ 
+  var peg$f12 = function() {// @ts-ignore
+ return "^"; };// @ts-ignore
+ 
+  var peg$f13 = function() {// @ts-ignore
+ return "~"; };// @ts-ignore
+ 
+  var peg$f14 = function(flavor, upstream, downstream) {
+// @ts-ignore
+    return { flavor: flavor || null, upstream, downstream }
+  };// @ts-ignore
+ 
+  var peg$f15 = function(major, minor, patch) {
+// @ts-ignore
+    return {
+// @ts-ignore
+      flavor: null,
+// @ts-ignore
+      upstream: {
+// @ts-ignore
+        number: [major, minor, patch],
+// @ts-ignore
+        prerelease: [],
+      },
+// @ts-ignore
+      downstream: {
+// @ts-ignore
+        number: [revision || 0],
+// @ts-ignore
+        prerelease: [],
+      },
+    }
+  };// @ts-ignore
+ 
+  var peg$f16 = function(flavor) {// @ts-ignore
+ return flavor };// @ts-ignore
+ 
+  var peg$f17 = function() {// @ts-ignore
+ return text() };// @ts-ignore
+ 
+  var peg$f18 = function() {// @ts-ignore
+ return text(); };// @ts-ignore
+ 
+  var peg$f19 = function(number, prerelease) {
+// @ts-ignore
+    return { 
+// @ts-ignore
+      number,
+// @ts-ignore
+      prerelease: prerelease || []
+    };
+  };// @ts-ignore
+ 
+  var peg$f20 = function(first, rest) {
+// @ts-ignore
+    return [first].concat(rest.map(r => r[1]));
+  };// @ts-ignore
+ 
+  var peg$f21 = function(segment) {
+// @ts-ignore
+    return segment;
+  };// @ts-ignore
+ 
+  var peg$f22 = function(first, rest) { 
+// @ts-ignore
+    return [first].concat(rest.map(r => r[1]));
+  };// @ts-ignore
+ 
+  var peg$f23 = function() {// @ts-ignore
+ return parseInt(text(), 10); };
+// @ts-ignore
+  var peg$currPos = 0;
+// @ts-ignore
+  var peg$savedPos = 0;
+// @ts-ignore
+  var peg$posDetailsCache = [{ line: 1, column: 1 }];
+// @ts-ignore
+  var peg$maxFailPos = 0;
+// @ts-ignore
+  var peg$maxFailExpected = [];
+// @ts-ignore
+  var peg$silentFails = 0;
+ 
+// @ts-ignore
+  var peg$result;
+ 
+// @ts-ignore
+  if ("startRule" in options) {
+// @ts-ignore
+    Iif (!(options.startRule in peg$startRuleFunctions)) {
+// @ts-ignore
+      throw new Error("Can't start parsing from rule \"" + options.startRule + "\".");
+    }
+ 
+// @ts-ignore
+    peg$startRuleFunction = peg$startRuleFunctions[options.startRule];
+  }
+ 
+// @ts-ignore
+  function text() {
+// @ts-ignore
+    return input.substring(peg$savedPos, peg$currPos);
+  }
+ 
+// @ts-ignore
+  function offset() {
+// @ts-ignore
+    return peg$savedPos;
+  }
+ 
+// @ts-ignore
+  function range() {
+// @ts-ignore
+    return {
+// @ts-ignore
+      source: peg$source,
+// @ts-ignore
+      start: peg$savedPos,
+// @ts-ignore
+      end: peg$currPos
+    };
+  }
+ 
+// @ts-ignore
+  function location() {
+// @ts-ignore
+    return peg$computeLocation(peg$savedPos, peg$currPos);
+  }
+ 
+// @ts-ignore
+  function expected(description, location) {
+// @ts-ignore
+    location = location !== undefined
+// @ts-ignore
+      ? location
+// @ts-ignore
+      : peg$computeLocation(peg$savedPos, peg$currPos);
+ 
+// @ts-ignore
+    throw peg$buildStructuredError(
+// @ts-ignore
+      [peg$otherExpectation(description)],
+// @ts-ignore
+      input.substring(peg$savedPos, peg$currPos),
+// @ts-ignore
+      location
+    );
+  }
+ 
+// @ts-ignore
+  function error(message, location) {
+// @ts-ignore
+    location = location !== undefined
+// @ts-ignore
+      ? location
+// @ts-ignore
+      : peg$computeLocation(peg$savedPos, peg$currPos);
+ 
+// @ts-ignore
+    throw peg$buildSimpleError(message, location);
+  }
+ 
+// @ts-ignore
+  function peg$literalExpectation(text, ignoreCase) {
+// @ts-ignore
+    return { type: "literal", text: text, ignoreCase: ignoreCase };
+  }
+ 
+// @ts-ignore
+  function peg$classExpectation(parts, inverted, ignoreCase) {
+// @ts-ignore
+    return { type: "class", parts: parts, inverted: inverted, ignoreCase: ignoreCase };
+  }
+ 
+// @ts-ignore
+  function peg$anyExpectation() {
+// @ts-ignore
+    return { type: "any" };
+  }
+ 
+// @ts-ignore
+  function peg$endExpectation() {
+// @ts-ignore
+    return { type: "end" };
+  }
+ 
+// @ts-ignore
+  function peg$otherExpectation(description) {
+// @ts-ignore
+    return { type: "other", description: description };
+  }
+ 
+// @ts-ignore
+  function peg$computePosDetails(pos) {
+// @ts-ignore
+    var details = peg$posDetailsCache[pos];
+// @ts-ignore
+    var p;
+ 
+// @ts-ignore
+    if (details) {
+// @ts-ignore
+      return details;
+// @ts-ignore
+    } else {
+// @ts-ignore
+      p = pos - 1;
+// @ts-ignore
+      while (!peg$posDetailsCache[p]) {
+// @ts-ignore
+        p--;
+      }
+ 
+// @ts-ignore
+      details = peg$posDetailsCache[p];
+// @ts-ignore
+      details = {
+// @ts-ignore
+        line: details.line,
+// @ts-ignore
+        column: details.column
+      };
+ 
+// @ts-ignore
+      while (p < pos) {
+// @ts-ignore
+        Iif (input.charCodeAt(p) === 10) {
+// @ts-ignore
+          details.line++;
+// @ts-ignore
+          details.column = 1;
+// @ts-ignore
+        } else {
+// @ts-ignore
+          details.column++;
+        }
+ 
+// @ts-ignore
+        p++;
+      }
+ 
+// @ts-ignore
+      peg$posDetailsCache[pos] = details;
+ 
+// @ts-ignore
+      return details;
+    }
+  }
+ 
+// @ts-ignore
+  function peg$computeLocation(startPos, endPos, offset) {
+// @ts-ignore
+    var startPosDetails = peg$computePosDetails(startPos);
+// @ts-ignore
+    var endPosDetails = peg$computePosDetails(endPos);
+ 
+// @ts-ignore
+    var res = {
+// @ts-ignore
+      source: peg$source,
+// @ts-ignore
+      start: {
+// @ts-ignore
+        offset: startPos,
+// @ts-ignore
+        line: startPosDetails.line,
+// @ts-ignore
+        column: startPosDetails.column
+      },
+// @ts-ignore
+      end: {
+// @ts-ignore
+        offset: endPos,
+// @ts-ignore
+        line: endPosDetails.line,
+// @ts-ignore
+        column: endPosDetails.column
+      }
+    };
+// @ts-ignore
+    Iif (offset && peg$source && (typeof peg$source.offset === "function")) {
+// @ts-ignore
+      res.start = peg$source.offset(res.start);
+// @ts-ignore
+      res.end = peg$source.offset(res.end);
+    }
+// @ts-ignore
+    return res;
+  }
+ 
+// @ts-ignore
+  function peg$fail(expected) {
+// @ts-ignore
+    if (peg$currPos < peg$maxFailPos) { return; }
+ 
+// @ts-ignore
+    if (peg$currPos > peg$maxFailPos) {
+// @ts-ignore
+      peg$maxFailPos = peg$currPos;
+// @ts-ignore
+      peg$maxFailExpected = [];
+    }
+ 
+// @ts-ignore
+    peg$maxFailExpected.push(expected);
+  }
+ 
+// @ts-ignore
+  function peg$buildSimpleError(message, location) {
+// @ts-ignore
+    return new peg$SyntaxError(message, null, null, location);
+  }
+ 
+// @ts-ignore
+  function peg$buildStructuredError(expected, found, location) {
+// @ts-ignore
+    return new peg$SyntaxError(
+// @ts-ignore
+      peg$SyntaxError.buildMessage(expected, found),
+// @ts-ignore
+      expected,
+// @ts-ignore
+      found,
+// @ts-ignore
+      location
+    );
+  }
+ 
+// @ts-ignore
+  function // @ts-ignore
+peg$parseVersionRange() {
+// @ts-ignore
+    var s0, s1, s2, s3, s4, s5, s6, s7;
+ 
+// @ts-ignore
+    s0 = peg$currPos;
+// @ts-ignore
+    s1 = peg$parseVersionRangeAtom();
+// @ts-ignore
+    if (s1 !== peg$FAILED) {
+// @ts-ignore
+      s2 = [];
+// @ts-ignore
+      s3 = peg$currPos;
+// @ts-ignore
+      s4 = peg$parse_();
+// @ts-ignore
+      s5 = peg$currPos;
+// @ts-ignore
+      s6 = peg$parseOr();
+// @ts-ignore
+      if (s6 === peg$FAILED) {
+// @ts-ignore
+        s6 = peg$parseAnd();
+      }
+// @ts-ignore
+      if (s6 !== peg$FAILED) {
+// @ts-ignore
+        s7 = peg$parse_();
+// @ts-ignore
+        s6 = [s6, s7];
+// @ts-ignore
+        s5 = s6;
+// @ts-ignore
+      } else {
+// @ts-ignore
+        peg$currPos = s5;
+// @ts-ignore
+        s5 = peg$FAILED;
+      }
+// @ts-ignore
+      if (s5 === peg$FAILED) {
+// @ts-ignore
+        s5 = null;
+      }
+// @ts-ignore
+      s6 = peg$parseVersionRangeAtom();
+// @ts-ignore
+      if (s6 !== peg$FAILED) {
+// @ts-ignore
+        s4 = [s4, s5, s6];
+// @ts-ignore
+        s3 = s4;
+// @ts-ignore
+      } else {
+// @ts-ignore
+        peg$currPos = s3;
+// @ts-ignore
+        s3 = peg$FAILED;
+      }
+// @ts-ignore
+      while (s3 !== peg$FAILED) {
+// @ts-ignore
+        s2.push(s3);
+// @ts-ignore
+        s3 = peg$currPos;
+// @ts-ignore
+        s4 = peg$parse_();
+// @ts-ignore
+        s5 = peg$currPos;
+// @ts-ignore
+        s6 = peg$parseOr();
+// @ts-ignore
+        if (s6 === peg$FAILED) {
+// @ts-ignore
+          s6 = peg$parseAnd();
+        }
+// @ts-ignore
+        if (s6 !== peg$FAILED) {
+// @ts-ignore
+          s7 = peg$parse_();
+// @ts-ignore
+          s6 = [s6, s7];
+// @ts-ignore
+          s5 = s6;
+// @ts-ignore
+        } else {
+// @ts-ignore
+          peg$currPos = s5;
+// @ts-ignore
+          s5 = peg$FAILED;
+        }
+// @ts-ignore
+        if (s5 === peg$FAILED) {
+// @ts-ignore
+          s5 = null;
+        }
+// @ts-ignore
+        s6 = peg$parseVersionRangeAtom();
+// @ts-ignore
+        if (s6 !== peg$FAILED) {
+// @ts-ignore
+          s4 = [s4, s5, s6];
+// @ts-ignore
+          s3 = s4;
+// @ts-ignore
+        } else {
+// @ts-ignore
+          peg$currPos = s3;
+// @ts-ignore
+          s3 = peg$FAILED;
+        }
+      }
+// @ts-ignore
+      s1 = [s1, s2];
+// @ts-ignore
+      s0 = s1;
+// @ts-ignore
+    } else E{
+// @ts-ignore
+      peg$currPos = s0;
+// @ts-ignore
+      s0 = peg$FAILED;
+    }
+ 
+// @ts-ignore
+    return s0;
+  }
+ 
+// @ts-ignore
+  function // @ts-ignore
+peg$parseOr() {
+// @ts-ignore
+    var s0;
+ 
+// @ts-ignore
+    if (input.substr(peg$currPos, 2) === peg$c0) {
+// @ts-ignore
+      s0 = peg$c0;
+// @ts-ignore
+      peg$currPos += 2;
+// @ts-ignore
+    } else {
+// @ts-ignore
+      s0 = peg$FAILED;
+// @ts-ignore
+      if (peg$silentFails === 0) { peg$fail(peg$e0); }
+    }
+ 
+// @ts-ignore
+    return s0;
+  }
+ 
+// @ts-ignore
+  function // @ts-ignore
+peg$parseAnd() {
+// @ts-ignore
+    var s0;
+ 
+// @ts-ignore
+    if (input.substr(peg$currPos, 2) === peg$c1) {
+// @ts-ignore
+      s0 = peg$c1;
+// @ts-ignore
+      peg$currPos += 2;
+// @ts-ignore
+    } else {
+// @ts-ignore
+      s0 = peg$FAILED;
+// @ts-ignore
+      if (peg$silentFails === 0) { peg$fail(peg$e1); }
+    }
+ 
+// @ts-ignore
+    return s0;
+  }
+ 
+// @ts-ignore
+  function // @ts-ignore
+peg$parseVersionRangeAtom() {
+// @ts-ignore
+    var s0;
+ 
+// @ts-ignore
+    s0 = peg$parseParens();
+// @ts-ignore
+    if (s0 === peg$FAILED) {
+// @ts-ignore
+      s0 = peg$parseAnchor();
+// @ts-ignore
+      if (s0 === peg$FAILED) {
+// @ts-ignore
+        s0 = peg$parseNot();
+// @ts-ignore
+        if (s0 === peg$FAILED) {
+// @ts-ignore
+          s0 = peg$parseAny();
+// @ts-ignore
+          if (s0 === peg$FAILED) {
+// @ts-ignore
+            s0 = peg$parseNone();
+          }
+        }
+      }
+    }
+ 
+// @ts-ignore
+    return s0;
+  }
+ 
+// @ts-ignore
+  function // @ts-ignore
+peg$parseParens() {
+// @ts-ignore
+    var s0, s1, s2, s3, s4, s5;
+ 
+// @ts-ignore
+    s0 = peg$currPos;
+// @ts-ignore
+    Iif (input.charCodeAt(peg$currPos) === 40) {
+// @ts-ignore
+      s1 = peg$c2;
+// @ts-ignore
+      peg$currPos++;
+// @ts-ignore
+    } else {
+// @ts-ignore
+      s1 = peg$FAILED;
+// @ts-ignore
+      if (peg$silentFails === 0) { peg$fail(peg$e2); }
+    }
+// @ts-ignore
+    Iif (s1 !== peg$FAILED) {
+// @ts-ignore
+      s2 = peg$parse_();
+// @ts-ignore
+      s3 = peg$parseVersionRange();
+// @ts-ignore
+      if (s3 !== peg$FAILED) {
+// @ts-ignore
+        s4 = peg$parse_();
+// @ts-ignore
+        if (input.charCodeAt(peg$currPos) === 41) {
+// @ts-ignore
+          s5 = peg$c3;
+// @ts-ignore
+          peg$currPos++;
+// @ts-ignore
+        } else {
+// @ts-ignore
+          s5 = peg$FAILED;
+// @ts-ignore
+          Iif (peg$silentFails === 0) { peg$fail(peg$e3); }
+        }
+// @ts-ignore
+        if (s5 !== peg$FAILED) {
+// @ts-ignore
+          peg$savedPos = s0;
+// @ts-ignore
+          s0 = peg$f0(s3);
+// @ts-ignore
+        } else {
+// @ts-ignore
+          peg$currPos = s0;
+// @ts-ignore
+          s0 = peg$FAILED;
+        }
+// @ts-ignore
+      } else {
+// @ts-ignore
+        peg$currPos = s0;
+// @ts-ignore
+        s0 = peg$FAILED;
+      }
+// @ts-ignore
+    } else {
+// @ts-ignore
+      peg$currPos = s0;
+// @ts-ignore
+      s0 = peg$FAILED;
+    }
+ 
+// @ts-ignore
+    return s0;
+  }
+ 
+// @ts-ignore
+  function // @ts-ignore
+peg$parseAnchor() {
+// @ts-ignore
+    var s0, s1, s2, s3;
+ 
+// @ts-ignore
+    s0 = peg$currPos;
+// @ts-ignore
+    s1 = peg$parseCmpOp();
+// @ts-ignore
+    if (s1 === peg$FAILED) {
+// @ts-ignore
+      s1 = null;
+    }
+// @ts-ignore
+    s2 = peg$parse_();
+// @ts-ignore
+    s3 = peg$parseVersionSpec();
+// @ts-ignore
+    if (s3 !== peg$FAILED) {
+// @ts-ignore
+      peg$savedPos = s0;
+// @ts-ignore
+      s0 = peg$f1(s1, s3);
+// @ts-ignore
+    } else {
+// @ts-ignore
+      peg$currPos = s0;
+// @ts-ignore
+      s0 = peg$FAILED;
+    }
+ 
+// @ts-ignore
+    return s0;
+  }
+ 
+// @ts-ignore
+  function // @ts-ignore
+peg$parseVersionSpec() {
+// @ts-ignore
+    var s0, s1, s2, s3, s4, s5;
+ 
+// @ts-ignore
+    s0 = peg$currPos;
+// @ts-ignore
+    s1 = peg$parseFlavor();
+// @ts-ignore
+    if (s1 === peg$FAILED) {
+// @ts-ignore
+      s1 = null;
+    }
+// @ts-ignore
+    s2 = peg$parseVersion();
+// @ts-ignore
+    if (s2 !== peg$FAILED) {
+// @ts-ignore
+      s3 = peg$currPos;
+// @ts-ignore
+      if (input.charCodeAt(peg$currPos) === 58) {
+// @ts-ignore
+        s4 = peg$c4;
+// @ts-ignore
+        peg$currPos++;
+// @ts-ignore
+      } else {
+// @ts-ignore
+        s4 = peg$FAILED;
+// @ts-ignore
+        if (peg$silentFails === 0) { peg$fail(peg$e4); }
+      }
+// @ts-ignore
+      if (s4 !== peg$FAILED) {
+// @ts-ignore
+        s5 = peg$parseVersion();
+// @ts-ignore
+        if (s5 !== peg$FAILED) {
+// @ts-ignore
+          s4 = [s4, s5];
+// @ts-ignore
+          s3 = s4;
+// @ts-ignore
+        } else E{
+// @ts-ignore
+          peg$currPos = s3;
+// @ts-ignore
+          s3 = peg$FAILED;
+        }
+// @ts-ignore
+      } else {
+// @ts-ignore
+        peg$currPos = s3;
+// @ts-ignore
+        s3 = peg$FAILED;
+      }
+// @ts-ignore
+      if (s3 === peg$FAILED) {
+// @ts-ignore
+        s3 = null;
+      }
+// @ts-ignore
+      peg$savedPos = s0;
+// @ts-ignore
+      s0 = peg$f2(s1, s2, s3);
+// @ts-ignore
+    } else {
+// @ts-ignore
+      peg$currPos = s0;
+// @ts-ignore
+      s0 = peg$FAILED;
+    }
+ 
+// @ts-ignore
+    return s0;
+  }
+ 
+// @ts-ignore
+  function // @ts-ignore
+peg$parseNot() {
+// @ts-ignore
+    var s0, s1, s2, s3;
+ 
+// @ts-ignore
+    s0 = peg$currPos;
+// @ts-ignore
+    if (input.charCodeAt(peg$currPos) === 33) {
+// @ts-ignore
+      s1 = peg$c5;
+// @ts-ignore
+      peg$currPos++;
+// @ts-ignore
+    } else {
+// @ts-ignore
+      s1 = peg$FAILED;
+// @ts-ignore
+      if (peg$silentFails === 0) { peg$fail(peg$e5); }
+    }
+// @ts-ignore
+    if (s1 !== peg$FAILED) {
+// @ts-ignore
+      s2 = peg$parse_();
+// @ts-ignore
+      s3 = peg$parseVersionRangeAtom();
+// @ts-ignore
+      if (s3 !== peg$FAILED) {
+// @ts-ignore
+        peg$savedPos = s0;
+// @ts-ignore
+        s0 = peg$f3(s3);
+// @ts-ignore
+      } else E{
+// @ts-ignore
+        peg$currPos = s0;
+// @ts-ignore
+        s0 = peg$FAILED;
+      }
+// @ts-ignore
+    } else {
+// @ts-ignore
+      peg$currPos = s0;
+// @ts-ignore
+      s0 = peg$FAILED;
+    }
+ 
+// @ts-ignore
+    return s0;
+  }
+ 
+// @ts-ignore
+  function // @ts-ignore
+peg$parseAny() {
+// @ts-ignore
+    var s0, s1;
+ 
+// @ts-ignore
+    s0 = peg$currPos;
+// @ts-ignore
+    if (input.charCodeAt(peg$currPos) === 42) {
+// @ts-ignore
+      s1 = peg$c6;
+// @ts-ignore
+      peg$currPos++;
+// @ts-ignore
+    } else {
+// @ts-ignore
+      s1 = peg$FAILED;
+// @ts-ignore
+      if (peg$silentFails === 0) { peg$fail(peg$e6); }
+    }
+// @ts-ignore
+    if (s1 !== peg$FAILED) {
+// @ts-ignore
+      peg$savedPos = s0;
+// @ts-ignore
+      s1 = peg$f4();
+    }
+// @ts-ignore
+    s0 = s1;
+ 
+// @ts-ignore
+    return s0;
+  }
+ 
+// @ts-ignore
+  function // @ts-ignore
+peg$parseNone() {
+// @ts-ignore
+    var s0, s1;
+ 
+// @ts-ignore
+    s0 = peg$currPos;
+// @ts-ignore
+    Iif (input.charCodeAt(peg$currPos) === 33) {
+// @ts-ignore
+      s1 = peg$c5;
+// @ts-ignore
+      peg$currPos++;
+// @ts-ignore
+    } else {
+// @ts-ignore
+      s1 = peg$FAILED;
+// @ts-ignore
+      if (peg$silentFails === 0) { peg$fail(peg$e5); }
+    }
+// @ts-ignore
+    Iif (s1 !== peg$FAILED) {
+// @ts-ignore
+      peg$savedPos = s0;
+// @ts-ignore
+      s1 = peg$f5();
+    }
+// @ts-ignore
+    s0 = s1;
+ 
+// @ts-ignore
+    return s0;
+  }
+ 
+// @ts-ignore
+  function // @ts-ignore
+peg$parseCmpOp() {
+// @ts-ignore
+    var s0, s1;
+ 
+// @ts-ignore
+    s0 = peg$currPos;
+// @ts-ignore
+    if (input.substr(peg$currPos, 2) === peg$c7) {
+// @ts-ignore
+      s1 = peg$c7;
+// @ts-ignore
+      peg$currPos += 2;
+// @ts-ignore
+    } else {
+// @ts-ignore
+      s1 = peg$FAILED;
+// @ts-ignore
+      if (peg$silentFails === 0) { peg$fail(peg$e7); }
+    }
+// @ts-ignore
+    if (s1 !== peg$FAILED) {
+// @ts-ignore
+      peg$savedPos = s0;
+// @ts-ignore
+      s1 = peg$f6();
+    }
+// @ts-ignore
+    s0 = s1;
+// @ts-ignore
+    if (s0 === peg$FAILED) {
+// @ts-ignore
+      s0 = peg$currPos;
+// @ts-ignore
+      if (input.substr(peg$currPos, 2) === peg$c8) {
+// @ts-ignore
+        s1 = peg$c8;
+// @ts-ignore
+        peg$currPos += 2;
+// @ts-ignore
+      } else {
+// @ts-ignore
+        s1 = peg$FAILED;
+// @ts-ignore
+        if (peg$silentFails === 0) { peg$fail(peg$e8); }
+      }
+// @ts-ignore
+      if (s1 !== peg$FAILED) {
+// @ts-ignore
+        peg$savedPos = s0;
+// @ts-ignore
+        s1 = peg$f7();
+      }
+// @ts-ignore
+      s0 = s1;
+// @ts-ignore
+      if (s0 === peg$FAILED) {
+// @ts-ignore
+        s0 = peg$currPos;
+// @ts-ignore
+        if (input.charCodeAt(peg$currPos) === 62) {
+// @ts-ignore
+          s1 = peg$c9;
+// @ts-ignore
+          peg$currPos++;
+// @ts-ignore
+        } else {
+// @ts-ignore
+          s1 = peg$FAILED;
+// @ts-ignore
+          if (peg$silentFails === 0) { peg$fail(peg$e9); }
+        }
+// @ts-ignore
+        if (s1 !== peg$FAILED) {
+// @ts-ignore
+          peg$savedPos = s0;
+// @ts-ignore
+          s1 = peg$f8();
+        }
+// @ts-ignore
+        s0 = s1;
+// @ts-ignore
+        if (s0 === peg$FAILED) {
+// @ts-ignore
+          s0 = peg$currPos;
+// @ts-ignore
+          if (input.charCodeAt(peg$currPos) === 60) {
+// @ts-ignore
+            s1 = peg$c10;
+// @ts-ignore
+            peg$currPos++;
+// @ts-ignore
+          } else {
+// @ts-ignore
+            s1 = peg$FAILED;
+// @ts-ignore
+            if (peg$silentFails === 0) { peg$fail(peg$e10); }
+          }
+// @ts-ignore
+          if (s1 !== peg$FAILED) {
+// @ts-ignore
+            peg$savedPos = s0;
+// @ts-ignore
+            s1 = peg$f9();
+          }
+// @ts-ignore
+          s0 = s1;
+// @ts-ignore
+          if (s0 === peg$FAILED) {
+// @ts-ignore
+            s0 = peg$currPos;
+// @ts-ignore
+            if (input.charCodeAt(peg$currPos) === 61) {
+// @ts-ignore
+              s1 = peg$c11;
+// @ts-ignore
+              peg$currPos++;
+// @ts-ignore
+            } else {
+// @ts-ignore
+              s1 = peg$FAILED;
+// @ts-ignore
+              if (peg$silentFails === 0) { peg$fail(peg$e11); }
+            }
+// @ts-ignore
+            if (s1 !== peg$FAILED) {
+// @ts-ignore
+              peg$savedPos = s0;
+// @ts-ignore
+              s1 = peg$f10();
+            }
+// @ts-ignore
+            s0 = s1;
+// @ts-ignore
+            if (s0 === peg$FAILED) {
+// @ts-ignore
+              s0 = peg$currPos;
+// @ts-ignore
+              Iif (input.substr(peg$currPos, 2) === peg$c12) {
+// @ts-ignore
+                s1 = peg$c12;
+// @ts-ignore
+                peg$currPos += 2;
+// @ts-ignore
+              } else {
+// @ts-ignore
+                s1 = peg$FAILED;
+// @ts-ignore
+                if (peg$silentFails === 0) { peg$fail(peg$e12); }
+              }
+// @ts-ignore
+              Iif (s1 !== peg$FAILED) {
+// @ts-ignore
+                peg$savedPos = s0;
+// @ts-ignore
+                s1 = peg$f11();
+              }
+// @ts-ignore
+              s0 = s1;
+// @ts-ignore
+              if (s0 === peg$FAILED) {
+// @ts-ignore
+                s0 = peg$currPos;
+// @ts-ignore
+                Iif (input.charCodeAt(peg$currPos) === 94) {
+// @ts-ignore
+                  s1 = peg$c13;
+// @ts-ignore
+                  peg$currPos++;
+// @ts-ignore
+                } else {
+// @ts-ignore
+                  s1 = peg$FAILED;
+// @ts-ignore
+                  if (peg$silentFails === 0) { peg$fail(peg$e13); }
+                }
+// @ts-ignore
+                Iif (s1 !== peg$FAILED) {
+// @ts-ignore
+                  peg$savedPos = s0;
+// @ts-ignore
+                  s1 = peg$f12();
+                }
+// @ts-ignore
+                s0 = s1;
+// @ts-ignore
+                if (s0 === peg$FAILED) {
+// @ts-ignore
+                  s0 = peg$currPos;
+// @ts-ignore
+                  if (input.charCodeAt(peg$currPos) === 126) {
+// @ts-ignore
+                    s1 = peg$c14;
+// @ts-ignore
+                    peg$currPos++;
+// @ts-ignore
+                  } else {
+// @ts-ignore
+                    s1 = peg$FAILED;
+// @ts-ignore
+                    if (peg$silentFails === 0) { peg$fail(peg$e14); }
+                  }
+// @ts-ignore
+                  if (s1 !== peg$FAILED) {
+// @ts-ignore
+                    peg$savedPos = s0;
+// @ts-ignore
+                    s1 = peg$f13();
+                  }
+// @ts-ignore
+                  s0 = s1;
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+ 
+// @ts-ignore
+    return s0;
+  }
+ 
+// @ts-ignore
+  function // @ts-ignore
+peg$parseExtendedVersion() {
+// @ts-ignore
+    var s0, s1, s2, s3, s4;
+ 
+// @ts-ignore
+    s0 = peg$currPos;
+// @ts-ignore
+    s1 = peg$parseFlavor();
+// @ts-ignore
+    if (s1 === peg$FAILED) {
+// @ts-ignore
+      s1 = null;
+    }
+// @ts-ignore
+    s2 = peg$parseVersion();
+// @ts-ignore
+    if (s2 !== peg$FAILED) {
+// @ts-ignore
+      if (input.charCodeAt(peg$currPos) === 58) {
+// @ts-ignore
+        s3 = peg$c4;
+// @ts-ignore
+        peg$currPos++;
+// @ts-ignore
+      } else {
+// @ts-ignore
+        s3 = peg$FAILED;
+// @ts-ignore
+        if (peg$silentFails === 0) { peg$fail(peg$e4); }
+      }
+// @ts-ignore
+      if (s3 !== peg$FAILED) {
+// @ts-ignore
+        s4 = peg$parseVersion();
+// @ts-ignore
+        if (s4 !== peg$FAILED) {
+// @ts-ignore
+          peg$savedPos = s0;
+// @ts-ignore
+          s0 = peg$f14(s1, s2, s4);
+// @ts-ignore
+        } else E{
+// @ts-ignore
+          peg$currPos = s0;
+// @ts-ignore
+          s0 = peg$FAILED;
+        }
+// @ts-ignore
+      } else {
+// @ts-ignore
+        peg$currPos = s0;
+// @ts-ignore
+        s0 = peg$FAILED;
+      }
+// @ts-ignore
+    } else {
+// @ts-ignore
+      peg$currPos = s0;
+// @ts-ignore
+      s0 = peg$FAILED;
+    }
+ 
+// @ts-ignore
+    return s0;
+  }
+ 
+// @ts-ignore
+  function // @ts-ignore
+peg$parseEmVer() {
+// @ts-ignore
+    var s0, s1, s2, s3, s4, s5, s6, s7, s8;
+ 
+// @ts-ignore
+    s0 = peg$currPos;
+// @ts-ignore
+    s1 = peg$parseDigit();
+// @ts-ignore
+    if (s1 !== peg$FAILED) {
+// @ts-ignore
+      if (input.charCodeAt(peg$currPos) === 46) {
+// @ts-ignore
+        s2 = peg$c15;
+// @ts-ignore
+        peg$currPos++;
+// @ts-ignore
+      } else {
+// @ts-ignore
+        s2 = peg$FAILED;
+// @ts-ignore
+        Iif (peg$silentFails === 0) { peg$fail(peg$e15); }
+      }
+// @ts-ignore
+      if (s2 !== peg$FAILED) {
+// @ts-ignore
+        s3 = peg$parseDigit();
+// @ts-ignore
+        if (s3 !== peg$FAILED) {
+// @ts-ignore
+          if (input.charCodeAt(peg$currPos) === 46) {
+// @ts-ignore
+            s4 = peg$c15;
+// @ts-ignore
+            peg$currPos++;
+// @ts-ignore
+          } else {
+// @ts-ignore
+            s4 = peg$FAILED;
+// @ts-ignore
+            Iif (peg$silentFails === 0) { peg$fail(peg$e15); }
+          }
+// @ts-ignore
+          if (s4 !== peg$FAILED) {
+// @ts-ignore
+            s5 = peg$parseDigit();
+// @ts-ignore
+            if (s5 !== peg$FAILED) {
+// @ts-ignore
+              s6 = peg$currPos;
+// @ts-ignore
+              if (input.charCodeAt(peg$currPos) === 46) {
+// @ts-ignore
+                s7 = peg$c15;
+// @ts-ignore
+                peg$currPos++;
+// @ts-ignore
+              } else {
+// @ts-ignore
+                s7 = peg$FAILED;
+// @ts-ignore
+                Iif (peg$silentFails === 0) { peg$fail(peg$e15); }
+              }
+// @ts-ignore
+              if (s7 !== peg$FAILED) {
+// @ts-ignore
+                s8 = peg$parseDigit();
+// @ts-ignore
+                if (s8 !== peg$FAILED) {
+// @ts-ignore
+                  s7 = [s7, s8];
+// @ts-ignore
+                  s6 = s7;
+// @ts-ignore
+                } else {
+// @ts-ignore
+                  peg$currPos = s6;
+// @ts-ignore
+                  s6 = peg$FAILED;
+                }
+// @ts-ignore
+              } else {
+// @ts-ignore
+                peg$currPos = s6;
+// @ts-ignore
+                s6 = peg$FAILED;
+              }
+// @ts-ignore
+              Iif (s6 === peg$FAILED) {
+// @ts-ignore
+                s6 = null;
+              }
+// @ts-ignore
+              peg$savedPos = s0;
+// @ts-ignore
+              s0 = peg$f15(s1, s3, s5);
+// @ts-ignore
+            } else {
+// @ts-ignore
+              peg$currPos = s0;
+// @ts-ignore
+              s0 = peg$FAILED;
+            }
+// @ts-ignore
+          } else {
+// @ts-ignore
+            peg$currPos = s0;
+// @ts-ignore
+            s0 = peg$FAILED;
+          }
+// @ts-ignore
+        } else {
+// @ts-ignore
+          peg$currPos = s0;
+// @ts-ignore
+          s0 = peg$FAILED;
+        }
+// @ts-ignore
+      } else {
+// @ts-ignore
+        peg$currPos = s0;
+// @ts-ignore
+        s0 = peg$FAILED;
+      }
+// @ts-ignore
+    } else {
+// @ts-ignore
+      peg$currPos = s0;
+// @ts-ignore
+      s0 = peg$FAILED;
+    }
+ 
+// @ts-ignore
+    return s0;
+  }
+ 
+// @ts-ignore
+  function // @ts-ignore
+peg$parseFlavor() {
+// @ts-ignore
+    var s0, s1, s2, s3;
+ 
+// @ts-ignore
+    s0 = peg$currPos;
+// @ts-ignore
+    Iif (input.charCodeAt(peg$currPos) === 35) {
+// @ts-ignore
+      s1 = peg$c16;
+// @ts-ignore
+      peg$currPos++;
+// @ts-ignore
+    } else {
+// @ts-ignore
+      s1 = peg$FAILED;
+// @ts-ignore
+      if (peg$silentFails === 0) { peg$fail(peg$e16); }
+    }
+// @ts-ignore
+    Iif (s1 !== peg$FAILED) {
+// @ts-ignore
+      s2 = peg$parseLowercase();
+// @ts-ignore
+      if (s2 !== peg$FAILED) {
+// @ts-ignore
+        if (input.charCodeAt(peg$currPos) === 58) {
+// @ts-ignore
+          s3 = peg$c4;
+// @ts-ignore
+          peg$currPos++;
+// @ts-ignore
+        } else {
+// @ts-ignore
+          s3 = peg$FAILED;
+// @ts-ignore
+          Iif (peg$silentFails === 0) { peg$fail(peg$e4); }
+        }
+// @ts-ignore
+        if (s3 !== peg$FAILED) {
+// @ts-ignore
+          peg$savedPos = s0;
+// @ts-ignore
+          s0 = peg$f16(s2);
+// @ts-ignore
+        } else {
+// @ts-ignore
+          peg$currPos = s0;
+// @ts-ignore
+          s0 = peg$FAILED;
+        }
+// @ts-ignore
+      } else {
+// @ts-ignore
+        peg$currPos = s0;
+// @ts-ignore
+        s0 = peg$FAILED;
+      }
+// @ts-ignore
+    } else {
+// @ts-ignore
+      peg$currPos = s0;
+// @ts-ignore
+      s0 = peg$FAILED;
+    }
+ 
+// @ts-ignore
+    return s0;
+  }
+ 
+// @ts-ignore
+  function // @ts-ignore
+peg$parseLowercase() {
+// @ts-ignore
+    var s0, s1, s2;
+ 
+// @ts-ignore
+    s0 = peg$currPos;
+// @ts-ignore
+    s1 = [];
+// @ts-ignore
+    if (peg$r0.test(input.charAt(peg$currPos))) {
+// @ts-ignore
+      s2 = input.charAt(peg$currPos);
+// @ts-ignore
+      peg$currPos++;
+// @ts-ignore
+    } else {
+// @ts-ignore
+      s2 = peg$FAILED;
+// @ts-ignore
+      Iif (peg$silentFails === 0) { peg$fail(peg$e17); }
+    }
+// @ts-ignore
+    if (s2 !== peg$FAILED) {
+// @ts-ignore
+      while (s2 !== peg$FAILED) {
+// @ts-ignore
+        s1.push(s2);
+// @ts-ignore
+        if (peg$r0.test(input.charAt(peg$currPos))) {
+// @ts-ignore
+          s2 = input.charAt(peg$currPos);
+// @ts-ignore
+          peg$currPos++;
+// @ts-ignore
+        } else {
+// @ts-ignore
+          s2 = peg$FAILED;
+// @ts-ignore
+          Iif (peg$silentFails === 0) { peg$fail(peg$e17); }
+        }
+      }
+// @ts-ignore
+    } else {
+// @ts-ignore
+      s1 = peg$FAILED;
+    }
+// @ts-ignore
+    Iif (s1 !== peg$FAILED) {
+// @ts-ignore
+      peg$savedPos = s0;
+// @ts-ignore
+      s1 = peg$f17();
+    }
+// @ts-ignore
+    s0 = s1;
+ 
+// @ts-ignore
+    return s0;
+  }
+ 
+// @ts-ignore
+  function // @ts-ignore
+peg$parseString() {
+// @ts-ignore
+    var s0, s1, s2;
+ 
+// @ts-ignore
+    s0 = peg$currPos;
+// @ts-ignore
+    s1 = [];
+// @ts-ignore
+    if (peg$r1.test(input.charAt(peg$currPos))) {
+// @ts-ignore
+      s2 = input.charAt(peg$currPos);
+// @ts-ignore
+      peg$currPos++;
+// @ts-ignore
+    } else E{
+// @ts-ignore
+      s2 = peg$FAILED;
+// @ts-ignore
+      Iif (peg$silentFails === 0) { peg$fail(peg$e18); }
+    }
+// @ts-ignore
+    if (s2 !== peg$FAILED) {
+// @ts-ignore
+      while (s2 !== peg$FAILED) {
+// @ts-ignore
+        s1.push(s2);
+// @ts-ignore
+        if (peg$r1.test(input.charAt(peg$currPos))) {
+// @ts-ignore
+          s2 = input.charAt(peg$currPos);
+// @ts-ignore
+          peg$currPos++;
+// @ts-ignore
+        } else {
+// @ts-ignore
+          s2 = peg$FAILED;
+// @ts-ignore
+          if (peg$silentFails === 0) { peg$fail(peg$e18); }
+        }
+      }
+// @ts-ignore
+    } else E{
+// @ts-ignore
+      s1 = peg$FAILED;
+    }
+// @ts-ignore
+    if (s1 !== peg$FAILED) {
+// @ts-ignore
+      peg$savedPos = s0;
+// @ts-ignore
+      s1 = peg$f18();
+    }
+// @ts-ignore
+    s0 = s1;
+ 
+// @ts-ignore
+    return s0;
+  }
+ 
+// @ts-ignore
+  function // @ts-ignore
+peg$parseVersion() {
+// @ts-ignore
+    var s0, s1, s2;
+ 
+// @ts-ignore
+    s0 = peg$currPos;
+// @ts-ignore
+    s1 = peg$parseVersionNumber();
+// @ts-ignore
+    if (s1 !== peg$FAILED) {
+// @ts-ignore
+      s2 = peg$parsePreRelease();
+// @ts-ignore
+      if (s2 === peg$FAILED) {
+// @ts-ignore
+        s2 = null;
+      }
+// @ts-ignore
+      peg$savedPos = s0;
+// @ts-ignore
+      s0 = peg$f19(s1, s2);
+// @ts-ignore
+    } else {
+// @ts-ignore
+      peg$currPos = s0;
+// @ts-ignore
+      s0 = peg$FAILED;
+    }
+ 
+// @ts-ignore
+    return s0;
+  }
+ 
+// @ts-ignore
+  function // @ts-ignore
+peg$parsePreRelease() {
+// @ts-ignore
+    var s0, s1, s2, s3, s4, s5, s6;
+ 
+// @ts-ignore
+    s0 = peg$currPos;
+// @ts-ignore
+    if (input.charCodeAt(peg$currPos) === 45) {
+// @ts-ignore
+      s1 = peg$c17;
+// @ts-ignore
+      peg$currPos++;
+// @ts-ignore
+    } else {
+// @ts-ignore
+      s1 = peg$FAILED;
+// @ts-ignore
+      if (peg$silentFails === 0) { peg$fail(peg$e19); }
+    }
+// @ts-ignore
+    if (s1 !== peg$FAILED) {
+// @ts-ignore
+      s2 = peg$parsePreReleaseSegment();
+// @ts-ignore
+      if (s2 !== peg$FAILED) {
+// @ts-ignore
+        s3 = [];
+// @ts-ignore
+        s4 = peg$currPos;
+// @ts-ignore
+        if (input.charCodeAt(peg$currPos) === 46) {
+// @ts-ignore
+          s5 = peg$c15;
+// @ts-ignore
+          peg$currPos++;
+// @ts-ignore
+        } else E{
+// @ts-ignore
+          s5 = peg$FAILED;
+// @ts-ignore
+          Iif (peg$silentFails === 0) { peg$fail(peg$e15); }
+        }
+// @ts-ignore
+        if (s5 !== peg$FAILED) {
+// @ts-ignore
+          s6 = peg$parsePreReleaseSegment();
+// @ts-ignore
+          if (s6 !== peg$FAILED) {
+// @ts-ignore
+            s5 = [s5, s6];
+// @ts-ignore
+            s4 = s5;
+// @ts-ignore
+          } else E{
+// @ts-ignore
+            peg$currPos = s4;
+// @ts-ignore
+            s4 = peg$FAILED;
+          }
+// @ts-ignore
+        } else E{
+// @ts-ignore
+          peg$currPos = s4;
+// @ts-ignore
+          s4 = peg$FAILED;
+        }
+// @ts-ignore
+        while (s4 !== peg$FAILED) {
+// @ts-ignore
+          s3.push(s4);
+// @ts-ignore
+          s4 = peg$currPos;
+// @ts-ignore
+          Iif (input.charCodeAt(peg$currPos) === 46) {
+// @ts-ignore
+            s5 = peg$c15;
+// @ts-ignore
+            peg$currPos++;
+// @ts-ignore
+          } else {
+// @ts-ignore
+            s5 = peg$FAILED;
+// @ts-ignore
+            if (peg$silentFails === 0) { peg$fail(peg$e15); }
+          }
+// @ts-ignore
+          Iif (s5 !== peg$FAILED) {
+// @ts-ignore
+            s6 = peg$parsePreReleaseSegment();
+// @ts-ignore
+            if (s6 !== peg$FAILED) {
+// @ts-ignore
+              s5 = [s5, s6];
+// @ts-ignore
+              s4 = s5;
+// @ts-ignore
+            } else {
+// @ts-ignore
+              peg$currPos = s4;
+// @ts-ignore
+              s4 = peg$FAILED;
+            }
+// @ts-ignore
+          } else {
+// @ts-ignore
+            peg$currPos = s4;
+// @ts-ignore
+            s4 = peg$FAILED;
+          }
+        }
+// @ts-ignore
+        peg$savedPos = s0;
+// @ts-ignore
+        s0 = peg$f20(s2, s3);
+// @ts-ignore
+      } else E{
+// @ts-ignore
+        peg$currPos = s0;
+// @ts-ignore
+        s0 = peg$FAILED;
+      }
+// @ts-ignore
+    } else {
+// @ts-ignore
+      peg$currPos = s0;
+// @ts-ignore
+      s0 = peg$FAILED;
+    }
+ 
+// @ts-ignore
+    return s0;
+  }
+ 
+// @ts-ignore
+  function // @ts-ignore
+peg$parsePreReleaseSegment() {
+// @ts-ignore
+    var s0, s1, s2;
+ 
+// @ts-ignore
+    s0 = peg$currPos;
+// @ts-ignore
+    Iif (input.charCodeAt(peg$currPos) === 46) {
+// @ts-ignore
+      s1 = peg$c15;
+// @ts-ignore
+      peg$currPos++;
+// @ts-ignore
+    } else {
+// @ts-ignore
+      s1 = peg$FAILED;
+// @ts-ignore
+      if (peg$silentFails === 0) { peg$fail(peg$e15); }
+    }
+// @ts-ignore
+    if (s1 === peg$FAILED) {
+// @ts-ignore
+      s1 = null;
+    }
+// @ts-ignore
+    s2 = peg$parseDigit();
+// @ts-ignore
+    if (s2 === peg$FAILED) {
+// @ts-ignore
+      s2 = peg$parseString();
+    }
+// @ts-ignore
+    if (s2 !== peg$FAILED) {
+// @ts-ignore
+      peg$savedPos = s0;
+// @ts-ignore
+      s0 = peg$f21(s2);
+// @ts-ignore
+    } else E{
+// @ts-ignore
+      peg$currPos = s0;
+// @ts-ignore
+      s0 = peg$FAILED;
+    }
+ 
+// @ts-ignore
+    return s0;
+  }
+ 
+// @ts-ignore
+  function // @ts-ignore
+peg$parseVersionNumber() {
+// @ts-ignore
+    var s0, s1, s2, s3, s4, s5;
+ 
+// @ts-ignore
+    s0 = peg$currPos;
+// @ts-ignore
+    s1 = peg$parseDigit();
+// @ts-ignore
+    if (s1 !== peg$FAILED) {
+// @ts-ignore
+      s2 = [];
+// @ts-ignore
+      s3 = peg$currPos;
+// @ts-ignore
+      if (input.charCodeAt(peg$currPos) === 46) {
+// @ts-ignore
+        s4 = peg$c15;
+// @ts-ignore
+        peg$currPos++;
+// @ts-ignore
+      } else {
+// @ts-ignore
+        s4 = peg$FAILED;
+// @ts-ignore
+        if (peg$silentFails === 0) { peg$fail(peg$e15); }
+      }
+// @ts-ignore
+      if (s4 !== peg$FAILED) {
+// @ts-ignore
+        s5 = peg$parseDigit();
+// @ts-ignore
+        if (s5 !== peg$FAILED) {
+// @ts-ignore
+          s4 = [s4, s5];
+// @ts-ignore
+          s3 = s4;
+// @ts-ignore
+        } else {
+// @ts-ignore
+          peg$currPos = s3;
+// @ts-ignore
+          s3 = peg$FAILED;
+        }
+// @ts-ignore
+      } else {
+// @ts-ignore
+        peg$currPos = s3;
+// @ts-ignore
+        s3 = peg$FAILED;
+      }
+// @ts-ignore
+      while (s3 !== peg$FAILED) {
+// @ts-ignore
+        s2.push(s3);
+// @ts-ignore
+        s3 = peg$currPos;
+// @ts-ignore
+        if (input.charCodeAt(peg$currPos) === 46) {
+// @ts-ignore
+          s4 = peg$c15;
+// @ts-ignore
+          peg$currPos++;
+// @ts-ignore
+        } else {
+// @ts-ignore
+          s4 = peg$FAILED;
+// @ts-ignore
+          if (peg$silentFails === 0) { peg$fail(peg$e15); }
+        }
+// @ts-ignore
+        if (s4 !== peg$FAILED) {
+// @ts-ignore
+          s5 = peg$parseDigit();
+// @ts-ignore
+          if (s5 !== peg$FAILED) {
+// @ts-ignore
+            s4 = [s4, s5];
+// @ts-ignore
+            s3 = s4;
+// @ts-ignore
+          } else E{
+// @ts-ignore
+            peg$currPos = s3;
+// @ts-ignore
+            s3 = peg$FAILED;
+          }
+// @ts-ignore
+        } else {
+// @ts-ignore
+          peg$currPos = s3;
+// @ts-ignore
+          s3 = peg$FAILED;
+        }
+      }
+// @ts-ignore
+      peg$savedPos = s0;
+// @ts-ignore
+      s0 = peg$f22(s1, s2);
+// @ts-ignore
+    } else {
+// @ts-ignore
+      peg$currPos = s0;
+// @ts-ignore
+      s0 = peg$FAILED;
+    }
+ 
+// @ts-ignore
+    return s0;
+  }
+ 
+// @ts-ignore
+  function // @ts-ignore
+peg$parseDigit() {
+// @ts-ignore
+    var s0, s1, s2;
+ 
+// @ts-ignore
+    s0 = peg$currPos;
+// @ts-ignore
+    s1 = [];
+// @ts-ignore
+    if (peg$r2.test(input.charAt(peg$currPos))) {
+// @ts-ignore
+      s2 = input.charAt(peg$currPos);
+// @ts-ignore
+      peg$currPos++;
+// @ts-ignore
+    } else {
+// @ts-ignore
+      s2 = peg$FAILED;
+// @ts-ignore
+      if (peg$silentFails === 0) { peg$fail(peg$e20); }
+    }
+// @ts-ignore
+    if (s2 !== peg$FAILED) {
+// @ts-ignore
+      while (s2 !== peg$FAILED) {
+// @ts-ignore
+        s1.push(s2);
+// @ts-ignore
+        if (peg$r2.test(input.charAt(peg$currPos))) {
+// @ts-ignore
+          s2 = input.charAt(peg$currPos);
+// @ts-ignore
+          peg$currPos++;
+// @ts-ignore
+        } else {
+// @ts-ignore
+          s2 = peg$FAILED;
+// @ts-ignore
+          if (peg$silentFails === 0) { peg$fail(peg$e20); }
+        }
+      }
+// @ts-ignore
+    } else {
+// @ts-ignore
+      s1 = peg$FAILED;
+    }
+// @ts-ignore
+    if (s1 !== peg$FAILED) {
+// @ts-ignore
+      peg$savedPos = s0;
+// @ts-ignore
+      s1 = peg$f23();
+    }
+// @ts-ignore
+    s0 = s1;
+ 
+// @ts-ignore
+    return s0;
+  }
+ 
+// @ts-ignore
+  function // @ts-ignore
+peg$parse_() {
+// @ts-ignore
+    var s0, s1;
+ 
+// @ts-ignore
+    peg$silentFails++;
+// @ts-ignore
+    s0 = [];
+// @ts-ignore
+    if (peg$r3.test(input.charAt(peg$currPos))) {
+// @ts-ignore
+      s1 = input.charAt(peg$currPos);
+// @ts-ignore
+      peg$currPos++;
+// @ts-ignore
+    } else {
+// @ts-ignore
+      s1 = peg$FAILED;
+// @ts-ignore
+      Iif (peg$silentFails === 0) { peg$fail(peg$e22); }
+    }
+// @ts-ignore
+    while (s1 !== peg$FAILED) {
+// @ts-ignore
+      s0.push(s1);
+// @ts-ignore
+      Iif (peg$r3.test(input.charAt(peg$currPos))) {
+// @ts-ignore
+        s1 = input.charAt(peg$currPos);
+// @ts-ignore
+        peg$currPos++;
+// @ts-ignore
+      } else {
+// @ts-ignore
+        s1 = peg$FAILED;
+// @ts-ignore
+        Iif (peg$silentFails === 0) { peg$fail(peg$e22); }
+      }
+    }
+// @ts-ignore
+    peg$silentFails--;
+// @ts-ignore
+    s1 = peg$FAILED;
+// @ts-ignore
+    if (peg$silentFails === 0) { peg$fail(peg$e21); }
+ 
+// @ts-ignore
+    return s0;
+  }
+ 
+// @ts-ignore
+  peg$result = peg$startRuleFunction();
+ 
+// @ts-ignore
+  if (peg$result !== peg$FAILED && peg$currPos === input.length) {
+// @ts-ignore
+    return peg$result;
+// @ts-ignore
+  } else {
+// @ts-ignore
+    Iif (peg$result !== peg$FAILED && peg$currPos < input.length) {
+// @ts-ignore
+      peg$fail(peg$endExpectation());
+    }
+ 
+// @ts-ignore
+    throw peg$buildStructuredError(
+// @ts-ignore
+      peg$maxFailExpected,
+// @ts-ignore
+      peg$maxFailPos < input.length ? input.charAt(peg$maxFailPos) : null,
+// @ts-ignore
+      peg$maxFailPos < input.length
+// @ts-ignore
+        ? peg$computeLocation(peg$maxFailPos, peg$maxFailPos + 1)
+// @ts-ignore
+        : peg$computeLocation(peg$maxFailPos, peg$maxFailPos)
+    );
+  }
+}
+ 
+// @ts-ignore
+  return {
+    SyntaxError: peg$SyntaxError,
+    parse: peg$parse
+  };
+})()
+ 
+export interface FilePosition {
+  offset: number;
+  line: number;
+  column: number;
+}
+ 
+export interface FileRange {
+  start: FilePosition;
+  end: FilePosition;
+  source: string;
+}
+ 
+export interface LiteralExpectation {
+  type: "literal";
+  text: string;
+  ignoreCase: boolean;
+}
+ 
+export interface ClassParts extends Array<string | ClassParts> {}
+ 
+export interface ClassExpectation {
+  type: "class";
+  parts: ClassParts;
+  inverted: boolean;
+  ignoreCase: boolean;
+}
+ 
+export interface AnyExpectation {
+  type: "any";
+}
+ 
+export interface EndExpectation {
+  type: "end";
+}
+ 
+export interface OtherExpectation {
+  type: "other";
+  description: string;
+}
+ 
+export type Expectation = LiteralExpectation | ClassExpectation | AnyExpectation | EndExpectation | OtherExpectation;
+ 
+declare class _PeggySyntaxError extends Error {
+  public static buildMessage(expected: Expectation[], found: string | null): string;
+  public message: string;
+  public expected: Expectation[];
+  public found: string | null;
+  public location: FileRange;
+  public name: string;
+  constructor(message: string, expected: Expectation[], found: string | null, location: FileRange);
+  format(sources: {
+    source?: any;
+    text: string;
+  }[]): string;
+}
+ 
+export interface TraceEvent {
+    type: string;
+    rule: string;
+    result?: any;
+    location: FileRange;
+  }
+ 
+declare class _DefaultTracer {
+  private indentLevel: number;
+  public trace(event: TraceEvent): void;
+}
+ 
+peggyParser.SyntaxError.prototype.name = "PeggySyntaxError";
+ 
+export interface ParseOptions {
+  filename?: string;
+  startRule?: "VersionRange" | "Or" | "And" | "VersionRangeAtom" | "Parens" | "Anchor" | "VersionSpec" | "Not" | "Any" | "None" | "CmpOp" | "ExtendedVersion" | "EmVer" | "Flavor" | "Lowercase" | "String" | "Version" | "PreRelease" | "PreReleaseSegment" | "VersionNumber" | "Digit" | "_";
+  tracer?: any;
+  [key: string]: any;
+}
+export type ParseFunction = <Options extends ParseOptions>(
+    input: string,
+    options?: Options
+  ) => Options extends { startRule: infer StartRule } ?
+    StartRule extends "VersionRange" ? VersionRange :
+    StartRule extends "Or" ? Or :
+    StartRule extends "And" ? And :
+    StartRule extends "VersionRangeAtom" ? VersionRangeAtom :
+    StartRule extends "Parens" ? Parens :
+    StartRule extends "Anchor" ? Anchor :
+    StartRule extends "VersionSpec" ? VersionSpec :
+    StartRule extends "Not" ? Not :
+    StartRule extends "Any" ? Any :
+    StartRule extends "None" ? None :
+    StartRule extends "CmpOp" ? CmpOp :
+    StartRule extends "ExtendedVersion" ? ExtendedVersion :
+    StartRule extends "EmVer" ? EmVer :
+    StartRule extends "Flavor" ? Flavor :
+    StartRule extends "Lowercase" ? Lowercase_1 :
+    StartRule extends "String" ? String_1 :
+    StartRule extends "Version" ? Version :
+    StartRule extends "PreRelease" ? PreRelease :
+    StartRule extends "PreReleaseSegment" ? PreReleaseSegment :
+    StartRule extends "VersionNumber" ? VersionNumber :
+    StartRule extends "Digit" ? Digit :
+    StartRule extends "_" ? _ : VersionRange
+    : VersionRange;
+export const parse: ParseFunction = peggyParser.parse;
+ 
+export const PeggySyntaxError = peggyParser.SyntaxError as typeof _PeggySyntaxError;
+ 
+export type PeggySyntaxError = _PeggySyntaxError;
+ 
+// These types were autogenerated by ts-pegjs
+export type VersionRange = [
+  VersionRangeAtom,
+  [_, [Or | And, _] | null, VersionRangeAtom][]
+];
+export type Or = "||";
+export type And = "&&";
+export type VersionRangeAtom = Parens | Anchor | Not | Any | None;
+export type Parens = { type: "Parens"; expr: VersionRange };
+export type Anchor = {
+  type: "Anchor";
+  operator: CmpOp | null;
+  version: VersionSpec;
+};
+export type VersionSpec = {
+  flavor: NonNullable<Flavor | null> | null;
+  upstream: Version;
+  downstream: any;
+};
+export type Not = { type: "Not"; value: VersionRangeAtom };
+export type Any = { type: "Any" };
+export type None = { type: "None" };
+export type CmpOp = ">=" | "<=" | ">" | "<" | "=" | "!=" | "^" | "~";
+export type ExtendedVersion = {
+  flavor: NonNullable<Flavor | null> | null;
+  upstream: Version;
+  downstream: Version;
+};
+export type EmVer = {
+  flavor: null;
+  upstream: { number: [Digit, Digit, Digit]; prerelease: [] };
+  downstream: { number: [any]; prerelease: [] };
+};
+export type Flavor = Lowercase_1;
+export type Lowercase_1 = string;
+export type String_1 = string;
+export type Version = {
+  number: VersionNumber;
+  prerelease: never[] | NonNullable<PreRelease | null>;
+};
+export type PreRelease = PreReleaseSegment[];
+export type PreReleaseSegment = Digit | String_1;
+export type VersionNumber = Digit[];
+export type Digit = number;
+export type _ = string[];
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/exver/index.html b/sdk/lib/coverage/lcov-report/lib/exver/index.html new file mode 100644 index 000000000..f664c8466 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/exver/index.html @@ -0,0 +1,131 @@ + + + + + + Code coverage report for lib/exver + + + + + + + + + +
+
+

All files lib/exver

+
+ +
+ 71.73% + Statements + 713/994 +
+ + +
+ 63.29% + Branches + 250/395 +
+ + +
+ 71.65% + Functions + 91/127 +
+ + +
+ 71.77% + Lines + 679/946 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
exver.ts +
+
73.61%611/83062.5%185/29669.31%61/8873.76%582/789
index.ts +
+
62.19%102/16465.65%65/9976.92%30/3961.78%97/157
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/exver/index.ts.html b/sdk/lib/coverage/lcov-report/lib/exver/index.ts.html new file mode 100644 index 000000000..d04d4ab16 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/exver/index.ts.html @@ -0,0 +1,1447 @@ + + + + + + Code coverage report for lib/exver/index.ts + + + + + + + + + +
+
+

All files / lib/exver index.ts

+
+ +
+ 62.19% + Statements + 102/164 +
+ + +
+ 65.65% + Branches + 65/99 +
+ + +
+ 76.92% + Functions + 30/39 +
+ + +
+ 61.78% + Lines + 97/157 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335 +336 +337 +338 +339 +340 +341 +342 +343 +344 +345 +346 +347 +348 +349 +350 +351 +352 +353 +354 +355 +356 +357 +358 +359 +360 +361 +362 +363 +364 +365 +366 +367 +368 +369 +370 +371 +372 +373 +374 +375 +376 +377 +378 +379 +380 +381 +382 +383 +384 +385 +386 +387 +388 +389 +390 +391 +392 +393 +394 +395 +396 +397 +398 +399 +400 +401 +402 +403 +404 +405 +406 +407 +408 +409 +410 +411 +412 +413 +414 +415 +416 +417 +418 +419 +420 +421 +422 +423 +424 +425 +426 +427 +428 +429 +430 +431 +432 +433 +434 +435 +436 +437 +438 +439 +440 +441 +442 +443 +444 +445 +446 +447 +448 +449 +450 +451 +452 +453 +454 +4556x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +6x +87x +  +  +50x +  +20x +  +  +  +20x +  +  +  +  +  +10x +  +  +  +  +27x +  +2x +  +  +  +  +  +  +24x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +18x +18x +7x +  +3x +  +  +  +  +3x +  +  +4x +  +  +  +  +4x +  +  +18x +  +  +  +18x +  +  +  +  +  +1x +  +  +  +21x +  +  +  +1x +  +  +  +20x +  +  +  +  +  +  +  +10x +  +  +  +112x +  +  +  +6x +  +308x +308x +  +  +  +40x +  +  +  +235x +235x +419x +63x +356x +38x +  +  +  +134x +  +134x +  +  +  +134x +134x +252x +252x +  +252x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +134x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +6x +  +154x +154x +154x +  +  +  +20x +  +  +  +160x +  +  +160x +160x +85x +  +75x +  +  +  +3x +  +3x +  +  +3x +  +  +  +  +3x +  +1x +  +1x +  +1x +  +  +  +  +30x +  +  +  +30x +  +  +  +31x +  +  +  +54x +  +  +  +9x +  +  +  +109x +106x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +24x +24x +  +24x +48x +  +48x +24x +  +24x +  +  +24x +24x +  +24x +  +  +  +  +  +  +  +  +  +  +  +198x +  +129x +129x +  +21x +  +30x +  +39x +  +6x +  +9x +  +  +  +  +  +  +  +  +  +  +  +  +  +24x +24x +  +  +  +6x +  +18x +  +  +  +21x +  +  +  +  +17x +  +  +  +  +22x +  +9x +  +  +  +  +  +  +6x +  +6x +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import * as P from "./exver"
+ 
+// prettier-ignore
+export type ValidateVersion<T extends String> = 
+T extends `-${infer A}` ? never  :
+T extends `${infer A}-${string}` ? ValidateVersion<A> :
+  T extends `${bigint}` ? unknown :
+  T extends `${bigint}.${infer A}` ? ValidateVersion<A> :
+  never
+ 
+// prettier-ignore
+export type ValidateExVer<T extends string> = 
+  T extends `#${string}:${infer A}:${infer B}` ? ValidateVersion<A> & ValidateVersion<B> :
+  T extends `${infer A}:${infer B}` ? ValidateVersion<A> & ValidateVersion<B> :  
+  never
+ 
+// prettier-ignore
+export type ValidateExVers<T> =
+  T extends [] ? unknown[] :
+  T extends [infer A, ...infer B] ? ValidateExVer<A & string> & ValidateExVers<B> :
+  never[]
+ 
+type Anchor = {
+  type: "Anchor"
+  operator: P.CmpOp
+  version: ExtendedVersion
+}
+ 
+type And = {
+  type: "And"
+  left: VersionRange
+  right: VersionRange
+}
+ 
+type Or = {
+  type: "Or"
+  left: VersionRange
+  right: VersionRange
+}
+ 
+type Not = {
+  type: "Not"
+  value: VersionRange
+}
+ 
+export class VersionRange {
+  private constructor(public atom: Anchor | And | Or | Not | P.Any | P.None) {}
+ 
+  toString(): string {
+    switch (this.atom.type) {
+      case "Anchor":
+        return `${this.atom.operator}${this.atom.version}`
+      case "And":
+        return `(${this.atom.left.toString()}) && (${this.atom.right.toString()})`
+      case "Or":
+        return `(${this.atom.left.toString()}) || (${this.atom.right.toString()})`
+      case "Not":
+        return `!(${this.atom.value.toString()})`
+      case "Any":
+        return "*"
+      case "None":
+        return "!"
+    }
+  }
+ 
+  private static parseAtom(atom: P.VersionRangeAtom): VersionRange {
+    switch (atom.type) {
+      case "Not":
+        return new VersionRange({
+          type: "Not",
+          value: VersionRange.parseAtom(atom.value),
+        })
+      case "Parens":
+        return VersionRange.parseRange(atom.expr)
+      case "Anchor":
+        return new VersionRange({
+          type: "Anchor",
+          operator: atom.operator || "^",
+          version: new ExtendedVersion(
+            atom.version.flavor,
+            new Version(
+              atom.version.upstream.number,
+              atom.version.upstream.prerelease,
+            ),
+            new Version(
+              atom.version.downstream.number,
+              atom.version.downstream.prerelease,
+            ),
+          ),
+        })
+      default:
+        return new VersionRange(atom)
+    }
+  }
+ 
+  private static parseRange(range: P.VersionRange): VersionRange {
+    let result = VersionRange.parseAtom(range[0])
+    for (const next of range[1]) {
+      switch (next[1]?.[0]) {
+        case "||":
+          result = new VersionRange({
+            type: "Or",
+            left: result,
+            right: VersionRange.parseAtom(next[2]),
+          })
+          break
+        case "&&":
+        default:
+          result = new VersionRange({
+            type: "And",
+            left: result,
+            right: VersionRange.parseAtom(next[2]),
+          })
+          break
+      }
+    }
+    return result
+  }
+ 
+  static parse(range: string): VersionRange {
+    return VersionRange.parseRange(
+      P.parse(range, { startRule: "VersionRange" }),
+    )
+  }
+ 
+  and(right: VersionRange) {
+    return new VersionRange({ type: "And", left: this, right })
+  }
+ 
+  or(right: VersionRange) {
+    return new VersionRange({ type: "Or", left: this, right })
+  }
+ 
+  not() {
+    return new VersionRange({ type: "Not", value: this })
+  }
+ 
+  static anchor(operator: P.CmpOp, version: ExtendedVersion) {
+    return new VersionRange({ type: "Anchor", operator, version })
+  }
+ 
+  static any() {
+    return new VersionRange({ type: "Any" })
+  }
+ 
+  static none() {
+    return new VersionRange({ type: "None" })
+  }
+ 
+  satisfiedBy(version: Version | ExtendedVersion) {
+    return version.satisfies(this)
+  }
+}
+ 
+export class Version {
+  constructor(
+    public number: number[],
+    public prerelease: (string | number)[],
+  ) {}
+ 
+  toString(): string {
+    return `${this.number.join(".")}${this.prerelease.length > 0 ? `-${this.prerelease.join(".")}` : ""}`
+  }
+ 
+  compare(other: Version): "greater" | "equal" | "less" {
+    const numLen = Math.max(this.number.length, other.number.length)
+    for (let i = 0; i < numLen; i++) {
+      if ((this.number[i] || 0) > (other.number[i] || 0)) {
+        return "greater"
+      } else if ((this.number[i] || 0) < (other.number[i] || 0)) {
+        return "less"
+      }
+    }
+ 
+    Iif (this.prerelease.length === 0 && other.prerelease.length !== 0) {
+      return "greater"
+    } else Iif (this.prerelease.length !== 0 && other.prerelease.length === 0) {
+      return "less"
+    }
+ 
+    const prereleaseLen = Math.max(this.number.length, other.number.length)
+    for (let i = 0; i < prereleaseLen; i++) {
+      if (typeof this.prerelease[i] === typeof other.prerelease[i]) {
+        Iif (this.prerelease[i] > other.prerelease[i]) {
+          return "greater"
+        } else Iif (this.prerelease[i] < other.prerelease[i]) {
+          return "less"
+        }
+      } else E{
+        switch (`${typeof this.prerelease[1]}:${typeof other.prerelease[i]}`) {
+          case "number:string":
+            return "less"
+          case "string:number":
+            return "greater"
+          case "number:undefined":
+          case "string:undefined":
+            return "greater"
+          case "undefined:number":
+          case "undefined:string":
+            return "less"
+        }
+      }
+    }
+ 
+    return "equal"
+  }
+ 
+  static parse(version: string): Version {
+    const parsed = P.parse(version, { startRule: "Version" })
+    return new Version(parsed.number, parsed.prerelease)
+  }
+ 
+  satisfies(versionRange: VersionRange): boolean {
+    return new ExtendedVersion(null, this, new Version([0], [])).satisfies(
+      versionRange,
+    )
+  }
+}
+ 
+// #flavor:0.1.2-beta.1:0
+export class ExtendedVersion {
+  constructor(
+    public flavor: string | null,
+    public upstream: Version,
+    public downstream: Version,
+  ) {}
+ 
+  toString(): string {
+    return `${this.flavor ? `#${this.flavor}:` : ""}${this.upstream.toString()}:${this.downstream.toString()}`
+  }
+ 
+  compare(other: ExtendedVersion): "greater" | "equal" | "less" | null {
+    Iif (this.flavor !== other.flavor) {
+      return null
+    }
+    const upstreamCmp = this.upstream.compare(other.upstream)
+    if (upstreamCmp !== "equal") {
+      return upstreamCmp
+    }
+    return this.downstream.compare(other.downstream)
+  }
+ 
+  compareLexicographic(other: ExtendedVersion): "greater" | "equal" | "less" {
+    Iif ((this.flavor || "") > (other.flavor || "")) {
+      return "greater"
+    } else Iif ((this.flavor || "") > (other.flavor || "")) {
+      return "less"
+    } else {
+      return this.compare(other)!
+    }
+  }
+ 
+  compareForSort(other: ExtendedVersion): 1 | 0 | -1 {
+    switch (this.compareLexicographic(other)) {
+      case "greater":
+        return 1
+      case "equal":
+        return 0
+      case "less":
+        return -1
+    }
+  }
+ 
+  greaterThan(other: ExtendedVersion): boolean {
+    return this.compare(other) === "greater"
+  }
+ 
+  greaterThanOrEqual(other: ExtendedVersion): boolean {
+    return ["greater", "equal"].includes(this.compare(other) as string)
+  }
+ 
+  equals(other: ExtendedVersion): boolean {
+    return this.compare(other) === "equal"
+  }
+ 
+  lessThan(other: ExtendedVersion): boolean {
+    return this.compare(other) === "less"
+  }
+ 
+  lessThanOrEqual(other: ExtendedVersion): boolean {
+    return ["less", "equal"].includes(this.compare(other) as string)
+  }
+ 
+  static parse(extendedVersion: string): ExtendedVersion {
+    const parsed = P.parse(extendedVersion, { startRule: "ExtendedVersion" })
+    return new ExtendedVersion(
+      parsed.flavor,
+      new Version(parsed.upstream.number, parsed.upstream.prerelease),
+      new Version(parsed.downstream.number, parsed.downstream.prerelease),
+    )
+  }
+ 
+  static parseEmver(extendedVersion: string): ExtendedVersion {
+    const parsed = P.parse(extendedVersion, { startRule: "EmVer" })
+    return new ExtendedVersion(
+      parsed.flavor,
+      new Version(parsed.upstream.number, parsed.upstream.prerelease),
+      new Version(parsed.downstream.number, parsed.downstream.prerelease),
+    )
+  }
+ 
+  /**
+   * Returns an ExtendedVersion with the Upstream major version version incremented by 1
+   * and sets subsequent digits to zero.
+   * If no non-zero upstream digit can be found the last upstream digit will be incremented.
+   */
+  incrementMajor(): ExtendedVersion {
+    const majorIdx = this.upstream.number.findIndex((num: number) => num !== 0)
+ 
+    const majorNumber = this.upstream.number.map((num, idx): number => {
+      if (idx > majorIdx) {
+        return 0
+      } else Iif (idx === majorIdx) {
+        return num + 1
+      }
+      return num
+    })
+ 
+    const incrementedUpstream = new Version(majorNumber, [])
+    const updatedDownstream = new Version([0], [])
+ 
+    return new ExtendedVersion(
+      this.flavor,
+      incrementedUpstream,
+      updatedDownstream,
+    )
+  }
+ 
+  /**
+   * Returns an ExtendedVersion with the Upstream minor version version incremented by 1
+   * also sets subsequent digits to zero.
+   * If no non-zero upstream digit can be found the last digit will be incremented.
+   */
+  incrementMinor(): ExtendedVersion {
+    const majorIdx = this.upstream.number.findIndex((num: number) => num !== 0)
+    let minorIdx = majorIdx === -1 ? majorIdx : majorIdx + 1
+ 
+    const majorNumber = this.upstream.number.map((num, idx): number => {
+      Iif (idx > minorIdx) {
+        return 0
+      } else if (idx === minorIdx) {
+        return num + 1
+      }
+      return num
+    })
+ 
+    const incrementedUpstream = new Version(majorNumber, [])
+    const updatedDownstream = new Version([0], [])
+ 
+    return new ExtendedVersion(
+      this.flavor,
+      incrementedUpstream,
+      updatedDownstream,
+    )
+  }
+ 
+  /**
+   * Returns a boolean indicating whether a given version satisfies the VersionRange
+   * !( >= 1:1 <= 2:2) || <=#bitcoin:1.2.0-alpha:0
+   */
+  satisfies(versionRange: VersionRange): boolean {
+    switch (versionRange.atom.type) {
+      case "Anchor":
+        const otherVersion = versionRange.atom.version
+        switch (versionRange.atom.operator) {
+          case "=":
+            return this.equals(otherVersion)
+          case ">":
+            return this.greaterThan(otherVersion)
+          case "<":
+            return this.lessThan(otherVersion)
+          case ">=":
+            return this.greaterThanOrEqual(otherVersion)
+          case "<=":
+            return this.lessThanOrEqual(otherVersion)
+          case "!=":
+            return !this.equals(otherVersion)
+          case "^":
+            const nextMajor = versionRange.atom.version.incrementMajor()
+            if (
+              this.greaterThanOrEqual(otherVersion) &&
+              this.lessThan(nextMajor)
+            ) {
+              return true
+            } else {
+              return false
+            }
+          case "~":
+            const nextMinor = versionRange.atom.version.incrementMinor()
+            if (
+              this.greaterThanOrEqual(otherVersion) &&
+              this.lessThan(nextMinor)
+            ) {
+              return true
+            } else {
+              return false
+            }
+        }
+      case "And":
+        return (
+          this.satisfies(versionRange.atom.left) &&
+          this.satisfies(versionRange.atom.right)
+        )
+      case "Or":
+        return (
+          this.satisfies(versionRange.atom.left) ||
+          this.satisfies(versionRange.atom.right)
+        )
+      case "Not":
+        return !this.satisfies(versionRange.atom.value)
+      case "Any":
+        return true
+      case "None":
+        return false
+    }
+  }
+}
+ 
+export const testTypeExVer = <T extends string>(t: T & ValidateExVer<T>) => t
+ 
+export const testTypeVersion = <T extends string>(t: T & ValidateVersion<T>) =>
+  t
+function tests() {
+  testTypeVersion("1.2.3")
+  testTypeVersion("1")
+  testTypeVersion("12.34.56")
+  testTypeVersion("1.2-3")
+  testTypeVersion("1-3")
+  testTypeVersion("1-alpha")
+  // @ts-expect-error
+  testTypeVersion("-3")
+  // @ts-expect-error
+  testTypeVersion("1.2.3:1")
+  // @ts-expect-error
+  testTypeVersion("#cat:1:1")
+ 
+  testTypeExVer("1.2.3:1.2.3")
+  testTypeExVer("1.2.3.4.5.6.7.8.9.0:1")
+  testTypeExVer("100:1")
+  testTypeExVer("#cat:1:1")
+  testTypeExVer("1.2.3.4.5.6.7.8.9.11.22.33:1")
+  testTypeExVer("1-0:1")
+  testTypeExVer("1-0:1")
+  // @ts-expect-error
+  testTypeExVer("1.2-3")
+  // @ts-expect-error
+  testTypeExVer("1-3")
+  // @ts-expect-error
+  testTypeExVer("1.2.3.4.5.6.7.8.9.0.10:1" as string)
+  // @ts-expect-error
+  testTypeExVer("1.-2:1")
+  // @ts-expect-error
+  testTypeExVer("1..2.3:3")
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/health/HealthCheck.ts.html b/sdk/lib/coverage/lcov-report/lib/health/HealthCheck.ts.html new file mode 100644 index 000000000..c2b890bca --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/health/HealthCheck.ts.html @@ -0,0 +1,289 @@ + + + + + + Code coverage report for lib/health/HealthCheck.ts + + + + + + + + + +
+
+

All files / lib/health HealthCheck.ts

+
+ +
+ 17.24% + Statements + 5/29 +
+ + +
+ 0% + Branches + 0/12 +
+ + +
+ 0% + Functions + 0/6 +
+ + +
+ 19.23% + Lines + 5/26 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69  +  +  +  +  +5x +5x +  +5x +  +5x +  +  +  +  +  +  +  +  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { Effects } from "../types"
+import { HealthCheckResult } from "./checkFns/HealthCheckResult"
+import { HealthReceipt } from "./HealthReceipt"
+import { Trigger } from "../trigger"
+import { TriggerInput } from "../trigger/TriggerInput"
+import { defaultTrigger } from "../trigger/defaultTrigger"
+import { once } from "../util/once"
+import { SubContainer } from "../util/SubContainer"
+import { object, unknown } from "ts-matches"
+import * as T from "../types"
+import { asError } from "../util/asError"
+ 
+export type HealthCheckParams = {
+  effects: Effects
+  name: string
+  trigger?: Trigger
+  fn(): Promise<HealthCheckResult> | HealthCheckResult
+  onFirstSuccess?: () => unknown | Promise<unknown>
+}
+ 
+export function healthCheck(o: HealthCheckParams) {
+  new Promise(async () => {
+    let currentValue: TriggerInput = {}
+    const getCurrentValue = () => currentValue
+    const trigger = (o.trigger ?? defaultTrigger)(getCurrentValue)
+    const triggerFirstSuccess = once(() =>
+      Promise.resolve(
+        "onFirstSuccess" in o && o.onFirstSuccess
+          ? o.onFirstSuccess()
+          : undefined,
+      ),
+    )
+    for (
+      let res = await trigger.next();
+      !res.done;
+      res = await trigger.next()
+    ) {
+      try {
+        const { result, message } = await o.fn()
+        await o.effects.setHealth({
+          name: o.name,
+          id: o.name,
+          result,
+          message: message || "",
+        })
+        currentValue.lastResult = result
+        await triggerFirstSuccess().catch((err) => {
+          console.error(asError(err))
+        })
+      } catch (e) {
+        await o.effects.setHealth({
+          name: o.name,
+          id: o.name,
+          result: "failure",
+          message: asMessage(e) || "",
+        })
+        currentValue.lastResult = "failure"
+      }
+    }
+  })
+  return {} as HealthReceipt
+}
+function asMessage(e: unknown) {
+  Iif (object({ message: unknown }).test(e)) return String(e.message)
+  const value = String(e)
+  Iif (value.length == null) return null
+  return value
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/health/checkFns/checkPortListening.ts.html b/sdk/lib/coverage/lcov-report/lib/health/checkFns/checkPortListening.ts.html new file mode 100644 index 000000000..2ca29390c --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/health/checkFns/checkPortListening.ts.html @@ -0,0 +1,286 @@ + + + + + + Code coverage report for lib/health/checkFns/checkPortListening.ts + + + + + + + + + +
+
+

All files / lib/health/checkFns checkPortListening.ts

+
+ +
+ 61.11% + Statements + 11/18 +
+ + +
+ 0% + Branches + 0/7 +
+ + +
+ 42.85% + Functions + 3/7 +
+ + +
+ 61.11% + Lines + 11/18 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68  +6x +  +  +6x +6x +  +6x +6x +6x +2x +  +  +  +12x +  +8x +  +2x +  +  +  +  +  +  +6x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { Effects } from "../../types"
+import { stringFromStdErrOut } from "../../util/stringFromStdErrOut"
+import { HealthCheckResult } from "./HealthCheckResult"
+ 
+import { promisify } from "node:util"
+import * as CP from "node:child_process"
+ 
+const cpExec = promisify(CP.exec)
+const cpExecFile = promisify(CP.execFile)
+export function containsAddress(x: string, port: number) {
+  const readPorts = x
+    .split("\n")
+    .filter(Boolean)
+    .splice(1)
+    .map((x) => x.split(" ").filter(Boolean)[1]?.split(":")?.[1])
+    .filter(Boolean)
+    .map((x) => Number.parseInt(x, 16))
+    .filter(Number.isFinite)
+  return readPorts.indexOf(port) >= 0
+}
+ 
+/**
+ * This is used to check if a port is listening on the system.
+ * Used during the health check fn or the check main fn.
+ */
+export async function checkPortListening(
+  effects: Effects,
+  port: number,
+  options: {
+    errorMessage: string
+    successMessage: string
+    timeoutMessage?: string
+    timeout?: number
+  },
+): Promise<HealthCheckResult> {
+  return Promise.race<HealthCheckResult>([
+    Promise.resolve().then(async () => {
+      const hasAddress =
+        containsAddress(
+          await cpExec(`cat /proc/net/tcp`, {}).then(stringFromStdErrOut),
+          port,
+        ) ||
+        containsAddress(
+          await cpExec("cat /proc/net/udp", {}).then(stringFromStdErrOut),
+          port,
+        )
+      Iif (hasAddress) {
+        return { result: "success", message: options.successMessage }
+      }
+      return {
+        result: "failure",
+        message: options.errorMessage,
+      }
+    }),
+    new Promise((resolve) => {
+      setTimeout(
+        () =>
+          resolve({
+            result: "failure",
+            message:
+              options.timeoutMessage || `Timeout trying to check port ${port}`,
+          }),
+        options.timeout ?? 1_000,
+      )
+    }),
+  ])
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/health/checkFns/checkWebUrl.ts.html b/sdk/lib/coverage/lcov-report/lib/health/checkFns/checkWebUrl.ts.html new file mode 100644 index 000000000..a6b3666e0 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/health/checkFns/checkWebUrl.ts.html @@ -0,0 +1,193 @@ + + + + + + Code coverage report for lib/health/checkFns/checkWebUrl.ts + + + + + + + + + +
+
+

All files / lib/health/checkFns checkWebUrl.ts

+
+ +
+ 45.45% + Statements + 5/11 +
+ + +
+ 0% + Branches + 0/4 +
+ + +
+ 0% + Functions + 0/3 +
+ + +
+ 40% + Lines + 4/10 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37  +5x +  +5x +5x +  +  +  +  +  +  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { Effects } from "../../types"
+import { asError } from "../../util/asError"
+import { HealthCheckResult } from "./HealthCheckResult"
+import { timeoutPromise } from "./index"
+import "isomorphic-fetch"
+ 
+/**
+ * This is a helper function to check if a web url is reachable.
+ * @param url
+ * @param createSuccess
+ * @returns
+ */
+export const checkWebUrl = async (
+  effects: Effects,
+  url: string,
+  {
+    timeout = 1000,
+    successMessage = `Reached ${url}`,
+    errorMessage = `Error while fetching URL: ${url}`,
+  } = {},
+): Promise<HealthCheckResult> => {
+  return Promise.race([fetch(url), timeoutPromise(timeout)])
+    .then(
+      (x) =>
+        ({
+          result: "success",
+          message: successMessage,
+        }) as const,
+    )
+    .catch((e) => {
+      console.warn(`Error while fetching URL: ${url}`)
+      console.error(JSON.stringify(e))
+      console.error(asError(e))
+      return { result: "failure" as const, message: errorMessage }
+    })
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/health/checkFns/index.html b/sdk/lib/coverage/lcov-report/lib/health/checkFns/index.html new file mode 100644 index 000000000..80386daeb --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/health/checkFns/index.html @@ -0,0 +1,161 @@ + + + + + + Code coverage report for lib/health/checkFns + + + + + + + + + +
+
+

All files lib/health/checkFns

+
+ +
+ 53.06% + Statements + 26/49 +
+ + +
+ 0% + Branches + 0/17 +
+ + +
+ 26.31% + Functions + 5/19 +
+ + +
+ 50% + Lines + 22/44 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
checkPortListening.ts +
+
61.11%11/180%0/742.85%3/761.11%11/18
checkWebUrl.ts +
+
45.45%5/110%0/40%0/340%4/10
index.ts +
+
70%7/100%0/233.33%2/671.42%5/7
runHealthScript.ts +
+
30%3/100%0/40%0/322.22%2/9
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/health/checkFns/index.ts.html b/sdk/lib/coverage/lcov-report/lib/health/checkFns/index.ts.html new file mode 100644 index 000000000..1f904b21a --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/health/checkFns/index.ts.html @@ -0,0 +1,118 @@ + + + + + + Code coverage report for lib/health/checkFns/index.ts + + + + + + + + + +
+
+

All files / lib/health/checkFns index.ts

+
+ +
+ 70% + Statements + 7/10 +
+ + +
+ 0% + Branches + 0/2 +
+ + +
+ 33.33% + Functions + 2/6 +
+ + +
+ 71.42% + Lines + 5/7 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +125x +5x +  +11x +  +5x +  +  +  +  +11x + 
import { runHealthScript } from "./runHealthScript"
+export { checkPortListening } from "./checkPortListening"
+export { HealthCheckResult } from "./HealthCheckResult"
+export { checkWebUrl } from "./checkWebUrl"
+ 
+export function timeoutPromise(ms: number, { message = "Timed out" } = {}) {
+  return new Promise<never>((resolve, reject) =>
+    setTimeout(() => reject(new Error(message)), ms),
+  )
+}
+export { runHealthScript }
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/health/checkFns/runHealthScript.ts.html b/sdk/lib/coverage/lcov-report/lib/health/checkFns/runHealthScript.ts.html new file mode 100644 index 000000000..952fc0bcc --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/health/checkFns/runHealthScript.ts.html @@ -0,0 +1,196 @@ + + + + + + Code coverage report for lib/health/checkFns/runHealthScript.ts + + + + + + + + + +
+
+

All files / lib/health/checkFns runHealthScript.ts

+
+ +
+ 30% + Statements + 3/10 +
+ + +
+ 0% + Branches + 0/4 +
+ + +
+ 0% + Functions + 0/3 +
+ + +
+ 22.22% + Lines + 2/9 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38  +  +  +  +5x +  +  +  +  +  +  +  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { Effects } from "../../types"
+import { SubContainer } from "../../util/SubContainer"
+import { stringFromStdErrOut } from "../../util/stringFromStdErrOut"
+import { HealthCheckResult } from "./HealthCheckResult"
+import { timeoutPromise } from "./index"
+ 
+/**
+ * Running a health script, is used when we want to have a simple
+ * script in bash or something like that. It should return something that is useful
+ * in {result: string} else it is considered an error
+ * @param param0
+ * @returns
+ */
+export const runHealthScript = async (
+  runCommand: string[],
+  subcontainer: SubContainer,
+  {
+    timeout = 30000,
+    errorMessage = `Error while running command: ${runCommand}`,
+    message = (res: string) =>
+      `Have ran script ${runCommand} and the result: ${res}`,
+  } = {},
+): Promise<HealthCheckResult> => {
+  const res = await Promise.race([
+    subcontainer.exec(runCommand),
+    timeoutPromise(timeout),
+  ]).catch((e) => {
+    console.warn(errorMessage)
+    console.warn(JSON.stringify(e))
+    console.warn(e.toString())
+    throw { result: "failure", message: errorMessage } as HealthCheckResult
+  })
+  return {
+    result: "success",
+    message: message(res.stdout.toString()),
+  } as HealthCheckResult
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/health/index.html b/sdk/lib/coverage/lcov-report/lib/health/index.html new file mode 100644 index 000000000..7798fb909 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/health/index.html @@ -0,0 +1,116 @@ + + + + + + Code coverage report for lib/health + + + + + + + + + +
+
+

All files lib/health

+
+ +
+ 17.24% + Statements + 5/29 +
+ + +
+ 0% + Branches + 0/12 +
+ + +
+ 0% + Functions + 0/6 +
+ + +
+ 19.23% + Lines + 5/26 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
HealthCheck.ts +
+
17.24%5/290%0/120%0/619.23%5/26
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/index.html b/sdk/lib/coverage/lcov-report/lib/index.html new file mode 100644 index 000000000..d4b81c750 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/index.html @@ -0,0 +1,131 @@ + + + + + + Code coverage report for lib + + + + + + + + + +
+
+

All files lib

+
+ +
+ 40.27% + Statements + 58/144 +
+ + +
+ 0% + Branches + 0/11 +
+ + +
+ 11.76% + Functions + 10/85 +
+ + +
+ 40.27% + Lines + 58/144 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
Dependency.ts +
+
50%1/2100%0/00%0/150%1/2
StartSdk.ts +
+
40.14%57/1420%0/1111.9%10/8440.14%57/142
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/inits/index.html b/sdk/lib/coverage/lcov-report/lib/inits/index.html new file mode 100644 index 000000000..5b6500706 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/inits/index.html @@ -0,0 +1,146 @@ + + + + + + Code coverage report for lib/inits + + + + + + + + + +
+
+

All files lib/inits

+
+ +
+ 20.68% + Statements + 6/29 +
+ + +
+ 0% + Branches + 0/6 +
+ + +
+ 0% + Functions + 0/11 +
+ + +
+ 20.68% + Lines + 6/29 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
setupInit.ts +
+
12.5%2/160%0/50%0/312.5%2/16
setupInstall.ts +
+
33.33%2/6100%0/00%0/433.33%2/6
setupUninstall.ts +
+
28.57%2/70%0/10%0/428.57%2/7
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/inits/migrations/Migration.ts.html b/sdk/lib/coverage/lcov-report/lib/inits/migrations/Migration.ts.html new file mode 100644 index 000000000..8f6f88fec --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/inits/migrations/Migration.ts.html @@ -0,0 +1,190 @@ + + + + + + Code coverage report for lib/inits/migrations/Migration.ts + + + + + + + + + +
+
+

All files / lib/inits/migrations Migration.ts

+
+ +
+ 20% + Statements + 1/5 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 0% + Functions + 0/4 +
+ + +
+ 20% + Lines + 1/5 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36  +  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { ValidateExVer } from "../../exver"
+import * as T from "../../types"
+ 
+export class Migration<
+  Manifest extends T.Manifest,
+  Store,
+  Version extends string,
+> {
+  constructor(
+    readonly options: {
+      version: Version & ValidateExVer<Version>
+      up: (opts: { effects: T.Effects }) => Promise<void>
+      down: (opts: { effects: T.Effects }) => Promise<void>
+    },
+  ) {}
+  static of<
+    Manifest extends T.Manifest,
+    Store,
+    Version extends string,
+  >(options: {
+    version: Version & ValidateExVer<Version>
+    up: (opts: { effects: T.Effects }) => Promise<void>
+    down: (opts: { effects: T.Effects }) => Promise<void>
+  }) {
+    return new Migration<Manifest, Store, Version>(options)
+  }
+ 
+  async up(opts: { effects: T.Effects }) {
+    this.up(opts)
+  }
+ 
+  async down(opts: { effects: T.Effects }) {
+    this.down(opts)
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/inits/migrations/index.html b/sdk/lib/coverage/lcov-report/lib/inits/migrations/index.html new file mode 100644 index 000000000..a37468cb3 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/inits/migrations/index.html @@ -0,0 +1,131 @@ + + + + + + Code coverage report for lib/inits/migrations + + + + + + + + + +
+
+

All files lib/inits/migrations

+
+ +
+ 14.28% + Statements + 5/35 +
+ + +
+ 0% + Branches + 0/2 +
+ + +
+ 0% + Functions + 0/18 +
+ + +
+ 14.7% + Lines + 5/34 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
Migration.ts +
+
20%1/5100%0/00%0/420%1/5
setupMigrations.ts +
+
13.33%4/300%0/20%0/1413.79%4/29
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/inits/migrations/setupMigrations.ts.html b/sdk/lib/coverage/lcov-report/lib/inits/migrations/setupMigrations.ts.html new file mode 100644 index 000000000..efee979fb --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/inits/migrations/setupMigrations.ts.html @@ -0,0 +1,316 @@ + + + + + + Code coverage report for lib/inits/migrations/setupMigrations.ts + + + + + + + + + +
+
+

All files / lib/inits/migrations setupMigrations.ts

+
+ +
+ 13.33% + Statements + 4/30 +
+ + +
+ 0% + Branches + 0/2 +
+ + +
+ 0% + Functions + 0/14 +
+ + +
+ 13.79% + Lines + 4/29 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +785x +  +  +5x +  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { ExtendedVersion } from "../../exver"
+ 
+import * as T from "../../types"
+import { once } from "../../util/once"
+import { Migration } from "./Migration"
+ 
+export class Migrations<Manifest extends T.Manifest, Store> {
+  private constructor(
+    readonly manifest: T.Manifest,
+    readonly migrations: Array<Migration<Manifest, Store, any>>,
+  ) {}
+  private sortedMigrations = once(() => {
+    const migrationsAsVersions = (
+      this.migrations as Array<Migration<Manifest, Store, any>>
+    )
+      .map((x) => [ExtendedVersion.parse(x.options.version), x] as const)
+      .filter(([v, _]) => v.flavor === this.currentVersion().flavor)
+    migrationsAsVersions.sort((a, b) => a[0].compareForSort(b[0]))
+    return migrationsAsVersions
+  })
+  private currentVersion = once(() =>
+    ExtendedVersion.parse(this.manifest.version),
+  )
+  static of<
+    Manifest extends T.Manifest,
+    Store,
+    Migrations extends Array<Migration<Manifest, Store, any>>,
+  >(manifest: T.Manifest, ...migrations: EnsureUniqueId<Migrations>) {
+    return new Migrations(
+      manifest,
+      migrations as Array<Migration<Manifest, Store, any>>,
+    )
+  }
+  async init({
+    effects,
+    previousVersion,
+  }: Parameters<T.ExpectedExports.init>[0]) {
+    Iif (!!previousVersion) {
+      const previousVersionExVer = ExtendedVersion.parse(previousVersion)
+      for (const [_, migration] of this.sortedMigrations()
+        .filter((x) => x[0].greaterThan(previousVersionExVer))
+        .filter((x) => x[0].lessThanOrEqual(this.currentVersion()))) {
+        await migration.up({ effects })
+      }
+    }
+  }
+  async uninit({
+    effects,
+    nextVersion,
+  }: Parameters<T.ExpectedExports.uninit>[0]) {
+    Iif (!!nextVersion) {
+      const nextVersionExVer = ExtendedVersion.parse(nextVersion)
+      const reversed = [...this.sortedMigrations()].reverse()
+      for (const [_, migration] of reversed
+        .filter((x) => x[0].greaterThan(nextVersionExVer))
+        .filter((x) => x[0].lessThanOrEqual(this.currentVersion()))) {
+        await migration.down({ effects })
+      }
+    }
+  }
+}
+ 
+export function setupMigrations<
+  Manifest extends T.Manifest,
+  Store,
+  Migrations extends Array<Migration<Manifest, Store, any>>,
+>(manifest: T.Manifest, ...migrations: EnsureUniqueId<Migrations>) {
+  return Migrations.of<Manifest, Store, Migrations>(manifest, ...migrations)
+}
+ 
+// prettier-ignore
+export type EnsureUniqueId<A, B = A, ids = never> =
+  B extends [] ? A : 
+  B extends [Migration<any, any, infer id>, ...infer Rest] ? (
+    id extends ids ? "One of the ids are not unique"[] :
+    EnsureUniqueId<A, Rest, id | ids>
+  ) : "There exists a migration that is not a Migration"[]
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/inits/setupInit.ts.html b/sdk/lib/coverage/lcov-report/lib/inits/setupInit.ts.html new file mode 100644 index 000000000..b6e36480a --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/inits/setupInit.ts.html @@ -0,0 +1,271 @@ + + + + + + Code coverage report for lib/inits/setupInit.ts + + + + + + + + + +
+
+

All files / lib/inits setupInit.ts

+
+ +
+ 12.5% + Statements + 2/16 +
+ + +
+ 0% + Branches + 0/5 +
+ + +
+ 0% + Functions + 0/3 +
+ + +
+ 12.5% + Lines + 2/16 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63  +5x +  +  +  +  +  +  +  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { DependenciesReceipt } from "../config/setupConfig"
+import { ExtendedVersion, VersionRange } from "../exver"
+import { SetInterfaces } from "../interfaces/setupInterfaces"
+ 
+import { ExposedStorePaths } from "../store/setupExposeStore"
+import * as T from "../types"
+import { VersionGraph } from "../version/VersionGraph"
+import { Install } from "./setupInstall"
+import { Uninstall } from "./setupUninstall"
+ 
+export function setupInit<Manifest extends T.Manifest, Store>(
+  versions: VersionGraph<Manifest["version"]>,
+  install: Install<Manifest, Store>,
+  uninstall: Uninstall<Manifest, Store>,
+  setInterfaces: SetInterfaces<Manifest, Store, any, any>,
+  setDependencies: (options: {
+    effects: T.Effects
+    input: any
+  }) => Promise<DependenciesReceipt>,
+  exposedStore: ExposedStorePaths,
+): {
+  init: T.ExpectedExports.init
+  uninit: T.ExpectedExports.uninit
+} {
+  return {
+    init: async (opts) => {
+      const prev = await opts.effects.getDataVersion()
+      if (prev) {
+        await versions.migrate({
+          effects: opts.effects,
+          from: ExtendedVersion.parse(prev),
+          to: versions.currentVersion(),
+        })
+      } else {
+        await install.install(opts)
+        await opts.effects.setDataVersion({
+          version: versions.current.options.version,
+        })
+      }
+      await setInterfaces({
+        ...opts,
+        input: null,
+      })
+      await opts.effects.exposeForDependents({ paths: exposedStore })
+      await setDependencies({ effects: opts.effects, input: null })
+    },
+    uninit: async (opts) => {
+      if (opts.nextVersion) {
+        const prev = await opts.effects.getDataVersion()
+        Iif (prev) {
+          await versions.migrate({
+            effects: opts.effects,
+            from: ExtendedVersion.parse(prev),
+            to: ExtendedVersion.parse(opts.nextVersion),
+          })
+        }
+      } else {
+        await uninstall.uninstall(opts)
+      }
+    },
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/inits/setupInstall.ts.html b/sdk/lib/coverage/lcov-report/lib/inits/setupInstall.ts.html new file mode 100644 index 000000000..c9cb7c726 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/inits/setupInstall.ts.html @@ -0,0 +1,160 @@ + + + + + + Code coverage report for lib/inits/setupInstall.ts + + + + + + + + + +
+
+

All files / lib/inits setupInstall.ts

+
+ +
+ 33.33% + Statements + 2/6 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 0% + Functions + 0/4 +
+ + +
+ 33.33% + Lines + 2/6 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26  +  +  +  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +5x +  +  +  +  + 
import * as T from "../types"
+ 
+export type InstallFn<Manifest extends T.Manifest, Store> = (opts: {
+  effects: T.Effects
+}) => Promise<void>
+export class Install<Manifest extends T.Manifest, Store> {
+  private constructor(readonly fn: InstallFn<Manifest, Store>) {}
+  static of<Manifest extends T.Manifest, Store>(
+    fn: InstallFn<Manifest, Store>,
+  ) {
+    return new Install(fn)
+  }
+ 
+  async install({ effects }: Parameters<T.ExpectedExports.init>[0]) {
+    await this.fn({
+      effects,
+    })
+  }
+}
+ 
+export function setupInstall<Manifest extends T.Manifest, Store>(
+  fn: InstallFn<Manifest, Store>,
+) {
+  return Install.of(fn)
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/inits/setupUninstall.ts.html b/sdk/lib/coverage/lcov-report/lib/inits/setupUninstall.ts.html new file mode 100644 index 000000000..f5387733a --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/inits/setupUninstall.ts.html @@ -0,0 +1,172 @@ + + + + + + Code coverage report for lib/inits/setupUninstall.ts + + + + + + + + + +
+
+

All files / lib/inits setupUninstall.ts

+
+ +
+ 28.57% + Statements + 2/7 +
+ + +
+ 0% + Branches + 0/1 +
+ + +
+ 0% + Functions + 0/4 +
+ + +
+ 28.57% + Lines + 2/7 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30  +  +  +  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +5x +  +  +  +  + 
import * as T from "../types"
+ 
+export type UninstallFn<Manifest extends T.Manifest, Store> = (opts: {
+  effects: T.Effects
+}) => Promise<void>
+export class Uninstall<Manifest extends T.Manifest, Store> {
+  private constructor(readonly fn: UninstallFn<Manifest, Store>) {}
+  static of<Manifest extends T.Manifest, Store>(
+    fn: UninstallFn<Manifest, Store>,
+  ) {
+    return new Uninstall(fn)
+  }
+ 
+  async uninstall({
+    effects,
+    nextVersion,
+  }: Parameters<T.ExpectedExports.uninit>[0]) {
+    Iif (!nextVersion)
+      await this.fn({
+        effects,
+      })
+  }
+}
+ 
+export function setupUninstall<Manifest extends T.Manifest, Store>(
+  fn: UninstallFn<Manifest, Store>,
+) {
+  return Uninstall.of(fn)
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/interfaces/Host.ts.html b/sdk/lib/coverage/lcov-report/lib/interfaces/Host.ts.html new file mode 100644 index 000000000..83c7dcb5a --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/interfaces/Host.ts.html @@ -0,0 +1,667 @@ + + + + + + Code coverage report for lib/interfaces/Host.ts + + + + + + + + + +
+
+

All files / lib/interfaces Host.ts

+
+ +
+ 22.22% + Statements + 6/27 +
+ + +
+ 0% + Branches + 0/18 +
+ + +
+ 0% + Functions + 0/7 +
+ + +
+ 24% + Lines + 6/25 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +1956x +  +6x +  +  +  +  +  +  +  +6x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +6x +  +  +  +6x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +6x +  +  +  +  + 
import { number, object, string } from "ts-matches"
+import { Effects } from "../types"
+import { Origin } from "./Origin"
+import { AddSslOptions, BindParams } from ".././osBindings"
+import { Security } from ".././osBindings"
+import { BindOptions } from ".././osBindings"
+import { AlpnInfo } from ".././osBindings"
+ 
+export { AddSslOptions, Security, BindOptions }
+ 
+export const knownProtocols = {
+  http: {
+    secure: null,
+    defaultPort: 80,
+    withSsl: "https",
+    alpn: { specified: ["http/1.1"] } as AlpnInfo,
+  },
+  https: {
+    secure: { ssl: true },
+    defaultPort: 443,
+  },
+  ws: {
+    secure: null,
+    defaultPort: 80,
+    withSsl: "wss",
+    alpn: { specified: ["http/1.1"] } as AlpnInfo,
+  },
+  wss: {
+    secure: { ssl: true },
+    defaultPort: 443,
+  },
+  ssh: {
+    secure: { ssl: false },
+    defaultPort: 22,
+  },
+  bitcoin: {
+    secure: { ssl: false },
+    defaultPort: 8333,
+  },
+  lightning: {
+    secure: { ssl: true },
+    defaultPort: 9735,
+  },
+  grpc: {
+    secure: { ssl: true },
+    defaultPort: 50051,
+  },
+  dns: {
+    secure: { ssl: false },
+    defaultPort: 53,
+  },
+} as const
+ 
+export type Scheme = string | null
+ 
+type KnownProtocols = typeof knownProtocols
+type ProtocolsWithSslVariants = {
+  [K in keyof KnownProtocols]: KnownProtocols[K] extends {
+    withSsl: string
+  }
+    ? K
+    : never
+}[keyof KnownProtocols]
+type NotProtocolsWithSslVariants = Exclude<
+  keyof KnownProtocols,
+  ProtocolsWithSslVariants
+>
+ 
+type BindOptionsByKnownProtocol =
+  | {
+      protocol: ProtocolsWithSslVariants
+      preferredExternalPort?: number
+      addSsl?: Partial<AddSslOptions>
+    }
+  | {
+      protocol: NotProtocolsWithSslVariants
+      preferredExternalPort?: number
+      addSsl?: AddSslOptions
+    }
+export type BindOptionsByProtocol = BindOptionsByKnownProtocol | BindOptions
+ 
+export type HostKind = BindParams["kind"]
+ 
+const hasStringProtocol = object({
+  protocol: string,
+}).test
+ 
+export class Host {
+  constructor(
+    readonly options: {
+      effects: Effects
+      kind: HostKind
+      id: string
+    },
+  ) {}
+ 
+  async bindPort(
+    internalPort: number,
+    options: BindOptionsByProtocol,
+  ): Promise<Origin<this>> {
+    if (hasStringProtocol(options)) {
+      return await this.bindPortForKnown(options, internalPort)
+    } else {
+      return await this.bindPortForUnknown(internalPort, options)
+    }
+  }
+ 
+  private async bindPortForUnknown(
+    internalPort: number,
+    options: {
+      preferredExternalPort: number
+      addSsl: AddSslOptions | null
+      secure: { ssl: boolean } | null
+    },
+  ) {
+    const binderOptions = {
+      kind: this.options.kind,
+      id: this.options.id,
+      internalPort,
+      ...options,
+    }
+    await this.options.effects.bind(binderOptions)
+ 
+    return new Origin(this, internalPort, null, null)
+  }
+ 
+  private async bindPortForKnown(
+    options: BindOptionsByKnownProtocol,
+    internalPort: number,
+  ) {
+    const protoInfo = knownProtocols[options.protocol]
+    const preferredExternalPort =
+      options.preferredExternalPort ||
+      knownProtocols[options.protocol].defaultPort
+    const sslProto = this.getSslProto(options, protoInfo)
+    const addSsl =
+      sslProto && "alpn" in protoInfo
+        ? {
+            // addXForwardedHeaders: null,
+            preferredExternalPort: knownProtocols[sslProto].defaultPort,
+            scheme: sslProto,
+            alpn: protoInfo.alpn,
+            ...("addSsl" in options ? options.addSsl : null),
+          }
+        : null
+ 
+    const secure: Security | null = !protoInfo.secure ? null : { ssl: false }
+ 
+    await this.options.effects.bind({
+      kind: this.options.kind,
+      id: this.options.id,
+      internalPort,
+      preferredExternalPort,
+      addSsl,
+      secure,
+    })
+ 
+    return new Origin(this, internalPort, options.protocol, sslProto)
+  }
+ 
+  private getSslProto(
+    options: BindOptionsByKnownProtocol,
+    protoInfo: KnownProtocols[keyof KnownProtocols],
+  ) {
+    Iif (inObject("noAddSsl", options) && options.noAddSsl) return null
+    Iif ("withSsl" in protoInfo && protoInfo.withSsl) return protoInfo.withSsl
+    return null
+  }
+}
+ 
+function inObject<Key extends string>(
+  key: Key,
+  obj: any,
+): obj is { [K in Key]: unknown } {
+  return key in obj
+}
+ 
+// export class StaticHost extends Host {
+//   constructor(options: { effects: Effects; id: string }) {
+//     super({ ...options, kind: "static" })
+//   }
+// }
+ 
+// export class SingleHost extends Host {
+//   constructor(options: { effects: Effects; id: string }) {
+//     super({ ...options, kind: "single" })
+//   }
+// }
+ 
+export class MultiHost extends Host {
+  constructor(options: { effects: Effects; id: string }) {
+    super({ ...options, kind: "multi" })
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/interfaces/Origin.ts.html b/sdk/lib/coverage/lcov-report/lib/interfaces/Origin.ts.html new file mode 100644 index 000000000..fea1143c5 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/interfaces/Origin.ts.html @@ -0,0 +1,349 @@ + + + + + + Code coverage report for lib/interfaces/Origin.ts + + + + + + + + + +
+
+

All files / lib/interfaces Origin.ts

+
+ +
+ 6.25% + Statements + 1/16 +
+ + +
+ 0% + Branches + 0/6 +
+ + +
+ 0% + Functions + 0/4 +
+ + +
+ 6.25% + Lines + 1/16 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89  +  +  +  +  +6x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { AddressInfo } from "../types"
+import { AddressReceipt } from "./AddressReceipt"
+import { Host, BindOptions, Scheme } from "./Host"
+import { ServiceInterfaceBuilder } from "./ServiceInterfaceBuilder"
+ 
+export class Origin<T extends Host> {
+  constructor(
+    readonly host: T,
+    readonly internalPort: number,
+    readonly scheme: string | null,
+    readonly sslScheme: string | null,
+  ) {}
+ 
+  build({ username, path, search, schemeOverride }: BuildOptions): AddressInfo {
+    const qpEntries = Object.entries(search)
+      .map(
+        ([key, val]) => `${encodeURIComponent(key)}=${encodeURIComponent(val)}`,
+      )
+      .join("&")
+ 
+    const qp = qpEntries.length ? `?${qpEntries}` : ""
+ 
+    return {
+      hostId: this.host.options.id,
+      internalPort: this.internalPort,
+      scheme: schemeOverride ? schemeOverride.noSsl : this.scheme,
+      sslScheme: schemeOverride ? schemeOverride.ssl : this.sslScheme,
+      suffix: `${path}${qp}`,
+      username,
+    }
+  }
+ 
+  /**
+   * A function to register a group of origins (<PROTOCOL> :// <HOSTNAME> : <PORT>) with StartOS
+   *
+   * The returned addressReceipt serves as proof that the addresses were registered
+   *
+   * @param addressInfo
+   * @returns
+   */
+  async export(
+    serviceInterfaces: ServiceInterfaceBuilder[],
+  ): Promise<AddressInfo[] & AddressReceipt> {
+    const addressesInfo = []
+    for (let serviceInterface of serviceInterfaces) {
+      const {
+        name,
+        description,
+        hasPrimary,
+        id,
+        type,
+        username,
+        path,
+        search,
+        schemeOverride,
+        masked,
+      } = serviceInterface.options
+ 
+      const addressInfo = this.build({
+        username,
+        path,
+        search,
+        schemeOverride,
+      })
+ 
+      await serviceInterface.options.effects.exportServiceInterface({
+        id,
+        name,
+        description,
+        hasPrimary,
+        addressInfo,
+        type,
+        masked,
+      })
+ 
+      addressesInfo.push(addressInfo)
+    }
+ 
+    return addressesInfo as AddressInfo[] & AddressReceipt
+  }
+}
+ 
+type BuildOptions = {
+  schemeOverride: { ssl: Scheme; noSsl: Scheme } | null
+  username: string | null
+  path: string
+  search: Record<string, string>
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/interfaces/ServiceInterfaceBuilder.ts.html b/sdk/lib/coverage/lcov-report/lib/interfaces/ServiceInterfaceBuilder.ts.html new file mode 100644 index 000000000..3d29c5646 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/interfaces/ServiceInterfaceBuilder.ts.html @@ -0,0 +1,181 @@ + + + + + + Code coverage report for lib/interfaces/ServiceInterfaceBuilder.ts + + + + + + + + + +
+
+

All files / lib/interfaces ServiceInterfaceBuilder.ts

+
+ +
+ 50% + Statements + 1/2 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 50% + Lines + 1/2 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { ServiceInterfaceType } from "../StartSdk"
+import { Effects } from "../types"
+import { Scheme } from "./Host"
+ 
+/**
+ * A helper class for creating a Network Interface
+ *
+ * Network Interfaces are collections of web addresses that expose the same API or other resource,
+ * display to the user with under a common name and description.
+ *
+ * All URIs on an interface inherit the same ui: bool, basic auth credentials, path, and search (query) params
+ *
+ * @param options
+ * @returns
+ */
+export class ServiceInterfaceBuilder {
+  constructor(
+    readonly options: {
+      effects: Effects
+      name: string
+      id: string
+      description: string
+      hasPrimary: boolean
+      type: ServiceInterfaceType
+      username: string | null
+      path: string
+      search: Record<string, string>
+      schemeOverride: { ssl: Scheme; noSsl: Scheme } | null
+      masked: boolean
+    },
+  ) {}
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/interfaces/index.html b/sdk/lib/coverage/lcov-report/lib/interfaces/index.html new file mode 100644 index 000000000..e972f08e7 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/interfaces/index.html @@ -0,0 +1,161 @@ + + + + + + Code coverage report for lib/interfaces + + + + + + + + + +
+
+

All files lib/interfaces

+
+ +
+ 22.44% + Statements + 11/49 +
+ + +
+ 0% + Branches + 0/24 +
+ + +
+ 0% + Functions + 0/13 +
+ + +
+ 22.22% + Lines + 10/45 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
Host.ts +
+
22.22%6/270%0/180%0/724%6/25
Origin.ts +
+
6.25%1/160%0/60%0/46.25%1/16
ServiceInterfaceBuilder.ts +
+
50%1/2100%0/00%0/150%1/2
setupInterfaces.ts +
+
75%3/4100%0/00%0/1100%2/2
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/interfaces/setupInterfaces.ts.html b/sdk/lib/coverage/lcov-report/lib/interfaces/setupInterfaces.ts.html new file mode 100644 index 000000000..9afc20f5f --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/interfaces/setupInterfaces.ts.html @@ -0,0 +1,154 @@ + + + + + + Code coverage report for lib/interfaces/setupInterfaces.ts + + + + + + + + + +
+
+

All files / lib/interfaces setupInterfaces.ts

+
+ +
+ 75% + Statements + 3/4 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 100% + Lines + 2/2 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +5x +5x + 
import { Config } from "../config/builder/config"
+ 
+import * as T from "../types"
+import { AddressReceipt } from "./AddressReceipt"
+ 
+export type InterfacesReceipt = Array<T.AddressInfo[] & AddressReceipt>
+export type SetInterfaces<
+  Manifest extends T.Manifest,
+  Store,
+  ConfigInput extends Record<string, any>,
+  Output extends InterfacesReceipt,
+> = (opts: { effects: T.Effects; input: null | ConfigInput }) => Promise<Output>
+export type SetupInterfaces = <
+  Manifest extends T.Manifest,
+  Store,
+  ConfigInput extends Record<string, any>,
+  Output extends InterfacesReceipt,
+>(
+  config: Config<ConfigInput, Store>,
+  fn: SetInterfaces<Manifest, Store, ConfigInput, Output>,
+) => SetInterfaces<Manifest, Store, ConfigInput, Output>
+export const NO_INTERFACE_CHANGES = [] as InterfacesReceipt
+export const setupInterfaces: SetupInterfaces = (_config, fn) => fn
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/mainFn/CommandController.ts.html b/sdk/lib/coverage/lcov-report/lib/mainFn/CommandController.ts.html new file mode 100644 index 000000000..215681b74 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/mainFn/CommandController.ts.html @@ -0,0 +1,502 @@ + + + + + + Code coverage report for lib/mainFn/CommandController.ts + + + + + + + + + +
+
+

All files / lib/mainFn CommandController.ts

+
+ +
+ 10.41% + Statements + 5/48 +
+ + +
+ 0% + Branches + 0/24 +
+ + +
+ 0% + Functions + 0/12 +
+ + +
+ 10.41% + Lines + 5/48 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +1405x +5x +  +  +  +5x +  +  +  +  +  +5x +  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { DEFAULT_SIGTERM_TIMEOUT } from "."
+import { NO_TIMEOUT, SIGKILL, SIGTERM } from "../StartSdk"
+ 
+import * as T from "../types"
+import { asError } from "../util/asError"
+import {
+  ExecSpawnable,
+  MountOptions,
+  SubContainerHandle,
+  SubContainer,
+} from "../util/SubContainer"
+import { splitCommand } from "../util/splitCommand"
+import * as cp from "child_process"
+ 
+export class CommandController {
+  private constructor(
+    readonly runningAnswer: Promise<unknown>,
+    private state: { exited: boolean },
+    private readonly subcontainer: SubContainer,
+    private process: cp.ChildProcessWithoutNullStreams,
+    readonly sigtermTimeout: number = DEFAULT_SIGTERM_TIMEOUT,
+  ) {}
+  static of<Manifest extends T.Manifest>() {
+    return async <A extends string>(
+      effects: T.Effects,
+      subcontainer:
+        | {
+            id: keyof Manifest["images"] & T.ImageId
+            sharedRun?: boolean
+          }
+        | SubContainer,
+      command: T.CommandType,
+      options: {
+        // Defaults to the DEFAULT_SIGTERM_TIMEOUT = 30_000ms
+        sigtermTimeout?: number
+        mounts?: { path: string; options: MountOptions }[]
+        runAsInit?: boolean
+        env?:
+          | {
+              [variable: string]: string
+            }
+          | undefined
+        cwd?: string | undefined
+        user?: string | undefined
+        onStdout?: (x: Buffer) => void
+        onStderr?: (x: Buffer) => void
+      },
+    ) => {
+      const commands = splitCommand(command)
+      const subc =
+        subcontainer instanceof SubContainer
+          ? subcontainer
+          : await (async () => {
+              const subc = await SubContainer.of(effects, subcontainer)
+              for (let mount of options.mounts || []) {
+                await subc.mount(mount.options, mount.path)
+              }
+              return subc
+            })()
+      let childProcess: cp.ChildProcessWithoutNullStreams
+      if (options.runAsInit) {
+        childProcess = await subc.launch(commands, {
+          env: options.env,
+        })
+      } else {
+        childProcess = await subc.spawn(commands, {
+          env: options.env,
+        })
+      }
+      const state = { exited: false }
+      const answer = new Promise<null>((resolve, reject) => {
+        childProcess.on("exit", (code) => {
+          state.exited = true
+          Iif (
+            code === 0 ||
+            code === 143 ||
+            (code === null && childProcess.signalCode == "SIGTERM")
+          ) {
+            return resolve(null)
+          }
+          if (code) {
+            return reject(new Error(`${commands[0]} exited with code ${code}`))
+          } else {
+            return reject(
+              new Error(
+                `${commands[0]} exited with signal ${childProcess.signalCode}`,
+              ),
+            )
+          }
+        })
+      })
+ 
+      return new CommandController(
+        answer,
+        state,
+        subc,
+        childProcess,
+        options.sigtermTimeout,
+      )
+    }
+  }
+  get subContainerHandle() {
+    return new SubContainerHandle(this.subcontainer)
+  }
+  async wait({ timeout = NO_TIMEOUT } = {}) {
+    Iif (timeout > 0)
+      setTimeout(() => {
+        this.term()
+      }, timeout)
+    try {
+      return await this.runningAnswer
+    } finally {
+      Iif (!this.state.exited) {
+        this.process.kill("SIGKILL")
+      }
+      await this.subcontainer.destroy?.().catch((_) => {})
+    }
+  }
+  async term({ signal = SIGTERM, timeout = this.sigtermTimeout } = {}) {
+    try {
+      Iif (!this.state.exited) {
+        Iif (!this.process.kill(signal)) {
+          console.error(
+            `failed to send signal ${signal} to pid ${this.process.pid}`,
+          )
+        }
+      }
+ 
+      Iif (signal !== "SIGKILL") {
+        setTimeout(() => {
+          this.process.kill("SIGKILL")
+        }, timeout)
+      }
+      await this.runningAnswer
+    } finally {
+      await this.subcontainer.destroy?.()
+    }
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/mainFn/Daemon.ts.html b/sdk/lib/coverage/lcov-report/lib/mainFn/Daemon.ts.html new file mode 100644 index 000000000..9d1c93d9e --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/mainFn/Daemon.ts.html @@ -0,0 +1,349 @@ + + + + + + Code coverage report for lib/mainFn/Daemon.ts + + + + + + + + + +
+
+

All files / lib/mainFn Daemon.ts

+
+ +
+ 15.62% + Statements + 5/32 +
+ + +
+ 0% + Branches + 0/1 +
+ + +
+ 0% + Functions + 0/13 +
+ + +
+ 16.66% + Lines + 5/30 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89  +5x +  +5x +  +5x +5x +  +  +  +  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import * as T from "../types"
+import { asError } from "../util/asError"
+import { ExecSpawnable, MountOptions, SubContainer } from "../util/SubContainer"
+import { CommandController } from "./CommandController"
+ 
+const TIMEOUT_INCREMENT_MS = 1000
+const MAX_TIMEOUT_MS = 30000
+/**
+ * This is a wrapper around CommandController that has a state of off, where the command shouldn't be running
+ * and the others state of running, where it will keep a living running command
+ */
+ 
+export class Daemon {
+  private commandController: CommandController | null = null
+  private shouldBeRunning = false
+  constructor(private startCommand: () => Promise<CommandController>) {}
+  get subContainerHandle(): undefined | ExecSpawnable {
+    return this.commandController?.subContainerHandle
+  }
+  static of<Manifest extends T.Manifest>() {
+    return async <A extends string>(
+      effects: T.Effects,
+      subcontainer:
+        | {
+            id: keyof Manifest["images"] & T.ImageId
+            sharedRun?: boolean
+          }
+        | SubContainer,
+      command: T.CommandType,
+      options: {
+        mounts?: { path: string; options: MountOptions }[]
+        env?:
+          | {
+              [variable: string]: string
+            }
+          | undefined
+        cwd?: string | undefined
+        user?: string | undefined
+        onStdout?: (x: Buffer) => void
+        onStderr?: (x: Buffer) => void
+        sigtermTimeout?: number
+      },
+    ) => {
+      const startCommand = () =>
+        CommandController.of<Manifest>()(
+          effects,
+          subcontainer,
+          command,
+          options,
+        )
+      return new Daemon(startCommand)
+    }
+  }
+  async start() {
+    Iif (this.commandController) {
+      return
+    }
+    this.shouldBeRunning = true
+    let timeoutCounter = 0
+    new Promise(async () => {
+      while (this.shouldBeRunning) {
+        this.commandController = await this.startCommand()
+        await this.commandController.wait().catch((err) => console.error(err))
+        await new Promise((resolve) => setTimeout(resolve, timeoutCounter))
+        timeoutCounter += TIMEOUT_INCREMENT_MS
+        timeoutCounter = Math.max(MAX_TIMEOUT_MS, timeoutCounter)
+      }
+    }).catch((err) => {
+      console.error(asError(err))
+    })
+  }
+  async term(termOptions?: {
+    signal?: NodeJS.Signals | undefined
+    timeout?: number | undefined
+  }) {
+    return this.stop(termOptions)
+  }
+  async stop(termOptions?: {
+    signal?: NodeJS.Signals | undefined
+    timeout?: number | undefined
+  }) {
+    this.shouldBeRunning = false
+    await this.commandController
+      ?.term({ ...termOptions })
+      .catch((e) => console.error(asError(e)))
+    this.commandController = null
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/mainFn/Daemons.ts.html b/sdk/lib/coverage/lcov-report/lib/mainFn/Daemons.ts.html new file mode 100644 index 000000000..673d32a99 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/mainFn/Daemons.ts.html @@ -0,0 +1,616 @@ + + + + + + Code coverage report for lib/mainFn/Daemons.ts + + + + + + + + + +
+
+

All files / lib/mainFn Daemons.ts

+
+ +
+ 31.81% + Statements + 14/44 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 0% + Functions + 0/16 +
+ + +
+ 28.94% + Lines + 11/38 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +5x +5x +  +5x +5x +5x +5x +5x +  +5x +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { NO_TIMEOUT, SIGKILL, SIGTERM, Signals } from "../StartSdk"
+import { HealthReceipt } from "../health/HealthReceipt"
+import { HealthCheckResult } from "../health/checkFns"
+ 
+import { Trigger } from "../trigger"
+import { TriggerInput } from "../trigger/TriggerInput"
+import { defaultTrigger } from "../trigger/defaultTrigger"
+import * as T from "../types"
+import { Mounts } from "./Mounts"
+import {
+  CommandOptions,
+  ExecSpawnable,
+  MountOptions,
+  SubContainer,
+} from "../util/SubContainer"
+import { splitCommand } from "../util/splitCommand"
+ 
+import { promisify } from "node:util"
+import * as CP from "node:child_process"
+ 
+export { Daemon } from "./Daemon"
+export { CommandController } from "./CommandController"
+import { HealthDaemon } from "./HealthDaemon"
+import { Daemon } from "./Daemon"
+import { CommandController } from "./CommandController"
+ 
+export const cpExec = promisify(CP.exec)
+export const cpExecFile = promisify(CP.execFile)
+export type Ready = {
+  display: string | null
+  fn: (
+    spawnable: ExecSpawnable,
+  ) => Promise<HealthCheckResult> | HealthCheckResult
+  trigger?: Trigger
+}
+ 
+type DaemonsParams<
+  Manifest extends T.Manifest,
+  Ids extends string,
+  Command extends string,
+  Id extends string,
+> = {
+  command: T.CommandType
+  image: { id: keyof Manifest["images"] & T.ImageId; sharedRun?: boolean }
+  mounts: Mounts<Manifest>
+  env?: Record<string, string>
+  ready: Ready
+  requires: Exclude<Ids, Id>[]
+  sigtermTimeout?: number
+}
+ 
+type ErrorDuplicateId<Id extends string> = `The id '${Id}' is already used`
+ 
+export const runCommand = <Manifest extends T.Manifest>() =>
+  CommandController.of<Manifest>()
+ 
+/**
+ * A class for defining and controlling the service daemons
+```ts
+Daemons.of({
+  effects,
+  started,
+  interfaceReceipt, // Provide the interfaceReceipt to prove it was completed
+  healthReceipts, // Provide the healthReceipts or [] to prove they were at least considered
+}).addDaemon('webui', {
+  command: 'hello-world', // The command to start the daemon
+  ready: {
+    display: 'Web Interface',
+    // The function to run to determine the health status of the daemon
+    fn: () =>
+      checkPortListening(effects, 80, {
+        successMessage: 'The web interface is ready',
+        errorMessage: 'The web interface is not ready',
+      }),
+  },
+  requires: [],
+})
+```
+ */
+export class Daemons<Manifest extends T.Manifest, Ids extends string> {
+  private constructor(
+    readonly effects: T.Effects,
+    readonly started: (onTerm: () => PromiseLike<void>) => PromiseLike<void>,
+    readonly daemons: Promise<Daemon>[],
+    readonly ids: Ids[],
+    readonly healthDaemons: HealthDaemon[],
+  ) {}
+  /**
+   * Returns an empty new Daemons class with the provided config.
+   *
+   * Call .addDaemon() on the returned class to add a daemon.
+   *
+   * Daemons run in the order they are defined, with latter daemons being capable of
+   * depending on prior daemons
+   * @param config
+   * @returns
+   */
+  static of<Manifest extends T.Manifest>(config: {
+    effects: T.Effects
+    started: (onTerm: () => PromiseLike<void>) => PromiseLike<void>
+    healthReceipts: HealthReceipt[]
+  }) {
+    return new Daemons<Manifest, never>(
+      config.effects,
+      config.started,
+      [],
+      [],
+      [],
+    )
+  }
+  /**
+   * Returns the complete list of daemons, including the one defined here
+   * @param id
+   * @param newDaemon
+   * @returns
+   */
+  addDaemon<Id extends string, Command extends string>(
+    // prettier-ignore
+    id: 
+      "" extends Id ? never :
+      ErrorDuplicateId<Id> extends Id ? never :
+      Id extends Ids ? ErrorDuplicateId<Id> :
+      Id,
+    options: DaemonsParams<Manifest, Ids, Command, Id>,
+  ) {
+    const daemonIndex = this.daemons.length
+    const daemon = Daemon.of()(this.effects, options.image, options.command, {
+      ...options,
+      mounts: options.mounts.build(),
+    })
+    const healthDaemon = new HealthDaemon(
+      daemon,
+      daemonIndex,
+      options.requires
+        .map((x) => this.ids.indexOf(id as any))
+        .filter((x) => x >= 0)
+        .map((id) => this.healthDaemons[id]),
+      id,
+      this.ids,
+      options.ready,
+      this.effects,
+      options.sigtermTimeout,
+    )
+    const daemons = this.daemons.concat(daemon)
+    const ids = [...this.ids, id] as (Ids | Id)[]
+    const healthDaemons = [...this.healthDaemons, healthDaemon]
+    return new Daemons<Manifest, Ids | Id>(
+      this.effects,
+      this.started,
+      daemons,
+      ids,
+      healthDaemons,
+    )
+  }
+ 
+  async build() {
+    this.updateMainHealth()
+    this.healthDaemons.forEach((x) =>
+      x.addWatcher(() => this.updateMainHealth()),
+    )
+    const built = {
+      term: async (options?: { signal?: Signals; timeout?: number }) => {
+        try {
+          await Promise.all(this.healthDaemons.map((x) => x.term(options)))
+        } finally {
+          this.effects.setMainStatus({ status: "stopped" })
+        }
+      },
+    }
+    this.started(() => built.term())
+    return built
+  }
+ 
+  private updateMainHealth() {
+    this.effects.setMainStatus({ status: "running" })
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/mainFn/HealthDaemon.ts.html b/sdk/lib/coverage/lcov-report/lib/mainFn/HealthDaemon.ts.html new file mode 100644 index 000000000..d90838f26 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/mainFn/HealthDaemon.ts.html @@ -0,0 +1,535 @@ + + + + + + Code coverage report for lib/mainFn/HealthDaemon.ts + + + + + + + + + +
+
+

All files / lib/mainFn HealthDaemon.ts

+
+ +
+ 6.94% + Statements + 5/72 +
+ + +
+ 0% + Branches + 0/12 +
+ + +
+ 0% + Functions + 0/22 +
+ + +
+ 7.81% + Lines + 5/64 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151  +5x +  +  +  +5x +5x +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { HealthCheckResult } from "../health/checkFns"
+import { defaultTrigger } from "../trigger/defaultTrigger"
+import { Ready } from "./Daemons"
+import { Daemon } from "./Daemon"
+import { Effects, SetHealth } from "../types"
+import { DEFAULT_SIGTERM_TIMEOUT } from "."
+import { asError } from "../util/asError"
+ 
+const oncePromise = <T>() => {
+  let resolve: (value: T) => void
+  const promise = new Promise<T>((res) => {
+    resolve = res
+  })
+  return { resolve: resolve!, promise }
+}
+ 
+/**
+ * Wanted a structure that deals with controlling daemons by their health status
+ * States:
+ * -- Waiting for dependencies to be success
+ * -- Running: Daemon is running and the status is in the health
+ *
+ */
+export class HealthDaemon {
+  private _health: HealthCheckResult = { result: "starting", message: null }
+  private healthWatchers: Array<() => unknown> = []
+  private running = false
+  constructor(
+    private readonly daemon: Promise<Daemon>,
+    readonly daemonIndex: number,
+    private readonly dependencies: HealthDaemon[],
+    readonly id: string,
+    readonly ids: string[],
+    readonly ready: Ready,
+    readonly effects: Effects,
+    readonly sigtermTimeout: number = DEFAULT_SIGTERM_TIMEOUT,
+  ) {
+    this.updateStatus()
+    this.dependencies.forEach((d) => d.addWatcher(() => this.updateStatus()))
+  }
+ 
+  /** Run after we want to do cleanup */
+  async term(termOptions?: {
+    signal?: NodeJS.Signals | undefined
+    timeout?: number | undefined
+  }) {
+    this.healthWatchers = []
+    this.running = false
+    this.healthCheckCleanup?.()
+ 
+    await this.daemon.then((d) =>
+      d.term({
+        timeout: this.sigtermTimeout,
+        ...termOptions,
+      }),
+    )
+  }
+ 
+  /** Want to add another notifier that the health might have changed */
+  addWatcher(watcher: () => unknown) {
+    this.healthWatchers.push(watcher)
+  }
+ 
+  get health() {
+    return Object.freeze(this._health)
+  }
+ 
+  private async changeRunning(newStatus: boolean) {
+    Iif (this.running === newStatus) return
+ 
+    this.running = newStatus
+ 
+    if (newStatus) {
+      ;(await this.daemon).start()
+      this.setupHealthCheck()
+    } else {
+      ;(await this.daemon).stop()
+      this.turnOffHealthCheck()
+ 
+      this.setHealth({ result: "starting", message: null })
+    }
+  }
+ 
+  private healthCheckCleanup: (() => void) | null = null
+  private turnOffHealthCheck() {
+    this.healthCheckCleanup?.()
+  }
+  private async setupHealthCheck() {
+    Iif (this.healthCheckCleanup) return
+    const trigger = (this.ready.trigger ?? defaultTrigger)(() => ({
+      lastResult: this._health.result,
+    }))
+ 
+    const { promise: status, resolve: setStatus } = oncePromise<{
+      done: true
+    }>()
+    new Promise(async () => {
+      for (
+        let res = await Promise.race([status, trigger.next()]);
+        !res.done;
+        res = await Promise.race([status, trigger.next()])
+      ) {
+        const handle = (await this.daemon).subContainerHandle
+ 
+        if (handle) {
+          const response: HealthCheckResult = await Promise.resolve(
+            this.ready.fn(handle),
+          ).catch((err) => {
+            console.error(asError(err))
+            return {
+              result: "failure",
+              message: "message" in err ? err.message : String(err),
+            }
+          })
+          await this.setHealth(response)
+        } else {
+          await this.setHealth({
+            result: "failure",
+            message: "Daemon not running",
+          })
+        }
+      }
+    }).catch((err) => console.error(`Daemon ${this.id} failed: ${err}`))
+ 
+    this.healthCheckCleanup = () => {
+      setStatus({ done: true })
+      this.healthCheckCleanup = null
+    }
+  }
+ 
+  private async setHealth(health: HealthCheckResult) {
+    this._health = health
+    this.healthWatchers.forEach((watcher) => watcher())
+    const display = this.ready.display
+    const result = health.result
+    Iif (!display) {
+      return
+    }
+    await this.effects.setHealth({
+      ...health,
+      id: this.id,
+      name: display,
+    } as SetHealth)
+  }
+ 
+  private async updateStatus() {
+    const healths = this.dependencies.map((d) => d._health)
+    this.changeRunning(healths.every((x) => x.result === "success"))
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/mainFn/Mounts.ts.html b/sdk/lib/coverage/lcov-report/lib/mainFn/Mounts.ts.html new file mode 100644 index 000000000..76f023c06 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/mainFn/Mounts.ts.html @@ -0,0 +1,460 @@ + + + + + + Code coverage report for lib/mainFn/Mounts.ts + + + + + + + + + +
+
+

All files / lib/mainFn Mounts.ts

+
+ +
+ 4.34% + Statements + 1/23 +
+ + +
+ 0% + Branches + 0/1 +
+ + +
+ 0% + Functions + 0/12 +
+ + +
+ 4.34% + Lines + 1/23 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126  +  +  +  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import * as T from "../types"
+import { MountOptions } from "../util/SubContainer"
+ 
+type MountArray = { path: string; options: MountOptions }[]
+ 
+export class Mounts<Manifest extends T.Manifest> {
+  private constructor(
+    readonly volumes: {
+      id: Manifest["volumes"][number]
+      subpath: string | null
+      mountpoint: string
+      readonly: boolean
+    }[],
+    readonly assets: {
+      id: Manifest["assets"][number]
+      subpath: string | null
+      mountpoint: string
+    }[],
+    readonly dependencies: {
+      dependencyId: string
+      volumeId: string
+      subpath: string | null
+      mountpoint: string
+      readonly: boolean
+    }[],
+  ) {}
+ 
+  static of<Manifest extends T.Manifest>() {
+    return new Mounts<Manifest>([], [], [])
+  }
+ 
+  addVolume(
+    id: Manifest["volumes"][number],
+    subpath: string | null,
+    mountpoint: string,
+    readonly: boolean,
+  ) {
+    this.volumes.push({
+      id,
+      subpath,
+      mountpoint,
+      readonly,
+    })
+    return this
+  }
+ 
+  addAssets(
+    id: Manifest["assets"][number],
+    subpath: string | null,
+    mountpoint: string,
+  ) {
+    this.assets.push({
+      id,
+      subpath,
+      mountpoint,
+    })
+    return this
+  }
+ 
+  addDependency<DependencyManifest extends T.Manifest>(
+    dependencyId: keyof Manifest["dependencies"] & string,
+    volumeId: DependencyManifest["volumes"][number],
+    subpath: string | null,
+    mountpoint: string,
+    readonly: boolean,
+  ) {
+    this.dependencies.push({
+      dependencyId,
+      volumeId,
+      subpath,
+      mountpoint,
+      readonly,
+    })
+    return this
+  }
+ 
+  build(): MountArray {
+    const mountpoints = new Set()
+    for (let mountpoint of this.volumes
+      .map((v) => v.mountpoint)
+      .concat(this.assets.map((a) => a.mountpoint))
+      .concat(this.dependencies.map((d) => d.mountpoint))) {
+      Iif (mountpoints.has(mountpoint)) {
+        throw new Error(
+          `cannot mount more than once to mountpoint ${mountpoint}`,
+        )
+      }
+      mountpoints.add(mountpoint)
+    }
+    return ([] as MountArray)
+      .concat(
+        this.volumes.map((v) => ({
+          path: v.mountpoint,
+          options: {
+            type: "volume",
+            id: v.id,
+            subpath: v.subpath,
+            readonly: v.readonly,
+          },
+        })),
+      )
+      .concat(
+        this.assets.map((a) => ({
+          path: a.mountpoint,
+          options: {
+            type: "assets",
+            id: a.id,
+            subpath: a.subpath,
+          },
+        })),
+      )
+      .concat(
+        this.dependencies.map((d) => ({
+          path: d.mountpoint,
+          options: {
+            type: "pointer",
+            packageId: d.dependencyId,
+            volumeId: d.volumeId,
+            subpath: d.subpath,
+            readonly: d.readonly,
+          },
+        })),
+      )
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/mainFn/index.html b/sdk/lib/coverage/lcov-report/lib/mainFn/index.html new file mode 100644 index 000000000..16b3adb1c --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/mainFn/index.html @@ -0,0 +1,191 @@ + + + + + + Code coverage report for lib/mainFn + + + + + + + + + +
+
+

All files lib/mainFn

+
+ +
+ 15.78% + Statements + 36/228 +
+ + +
+ 0% + Branches + 0/38 +
+ + +
+ 0% + Functions + 0/77 +
+ + +
+ 15.16% + Lines + 32/211 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
CommandController.ts +
+
10.41%5/480%0/240%0/1210.41%5/48
Daemon.ts +
+
15.62%5/320%0/10%0/1316.66%5/30
Daemons.ts +
+
31.81%14/44100%0/00%0/1628.94%11/38
HealthDaemon.ts +
+
6.94%5/720%0/120%0/227.81%5/64
Mounts.ts +
+
4.34%1/230%0/10%0/124.34%1/23
index.ts +
+
66.66%6/9100%0/00%0/262.5%5/8
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/mainFn/index.ts.html b/sdk/lib/coverage/lcov-report/lib/mainFn/index.ts.html new file mode 100644 index 000000000..4792fc2be --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/mainFn/index.ts.html @@ -0,0 +1,178 @@ + + + + + + Code coverage report for lib/mainFn/index.ts + + + + + + + + + +
+
+

All files / lib/mainFn index.ts

+
+ +
+ 66.66% + Statements + 6/9 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 0% + Functions + 0/2 +
+ + +
+ 62.5% + Lines + 5/8 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32  +  +5x +5x +  +5x +  +  +  +5x +  +  +  +  +  +  +  +  +  +  +5x +  +  +  +  +  +  +  +  +  +  + 
import * as T from "../types"
+import { Daemons } from "./Daemons"
+import "../interfaces/ServiceInterfaceBuilder"
+import "../interfaces/Origin"
+ 
+import "./Daemons"
+ 
+import { MainEffects } from "../StartSdk"
+ 
+export const DEFAULT_SIGTERM_TIMEOUT = 30_000
+/**
+ * Used to ensure that the main function is running with the valid proofs.
+ * We first do the folowing order of things
+ * 1. We get the interfaces
+ * 2. We setup all the commands to setup the system
+ * 3. We create the health checks
+ * 4. We setup the daemons init system
+ * @param fn
+ * @returns
+ */
+export const setupMain = <Manifest extends T.Manifest, Store>(
+  fn: (o: {
+    effects: MainEffects
+    started(onTerm: () => PromiseLike<void>): PromiseLike<void>
+  }) => Promise<Daemons<Manifest, any>>,
+): T.ExpectedExports.main => {
+  return async (options) => {
+    const result = await fn(options)
+    return result
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/manifest/index.html b/sdk/lib/coverage/lcov-report/lib/manifest/index.html new file mode 100644 index 000000000..bcda1d230 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/manifest/index.html @@ -0,0 +1,116 @@ + + + + + + Code coverage report for lib/manifest + + + + + + + + + +
+
+

All files lib/manifest

+
+ +
+ 25% + Statements + 4/16 +
+ + +
+ 65.51% + Branches + 19/29 +
+ + +
+ 20% + Functions + 1/5 +
+ + +
+ 26.66% + Lines + 4/15 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
setupManifest.ts +
+
25%4/1665.51%19/2920%1/526.66%4/15
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/manifest/setupManifest.ts.html b/sdk/lib/coverage/lcov-report/lib/manifest/setupManifest.ts.html new file mode 100644 index 000000000..96ab80d80 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/manifest/setupManifest.ts.html @@ -0,0 +1,337 @@ + + + + + + Code coverage report for lib/manifest/setupManifest.ts + + + + + + + + + +
+
+

All files / lib/manifest setupManifest.ts

+
+ +
+ 25% + Statements + 4/16 +
+ + +
+ 65.51% + Branches + 19/29 +
+ + +
+ 20% + Functions + 1/5 +
+ + +
+ 26.66% + Lines + 4/15 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85  +  +  +4x +  +  +  +  +  +  +  +4x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +5x +  +  +  +  +  +  +  +  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import * as T from "../types"
+import { ImageConfig, ImageId, VolumeId } from "../osBindings"
+import { SDKManifest, SDKImageConfig } from "./ManifestTypes"
+import { SDKVersion } from "../StartSdk"
+import { VersionGraph } from "../version/VersionGraph"
+ 
+/**
+ * This is an example of a function that takes a manifest and returns a new manifest with additional properties
+ * @param manifest Manifests are the description of the package
+ * @returns The manifest with additional properties
+ */
+export function setupManifest<
+  Id extends string,
+  Version extends string,
+  Dependencies extends Record<string, unknown>,
+  VolumesTypes extends VolumeId,
+  AssetTypes extends VolumeId,
+  ImagesTypes extends ImageId,
+  Manifest extends {
+    dependencies: Dependencies
+    id: Id
+    assets: AssetTypes[]
+    images: Record<ImagesTypes, SDKImageConfig>
+    volumes: VolumesTypes[]
+  },
+  Satisfies extends string[] = [],
+>(
+  versions: VersionGraph<Version>,
+  manifest: SDKManifest & Manifest,
+): Manifest & T.Manifest {
+  const images = Object.entries(manifest.images).reduce(
+    (images, [k, v]) => {
+      v.arch = v.arch || ["aarch64", "x86_64"]
+      Iif (v.emulateMissingAs === undefined)
+        v.emulateMissingAs = v.arch[0] || null
+      images[k] = v as ImageConfig
+      return images
+    },
+    {} as { [k: string]: ImageConfig },
+  )
+  return {
+    ...manifest,
+    gitHash: null,
+    osVersion: SDKVersion,
+    version: versions.current.options.version,
+    releaseNotes: versions.current.options.releaseNotes,
+    satisfies: versions.current.options.satisfies || [],
+    canMigrateTo: versions.canMigrateTo().toString(),
+    canMigrateFrom: versions.canMigrateFrom().toString(),
+    images,
+    alerts: {
+      install: manifest.alerts?.install || null,
+      update: manifest.alerts?.update || null,
+      uninstall: manifest.alerts?.uninstall || null,
+      restore: manifest.alerts?.restore || null,
+      start: manifest.alerts?.start || null,
+      stop: manifest.alerts?.stop || null,
+    },
+    hasConfig: manifest.hasConfig === undefined ? true : manifest.hasConfig,
+    hardwareRequirements: {
+      device: Object.fromEntries(
+        Object.entries(manifest.hardwareRequirements?.device || {}).map(
+          ([k, v]) => [k, v.source],
+        ),
+      ),
+      ram: manifest.hardwareRequirements?.ram || null,
+      arch:
+        manifest.hardwareRequirements?.arch === undefined
+          ? Object.values(images).reduce(
+              (arch, config) => {
+                Iif (config.emulateMissingAs) {
+                  return arch
+                }
+                Iif (arch === null) {
+                  return config.arch
+                }
+                return arch.filter((a) => config.arch.includes(a))
+              },
+              null as string[] | null,
+            )
+          : manifest.hardwareRequirements?.arch,
+    },
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/store/PathBuilder.ts.html b/sdk/lib/coverage/lcov-report/lib/store/PathBuilder.ts.html new file mode 100644 index 000000000..e97ca3607 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/store/PathBuilder.ts.html @@ -0,0 +1,199 @@ + + + + + + Code coverage report for lib/store/PathBuilder.ts + + + + + + + + + +
+
+

All files / lib/store PathBuilder.ts

+
+ +
+ 53.84% + Statements + 7/13 +
+ + +
+ 33.33% + Branches + 1/3 +
+ + +
+ 33.33% + Functions + 1/3 +
+ + +
+ 50% + Lines + 5/10 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +5x +5x +  +  +  +5x +  +  +6x +  +  +  +  +  +  +  +  +  + 
import { Affine } from "../util"
+ 
+const pathValue = Symbol("pathValue")
+export type PathValue = typeof pathValue
+ 
+export type PathBuilderStored<AllStore, Store> = {
+  [K in PathValue]: [AllStore, Store]
+}
+ 
+export type PathBuilder<AllStore, Store = AllStore> = (Store extends Record<
+  string,
+  unknown
+>
+  ? {
+      [K in keyof Store]: PathBuilder<AllStore, Store[K]>
+    }
+  : {}) &
+  PathBuilderStored<AllStore, Store>
+ 
+export type StorePath = string & Affine<"StorePath">
+const privateSymbol = Symbol("jsonPath")
+export const extractJsonPath = (builder: PathBuilder<unknown>) => {
+  return (builder as any)[privateSymbol] as StorePath
+}
+ 
+export const pathBuilder = <Store, StorePath = Store>(
+  paths: string[] = [],
+): PathBuilder<Store, StorePath> => {
+  return new Proxy({} as PathBuilder<Store, StorePath>, {
+    get(target, prop) {
+      Iif (prop === privateSymbol) {
+        Iif (paths.length === 0) return ""
+        return `/${paths.join("/")}`
+      }
+      return pathBuilder<any>([...paths, prop as string])
+    },
+  }) as PathBuilder<Store, StorePath>
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/store/getStore.ts.html b/sdk/lib/coverage/lcov-report/lib/store/getStore.ts.html new file mode 100644 index 000000000..4e9ec11bf --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/store/getStore.ts.html @@ -0,0 +1,268 @@ + + + + + + Code coverage report for lib/store/getStore.ts + + + + + + + + + +
+
+

All files / lib/store getStore.ts

+
+ +
+ 20% + Statements + 3/15 +
+ + +
+ 0% + Branches + 0/2 +
+ + +
+ 0% + Functions + 0/7 +
+ + +
+ 20% + Lines + 3/15 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62  +5x +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +5x +  +  +  +  +  +  +  +  +  + 
import { Effects } from "../types"
+import { PathBuilder, extractJsonPath } from "./PathBuilder"
+ 
+export class GetStore<Store, StoreValue> {
+  constructor(
+    readonly effects: Effects,
+    readonly path: PathBuilder<Store, StoreValue>,
+    readonly options: {
+      /** Defaults to what ever the package currently in */
+      packageId?: string | undefined
+    } = {},
+  ) {}
+ 
+  /**
+   * Returns the value of Store at the provided path. Restart the service if the value changes
+   */
+  const() {
+    return this.effects.store.get<Store, StoreValue>({
+      ...this.options,
+      path: extractJsonPath(this.path),
+      callback: this.effects.restart,
+    })
+  }
+  /**
+   * Returns the value of Store at the provided path. Does nothing if the value changes
+   */
+  once() {
+    return this.effects.store.get<Store, StoreValue>({
+      ...this.options,
+      path: extractJsonPath(this.path),
+    })
+  }
+ 
+  /**
+   * Watches the value of Store at the provided path. Takes a custom callback function to run whenever the value changes
+   */
+  async *watch() {
+    while (true) {
+      let callback: () => void
+      const waitForNext = new Promise<void>((resolve) => {
+        callback = resolve
+      })
+      yield await this.effects.store.get<Store, StoreValue>({
+        ...this.options,
+        path: extractJsonPath(this.path),
+        callback: () => callback(),
+      })
+      await waitForNext
+    }
+  }
+}
+export function getStore<Store, StoreValue>(
+  effects: Effects,
+  path: PathBuilder<Store, StoreValue>,
+  options: {
+    /** Defaults to what ever the package currently in */
+    packageId?: string | undefined
+  } = {},
+) {
+  return new GetStore<Store, StoreValue>(effects, path, options)
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/store/index.html b/sdk/lib/coverage/lcov-report/lib/store/index.html new file mode 100644 index 000000000..7cee3cafe --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/store/index.html @@ -0,0 +1,131 @@ + + + + + + Code coverage report for lib/store + + + + + + + + + +
+
+

All files lib/store

+
+ +
+ 35.71% + Statements + 10/28 +
+ + +
+ 20% + Branches + 1/5 +
+ + +
+ 10% + Functions + 1/10 +
+ + +
+ 32% + Lines + 8/25 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
PathBuilder.ts +
+
53.84%7/1333.33%1/333.33%1/350%5/10
getStore.ts +
+
20%3/150%0/20%0/720%3/15
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/test/index.html b/sdk/lib/coverage/lcov-report/lib/test/index.html new file mode 100644 index 000000000..ac3c5508a --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/test/index.html @@ -0,0 +1,131 @@ + + + + + + Code coverage report for lib/test + + + + + + + + + +
+
+

All files lib/test

+
+ +
+ 100% + Statements + 9/9 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 100% + Functions + 0/0 +
+ + +
+ 100% + Lines + 9/9 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
output.sdk.ts +
+
100%5/5100%0/0100%0/0100%5/5
output.ts +
+
100%4/4100%0/0100%0/0100%4/4
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/test/output.sdk.ts.html b/sdk/lib/coverage/lcov-report/lib/test/output.sdk.ts.html new file mode 100644 index 000000000..23e5bd6fa --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/test/output.sdk.ts.html @@ -0,0 +1,253 @@ + + + + + + Code coverage report for lib/test/output.sdk.ts + + + + + + + + + +
+
+

All files / lib/test output.sdk.ts

+
+ +
+ 100% + Statements + 5/5 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 100% + Functions + 0/0 +
+ + +
+ 100% + Lines + 5/5 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +574x +4x +4x +4x +  +  +4x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { StartSdk } from "../StartSdk"
+import { setupManifest } from "../manifest/setupManifest"
+import { VersionInfo } from "../version/VersionInfo"
+import { VersionGraph } from "../version/VersionGraph"
+ 
+export type Manifest = any
+export const sdk = StartSdk.of()
+  .withManifest(
+    setupManifest(
+      VersionGraph.of(
+        VersionInfo.of({
+          version: "1.0.0:0",
+          releaseNotes: "",
+          migrations: {},
+        })
+          .satisfies("#other:1.0.0:0")
+          .satisfies("#other:2.0.0:0"),
+      ),
+      {
+        id: "testOutput",
+        title: "",
+        license: "",
+        replaces: [],
+        wrapperRepo: "",
+        upstreamRepo: "",
+        supportSite: "",
+        marketingSite: "",
+        donationUrl: null,
+        description: {
+          short: "",
+          long: "",
+        },
+        containers: {},
+        images: {},
+        volumes: [],
+        assets: [],
+        alerts: {
+          install: null,
+          update: null,
+          uninstall: null,
+          restore: null,
+          start: null,
+          stop: null,
+        },
+        dependencies: {
+          "remote-test": {
+            description: "",
+            optional: false,
+            s9pk: "https://example.com/remote-test.s9pk",
+          },
+        },
+      },
+    ),
+  )
+  .withStore<{ storeRoot: { storeLeaf: "value" } }>()
+  .build(true)
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/test/output.ts.html b/sdk/lib/coverage/lcov-report/lib/test/output.ts.html new file mode 100644 index 000000000..7a69b61a8 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/test/output.ts.html @@ -0,0 +1,1213 @@ + + + + + + Code coverage report for lib/test/output.ts + + + + + + + + + +
+
+

All files / lib/test output.ts

+
+ +
+ 100% + Statements + 4/4 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 100% + Functions + 0/0 +
+ + +
+ 100% + Lines + 4/4 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335 +336 +337 +338 +339 +340 +341 +342 +343 +344 +345 +346 +347 +348 +349 +350 +351 +352 +353 +354 +355 +356 +357 +358 +359 +360 +361 +362 +363 +364 +365 +366 +367 +368 +369 +370 +371 +372 +373 +374 +375 +376 +377  +2x +2x +  +2x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +2x + 
 
+import { sdk } from "./output.sdk"
+const {Config, List, Value, Variants} = sdk
+ 
+export const configSpec = Config.of({"mediasources": Value.multiselect({
+  "name": "Media Sources",
+  "minLength": null,
+  "maxLength": null,
+  "default": [
+    "nextcloud"
+  ],
+  "description": "List of Media Sources to use with Jellyfin",
+  "warning": null,
+  "values": {
+    "nextcloud": "NextCloud",
+    "filebrowser": "File Browser"
+  }
+}),"testListUnion": Value.list(/* TODO: Convert range for this value ([1,*))*/List.obj({
+          name:"Lightning Nodes",
+          minLength:null,
+          maxLength:null,
+          default: [],
+          description: "List of Lightning Network node instances to manage",
+          warning: null,
+        }, {
+          spec: 
+          Config.of({
+            "union": /* TODO: Convert range for this value ([1,*))*/
+          Value.union({
+            name: "Type",
+            description: "- LND: Lightning Network Daemon from Lightning Labs\n- CLN: Core Lightning from Blockstream\n",
+            warning: null,
+            required: {"default":"lnd"},
+          }, Variants.of({"lnd": {name: "lnd", spec: Config.of({"name": Value.text({
+  "name": "Node Name",
+  "required": {
+    "default": "LND Wrapper"
+  },
+  "description": "Name of this node in the list",
+  "warning": null,
+  "masked": false,
+  "placeholder": null,
+  "inputmode": "text",
+  "patterns": [],
+  "minLength": null,
+  "maxLength": null
+}),})},}))
+        
+          })
+        ,
+          displayAs: "{{name}}",
+          uniqueBy: "name",
+        })),"rpc": Value.object({
+        name: "RPC Settings",
+        description: "RPC configuration options.",
+        warning: null,
+      }, Config.of({"enable": Value.toggle({
+  "name": "Enable",
+  "default": true,
+  "description": "Allow remote RPC requests.",
+  "warning": null
+}),"username": Value.text({
+  "name": "Username",
+  "required": {
+    "default": "bitcoin"
+  },
+  "description": "The username for connecting to Bitcoin over RPC.",
+  "warning": null,
+  "masked": true,
+  "placeholder": null,
+  "inputmode": "text",
+  "patterns": [
+    {
+      "regex": "^[a-zA-Z0-9_]+$",
+      "description": "Must be alphanumeric (can contain underscore)."
+    }
+  ],
+  "minLength": null,
+  "maxLength": null
+}),"password": Value.text({
+  "name": "RPC Password",
+  "required": {
+    "default": {
+      "charset": "a-z,2-7",
+      "len": 20
+    }
+  },
+  "description": "The password for connecting to Bitcoin over RPC.",
+  "warning": null,
+  "masked": true,
+  "placeholder": null,
+  "inputmode": "text",
+  "patterns": [
+    {
+      "regex": "^[^\\n\"]*$",
+      "description": "Must not contain newline or quote characters."
+    }
+  ],
+  "minLength": null,
+  "maxLength": null
+}),"bio": Value.textarea({
+  "name": "Username",
+  "description": "The username for connecting to Bitcoin over RPC.",
+  "warning": null,
+  "required": true,
+  "placeholder": null,
+  "maxLength": null,
+  "minLength": null
+}),"advanced": Value.object({
+        name: "Advanced",
+        description: "Advanced RPC Settings",
+        warning: null,
+      }, Config.of({"auth": Value.list(/* TODO: Convert range for this value ([0,*))*/List.text({
+  "name": "Authorization",
+  "minLength": null,
+  "maxLength": null,
+  "default": [],
+  "description": "Username and hashed password for JSON-RPC connections. RPC clients connect using the usual http basic authentication.",
+  "warning": null
+}, {"masked":false,"placeholder":null,"patterns":[{"regex":"^[a-zA-Z0-9_-]+:([0-9a-fA-F]{2})+\\$([0-9a-fA-F]{2})+$","description":"Each item must be of the form \"<USERNAME>:<SALT>$<HASH>\"."}],"minLength":null,"maxLength":null})),"serialversion": Value.select({
+  "name": "Serialization Version",
+  "description": "Return raw transaction or block hex with Segwit or non-SegWit serialization.",
+  "warning": null,
+  "required": {
+    "default": "segwit"
+  },
+  "values": {
+    "non-segwit": "non-segwit",
+    "segwit": "segwit"
+  }
+} as const),"servertimeout": /* TODO: Convert range for this value ([5,300])*/Value.number({
+  "name": "Rpc Server Timeout",
+  "description": "Number of seconds after which an uncompleted RPC call will time out.",
+  "warning": null,
+  "required": {
+    "default": 30
+  },
+  "min": null,
+  "max": null,
+  "step": null,
+  "integer": true,
+  "units": "seconds",
+  "placeholder": null
+}),"threads": /* TODO: Convert range for this value ([1,64])*/Value.number({
+  "name": "Threads",
+  "description": "Set the number of threads for handling RPC calls. You may wish to increase this if you are making lots of calls via an integration.",
+  "warning": null,
+  "required": {
+    "default": 16
+  },
+  "min": null,
+  "max": null,
+  "step": null,
+  "integer": true,
+  "units": null,
+  "placeholder": null
+}),"workqueue": /* TODO: Convert range for this value ([8,256])*/Value.number({
+  "name": "Work Queue",
+  "description": "Set the depth of the work queue to service RPC calls. Determines how long the backlog of RPC requests can get before it just rejects new ones.",
+  "warning": null,
+  "required": {
+    "default": 128
+  },
+  "min": null,
+  "max": null,
+  "step": null,
+  "integer": true,
+  "units": "requests",
+  "placeholder": null
+}),})),})),"zmq-enabled": Value.toggle({
+  "name": "ZeroMQ Enabled",
+  "default": true,
+  "description": "Enable the ZeroMQ interface",
+  "warning": null
+}),"txindex": Value.toggle({
+  "name": "Transaction Index",
+  "default": true,
+  "description": "Enable the Transaction Index (txindex)",
+  "warning": null
+}),"wallet": Value.object({
+        name: "Wallet",
+        description: "Wallet Settings",
+        warning: null,
+      }, Config.of({"enable": Value.toggle({
+  "name": "Enable Wallet",
+  "default": true,
+  "description": "Load the wallet and enable wallet RPC calls.",
+  "warning": null
+}),"avoidpartialspends": Value.toggle({
+  "name": "Avoid Partial Spends",
+  "default": true,
+  "description": "Group outputs by address, selecting all or none, instead of selecting on a per-output basis. This improves privacy at the expense of higher transaction fees.",
+  "warning": null
+}),"discardfee": /* TODO: Convert range for this value ([0,.01])*/Value.number({
+  "name": "Discard Change Tolerance",
+  "description": "The fee rate (in BTC/kB) that indicates your tolerance for discarding change by adding it to the fee.",
+  "warning": null,
+  "required": {
+    "default": 0.0001
+  },
+  "min": null,
+  "max": null,
+  "step": null,
+  "integer": false,
+  "units": "BTC/kB",
+  "placeholder": null
+}),})),"advanced": Value.object({
+        name: "Advanced",
+        description: "Advanced Settings",
+        warning: null,
+      }, Config.of({"mempool": Value.object({
+        name: "Mempool",
+        description: "Mempool Settings",
+        warning: null,
+      }, Config.of({"mempoolfullrbf": Value.toggle({
+  "name": "Enable Full RBF",
+  "default": false,
+  "description": "Policy for your node to use for relaying and mining unconfirmed transactions.  For details, see https://github.com/bitcoin/bitcoin/blob/master/doc/release-notes/release-notes-24.0.md#notice-of-new-option-for-transaction-replacement-policies",
+  "warning": null
+}),"persistmempool": Value.toggle({
+  "name": "Persist Mempool",
+  "default": true,
+  "description": "Save the mempool on shutdown and load on restart.",
+  "warning": null
+}),"maxmempool": /* TODO: Convert range for this value ([1,*))*/Value.number({
+  "name": "Max Mempool Size",
+  "description": "Keep the transaction memory pool below <n> megabytes.",
+  "warning": null,
+  "required": {
+    "default": 300
+  },
+  "min": null,
+  "max": null,
+  "step": null,
+  "integer": true,
+  "units": "MiB",
+  "placeholder": null
+}),"mempoolexpiry": /* TODO: Convert range for this value ([1,*))*/Value.number({
+  "name": "Mempool Expiration",
+  "description": "Do not keep transactions in the mempool longer than <n> hours.",
+  "warning": null,
+  "required": {
+    "default": 336
+  },
+  "min": null,
+  "max": null,
+  "step": null,
+  "integer": true,
+  "units": "Hr",
+  "placeholder": null
+}),})),"peers": Value.object({
+        name: "Peers",
+        description: "Peer Connection Settings",
+        warning: null,
+      }, Config.of({"listen": Value.toggle({
+  "name": "Make Public",
+  "default": true,
+  "description": "Allow other nodes to find your server on the network.",
+  "warning": null
+}),"onlyconnect": Value.toggle({
+  "name": "Disable Peer Discovery",
+  "default": false,
+  "description": "Only connect to specified peers.",
+  "warning": null
+}),"onlyonion": Value.toggle({
+  "name": "Disable Clearnet",
+  "default": false,
+  "description": "Only connect to peers over Tor.",
+  "warning": null
+}),"addnode": Value.list(/* TODO: Convert range for this value ([0,*))*/List.obj({
+          name: "Add Nodes",
+          minLength: null,
+          maxLength: null,
+          default: [],
+          description: "Add addresses of nodes to connect to.",
+          warning: null,
+        }, {
+          spec: Config.of({"hostname": Value.text({
+  "name": "Hostname",
+  "required": false,
+  "description": "Domain or IP address of bitcoin peer",
+  "warning": null,
+  "masked": false,
+  "placeholder": null,
+  "inputmode": "text",
+  "patterns": [
+    {
+      "regex": "(^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$)|((^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$)|(^[a-z2-7]{16}\\.onion$)|(^([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]$))",
+      "description": "Must be either a domain name, or an IPv4 or IPv6 address. Do not include protocol scheme (eg 'http://') or port."
+    }
+  ],
+  "minLength": null,
+  "maxLength": null
+}),"port": /* TODO: Convert range for this value ([0,65535])*/Value.number({
+  "name": "Port",
+  "description": "Port that peer is listening on for inbound p2p connections",
+  "warning": null,
+  "required": false,
+  "min": null,
+  "max": null,
+  "step": null,
+  "integer": true,
+  "units": null,
+  "placeholder": null
+}),}),
+          displayAs: null,
+          uniqueBy: null,
+        })),})),"dbcache": /* TODO: Convert range for this value ((0,*))*/Value.number({
+  "name": "Database Cache",
+  "description": "How much RAM to allocate for caching the TXO set. Higher values improve syncing performance, but increase your chance of using up all your system's memory or corrupting your database in the event of an ungraceful shutdown. Set this high but comfortably below your system's total RAM during IBD, then turn down to 450 (or leave blank) once the sync completes.",
+  "warning": "WARNING: Increasing this value results in a higher chance of ungraceful shutdowns, which can leave your node unusable if it happens during the initial block download. Use this setting with caution. Be sure to set this back to the default (450 or leave blank) once your node is synced. DO NOT press the STOP button if your dbcache is large. Instead, set this number back to the default, hit save, and wait for bitcoind to restart on its own.",
+  "required": false,
+  "min": null,
+  "max": null,
+  "step": null,
+  "integer": true,
+  "units": "MiB",
+  "placeholder": null
+}),"pruning": Value.union({
+        name: "Pruning Settings",
+        description: "- Disabled: Disable pruning\n- Automatic: Limit blockchain size on disk to a certain number of megabytes\n- Manual: Prune blockchain with the \"pruneblockchain\" RPC\n",
+        warning: null,
+        
+        // prettier-ignore
+        required: {"default":"disabled"},
+      }, Variants.of({"disabled": {name: "Disabled", spec: Config.of({})},"automatic": {name: "Automatic", spec: Config.of({"size": /* TODO: Convert range for this value ([550,1000000))*/Value.number({
+  "name": "Max Chain Size",
+  "description": "Limit of blockchain size on disk.",
+  "warning": "Increasing this value will require re-syncing your node.",
+  "required": {
+    "default": 550
+  },
+  "min": null,
+  "max": null,
+  "step": null,
+  "integer": true,
+  "units": "MiB",
+  "placeholder": null
+}),})},"manual": {name: "Manual", spec: Config.of({"size": /* TODO: Convert range for this value ([550,1000000))*/Value.number({
+  "name": "Failsafe Chain Size",
+  "description": "Prune blockchain if size expands beyond this.",
+  "warning": null,
+  "required": {
+    "default": 65536
+  },
+  "min": null,
+  "max": null,
+  "step": null,
+  "integer": true,
+  "units": "MiB",
+  "placeholder": null
+}),})},})),"blockfilters": Value.object({
+        name: "Block Filters",
+        description: "Settings for storing and serving compact block filters",
+        warning: null,
+      }, Config.of({"blockfilterindex": Value.toggle({
+  "name": "Compute Compact Block Filters (BIP158)",
+  "default": true,
+  "description": "Generate Compact Block Filters during initial sync (IBD) to enable 'getblockfilter' RPC. This is useful if dependent services need block filters to efficiently scan for addresses/transactions etc.",
+  "warning": null
+}),"peerblockfilters": Value.toggle({
+  "name": "Serve Compact Block Filters to Peers (BIP157)",
+  "default": false,
+  "description": "Serve Compact Block Filters as a peer service to other nodes on the network. This is useful if you wish to connect an SPV client to your node to make it efficient to scan transactions without having to download all block data.  'Compute Compact Block Filters (BIP158)' is required.",
+  "warning": null
+}),})),"bloomfilters": Value.object({
+        name: "Bloom Filters (BIP37)",
+        description: "Setting for serving Bloom Filters",
+        warning: null,
+      }, Config.of({"peerbloomfilters": Value.toggle({
+  "name": "Serve Bloom Filters to Peers",
+  "default": false,
+  "description": "Peers have the option of setting filters on each connection they make after the version handshake has completed. Bloom filters are for clients implementing SPV (Simplified Payment Verification) that want to check that block headers  connect together correctly, without needing to verify the full blockchain.  The client must trust that the transactions in the chain are in fact valid.  It is highly recommended AGAINST using for anything except Bisq integration.",
+  "warning": "This is ONLY for use with Bisq integration, please use Block Filters for all other applications."
+}),})),})),});
+export const matchConfigSpec = configSpec.validator;
+export type ConfigSpec = typeof matchConfigSpec._TYPE;
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/trigger/changeOnFirstSuccess.ts.html b/sdk/lib/coverage/lcov-report/lib/trigger/changeOnFirstSuccess.ts.html new file mode 100644 index 000000000..6de1a0250 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/trigger/changeOnFirstSuccess.ts.html @@ -0,0 +1,181 @@ + + + + + + Code coverage report for lib/trigger/changeOnFirstSuccess.ts + + + + + + + + + +
+
+

All files / lib/trigger changeOnFirstSuccess.ts

+
+ +
+ 12.5% + Statements + 2/16 +
+ + +
+ 0% + Branches + 0/2 +
+ + +
+ 50% + Functions + 1/2 +
+ + +
+ 12.5% + Lines + 2/16 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33  +  +5x +  +  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { Trigger } from "./index"
+ 
+export function changeOnFirstSuccess(o: {
+  beforeFirstSuccess: Trigger
+  afterFirstSuccess: Trigger
+}): Trigger {
+  return async function* (getInput) {
+    let currentValue = getInput()
+    while (!currentValue.lastResult) {
+      yield
+      currentValue = getInput()
+    }
+    const beforeFirstSuccess = o.beforeFirstSuccess(getInput)
+    for (
+      let res = await beforeFirstSuccess.next();
+      currentValue?.lastResult !== "success" && !res.done;
+      res = await beforeFirstSuccess.next()
+    ) {
+      yield
+      currentValue = getInput()
+    }
+    const afterFirstSuccess = o.afterFirstSuccess(getInput)
+    for (
+      let res = await afterFirstSuccess.next();
+      !res.done;
+      res = await afterFirstSuccess.next()
+    ) {
+      yield
+      currentValue = getInput()
+    }
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/trigger/cooldownTrigger.ts.html b/sdk/lib/coverage/lcov-report/lib/trigger/cooldownTrigger.ts.html new file mode 100644 index 000000000..b274515b7 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/trigger/cooldownTrigger.ts.html @@ -0,0 +1,109 @@ + + + + + + Code coverage report for lib/trigger/cooldownTrigger.ts + + + + + + + + + +
+
+

All files / lib/trigger cooldownTrigger.ts

+
+ +
+ 33.33% + Statements + 2/6 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 33.33% + Functions + 1/3 +
+ + +
+ 40% + Lines + 2/5 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +95x +10x +  +  +  +  +  +  + 
export function cooldownTrigger(timeMs: number) {
+  return async function* () {
+    while (true) {
+      await new Promise((resolve) => setTimeout(resolve, timeMs))
+      yield
+    }
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/trigger/defaultTrigger.ts.html b/sdk/lib/coverage/lcov-report/lib/trigger/defaultTrigger.ts.html new file mode 100644 index 000000000..46065e319 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/trigger/defaultTrigger.ts.html @@ -0,0 +1,109 @@ + + + + + + Code coverage report for lib/trigger/defaultTrigger.ts + + + + + + + + + +
+
+

All files / lib/trigger defaultTrigger.ts

+
+ +
+ 100% + Statements + 3/3 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 100% + Functions + 0/0 +
+ + +
+ 100% + Lines + 3/3 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +95x +5x +  +  +5x +  +  +  + 
import { cooldownTrigger } from "./cooldownTrigger"
+import { changeOnFirstSuccess } from "./changeOnFirstSuccess"
+import { successFailure } from "./successFailure"
+ 
+export const defaultTrigger = changeOnFirstSuccess({
+  beforeFirstSuccess: cooldownTrigger(1000),
+  afterFirstSuccess: cooldownTrigger(30000),
+})
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/trigger/index.html b/sdk/lib/coverage/lcov-report/lib/trigger/index.html new file mode 100644 index 000000000..db22def37 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/trigger/index.html @@ -0,0 +1,191 @@ + + + + + + Code coverage report for lib/trigger + + + + + + + + + +
+
+

All files lib/trigger

+
+ +
+ 30.61% + Statements + 15/49 +
+ + +
+ 0% + Branches + 0/5 +
+ + +
+ 40% + Functions + 4/10 +
+ + +
+ 26.66% + Lines + 12/45 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
changeOnFirstSuccess.ts +
+
12.5%2/160%0/250%1/212.5%2/16
cooldownTrigger.ts +
+
33.33%2/6100%0/033.33%1/340%2/5
defaultTrigger.ts +
+
100%3/3100%0/0100%0/0100%3/3
index.ts +
+
100%4/4100%0/0100%2/2100%2/2
lastStatus.ts +
+
6.25%1/160%0/30%0/26.25%1/16
successFailure.ts +
+
75%3/4100%0/00%0/166.66%2/3
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/trigger/index.ts.html b/sdk/lib/coverage/lcov-report/lib/trigger/index.ts.html new file mode 100644 index 000000000..0f4f86397 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/trigger/index.ts.html @@ -0,0 +1,109 @@ + + + + + + Code coverage report for lib/trigger/index.ts + + + + + + + + + +
+
+

All files / lib/trigger index.ts

+
+ +
+ 100% + Statements + 4/4 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 100% + Functions + 2/2 +
+ + +
+ 100% + Lines + 2/2 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9  +  +11x +11x +  +  +  +  + 
import { ExecSpawnable } from "../util/SubContainer"
+import { TriggerInput } from "./TriggerInput"
+export { changeOnFirstSuccess } from "./changeOnFirstSuccess"
+export { cooldownTrigger } from "./cooldownTrigger"
+ 
+export type Trigger = (
+  getInput: () => TriggerInput,
+) => AsyncIterator<unknown, unknown, never>
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/trigger/lastStatus.ts.html b/sdk/lib/coverage/lcov-report/lib/trigger/lastStatus.ts.html new file mode 100644 index 000000000..e5fbff2d6 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/trigger/lastStatus.ts.html @@ -0,0 +1,184 @@ + + + + + + Code coverage report for lib/trigger/lastStatus.ts + + + + + + + + + +
+
+

All files / lib/trigger lastStatus.ts

+
+ +
+ 6.25% + Statements + 1/16 +
+ + +
+ 0% + Branches + 0/3 +
+ + +
+ 0% + Functions + 0/2 +
+ + +
+ 6.25% + Lines + 1/16 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34  +  +  +  +  +  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { Trigger } from "."
+import { HealthStatus } from "../types"
+ 
+export type LastStatusTriggerParams = { [k in HealthStatus]?: Trigger } & {
+  default: Trigger
+}
+ 
+export function lastStatus(o: LastStatusTriggerParams): Trigger {
+  return async function* (getInput) {
+    let trigger = o.default(getInput)
+    const triggers: {
+      [k in HealthStatus]?: AsyncIterator<unknown, unknown, never>
+    } & { default: AsyncIterator<unknown, unknown, never> } = {
+      default: trigger,
+    }
+    while (true) {
+      let currentValue = getInput()
+      let prev: HealthStatus | "default" | undefined = currentValue.lastResult
+      Iif (!prev) {
+        yield
+        continue
+      }
+      Iif (!(prev in o)) {
+        prev = "default"
+      }
+      Iif (!triggers[prev]) {
+        triggers[prev] = o[prev]!(getInput)
+      }
+      await triggers[prev]?.next()
+      yield
+    }
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/trigger/successFailure.ts.html b/sdk/lib/coverage/lcov-report/lib/trigger/successFailure.ts.html new file mode 100644 index 000000000..2c09efbc2 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/trigger/successFailure.ts.html @@ -0,0 +1,106 @@ + + + + + + Code coverage report for lib/trigger/successFailure.ts + + + + + + + + + +
+
+

All files / lib/trigger successFailure.ts

+
+ +
+ 75% + Statements + 3/4 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 66.66% + Lines + 2/3 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8  +5x +  +5x +  +  +  + 
import { Trigger } from "."
+import { lastStatus } from "./lastStatus"
+ 
+export const successFailure = (o: {
+  duringSuccess: Trigger
+  duringError: Trigger
+}) => lastStatus({ success: o.duringSuccess, default: o.duringError })
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/util/GetSslCertificate.ts.html b/sdk/lib/coverage/lcov-report/lib/util/GetSslCertificate.ts.html new file mode 100644 index 000000000..640beb3b6 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/util/GetSslCertificate.ts.html @@ -0,0 +1,226 @@ + + + + + + Code coverage report for lib/util/GetSslCertificate.ts + + + + + + + + + +
+
+

All files / lib/util GetSslCertificate.ts

+
+ +
+ 8.33% + Statements + 1/12 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 0% + Functions + 0/6 +
+ + +
+ 8.33% + Lines + 1/12 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48  +  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { T } from ".."
+import { Effects } from "../types"
+ 
+export class GetSslCertificate {
+  constructor(
+    readonly effects: Effects,
+    readonly hostnames: string[],
+    readonly algorithm?: T.Algorithm,
+  ) {}
+ 
+  /**
+   * Returns the system SMTP credentials. Restarts the service if the credentials change
+   */
+  const() {
+    return this.effects.getSslCertificate({
+      hostnames: this.hostnames,
+      algorithm: this.algorithm,
+      callback: this.effects.restart,
+    })
+  }
+  /**
+   * Returns the system SMTP credentials. Does nothing if the credentials change
+   */
+  once() {
+    return this.effects.getSslCertificate({
+      hostnames: this.hostnames,
+      algorithm: this.algorithm,
+    })
+  }
+  /**
+   * Watches the system SMTP credentials. Takes a custom callback function to run whenever the credentials change
+   */
+  async *watch() {
+    while (true) {
+      let callback: () => void
+      const waitForNext = new Promise<void>((resolve) => {
+        callback = resolve
+      })
+      yield await this.effects.getSslCertificate({
+        hostnames: this.hostnames,
+        algorithm: this.algorithm,
+        callback: () => callback(),
+      })
+      await waitForNext
+    }
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/util/GetSystemSmtp.ts.html b/sdk/lib/coverage/lcov-report/lib/util/GetSystemSmtp.ts.html new file mode 100644 index 000000000..43cfee672 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/util/GetSystemSmtp.ts.html @@ -0,0 +1,190 @@ + + + + + + Code coverage report for lib/util/GetSystemSmtp.ts + + + + + + + + + +
+
+

All files / lib/util GetSystemSmtp.ts

+
+ +
+ 10% + Statements + 1/10 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 0% + Functions + 0/6 +
+ + +
+ 10% + Lines + 1/10 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { Effects } from "../types"
+ 
+export class GetSystemSmtp {
+  constructor(readonly effects: Effects) {}
+ 
+  /**
+   * Returns the system SMTP credentials. Restarts the service if the credentials change
+   */
+  const() {
+    return this.effects.getSystemSmtp({
+      callback: this.effects.restart,
+    })
+  }
+  /**
+   * Returns the system SMTP credentials. Does nothing if the credentials change
+   */
+  once() {
+    return this.effects.getSystemSmtp({})
+  }
+  /**
+   * Watches the system SMTP credentials. Takes a custom callback function to run whenever the credentials change
+   */
+  async *watch() {
+    while (true) {
+      let callback: () => void
+      const waitForNext = new Promise<void>((resolve) => {
+        callback = resolve
+      })
+      yield await this.effects.getSystemSmtp({
+        callback: () => callback(),
+      })
+      await waitForNext
+    }
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/util/Hostname.ts.html b/sdk/lib/coverage/lcov-report/lib/util/Hostname.ts.html new file mode 100644 index 000000000..67313dca3 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/util/Hostname.ts.html @@ -0,0 +1,160 @@ + + + + + + Code coverage report for lib/util/Hostname.ts + + + + + + + + + +
+
+

All files / lib/util Hostname.ts

+
+ +
+ 6.66% + Statements + 1/15 +
+ + +
+ 0% + Branches + 0/13 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 6.66% + Lines + 1/15 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { HostnameInfo } from "../types"
+ 
+export function hostnameInfoToAddress(hostInfo: HostnameInfo): string {
+  Iif (hostInfo.kind === "onion") {
+    return `${hostInfo.hostname.value}`
+  }
+  Iif (hostInfo.kind !== "ip") {
+    throw Error("Expecting that the kind is ip.")
+  }
+  const hostname = hostInfo.hostname
+  Iif (hostname.kind === "domain") {
+    return `${hostname.subdomain ? `${hostname.subdomain}.` : ""}${hostname.domain}`
+  }
+  const port = hostname.sslPort || hostname.port
+  const portString = port ? `:${port}` : ""
+  Iif ("ipv4" === hostname.kind || "ipv6" === hostname.kind) {
+    return `${hostname.value}${portString}`
+  }
+  Iif ("local" === hostname.kind) {
+    return `${hostname.value}${portString}`
+  }
+  throw Error(
+    "Expecting to have a valid hostname kind." + JSON.stringify(hostname),
+  )
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/util/Overlay.ts.html b/sdk/lib/coverage/lcov-report/lib/util/Overlay.ts.html new file mode 100644 index 000000000..78da41682 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/util/Overlay.ts.html @@ -0,0 +1,805 @@ + + + + + + Code coverage report for lib/util/Overlay.ts + + + + + + + + + +
+
+

All files / lib/util Overlay.ts

+
+ +
+ 7.6% + Statements + 7/92 +
+ + +
+ 0% + Branches + 0/45 +
+ + +
+ 0% + Functions + 0/15 +
+ + +
+ 7.69% + Lines + 7/91 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +2415x +  +5x +5x +5x +5x +5x +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import * as fs from "fs/promises"
+import * as T from "../types"
+import * as cp from "child_process"
+import { promisify } from "util"
+import { Buffer } from "node:buffer"
+export const execFile = promisify(cp.execFile)
+const WORKDIR = (imageId: string) => `/media/startos/images/${imageId}/`
+export class Overlay {
+  private constructor(
+    readonly effects: T.Effects,
+    readonly imageId: T.ImageId,
+    readonly rootfs: string,
+    readonly guid: T.Guid,
+  ) {}
+  static async of(
+    effects: T.Effects,
+    image: { id: T.ImageId; sharedRun?: boolean },
+  ) {
+    const { id, sharedRun } = image
+    const [rootfs, guid] = await effects.createOverlayedImage({
+      imageId: id as string,
+    })
+ 
+    const shared = ["dev", "sys", "proc"]
+    Iif (!!sharedRun) {
+      shared.push("run")
+    }
+ 
+    fs.copyFile("/etc/resolv.conf", `${rootfs}/etc/resolv.conf`)
+ 
+    for (const dirPart of shared) {
+      const from = `/${dirPart}`
+      const to = `${rootfs}/${dirPart}`
+      await fs.mkdir(from, { recursive: true })
+      await fs.mkdir(to, { recursive: true })
+      await execFile("mount", ["--rbind", from, to])
+    }
+ 
+    return new Overlay(effects, id, rootfs, guid)
+  }
+ 
+  async mount(options: MountOptions, path: string): Promise<Overlay> {
+    path = path.startsWith("/")
+      ? `${this.rootfs}${path}`
+      : `${this.rootfs}/${path}`
+    if (options.type === "volume") {
+      const subpath = options.subpath
+        ? options.subpath.startsWith("/")
+          ? options.subpath
+          : `/${options.subpath}`
+        : "/"
+      const from = `/media/startos/volumes/${options.id}${subpath}`
+ 
+      await fs.mkdir(from, { recursive: true })
+      await fs.mkdir(path, { recursive: true })
+      await await execFile("mount", ["--bind", from, path])
+    } else if (options.type === "assets") {
+      const subpath = options.subpath
+        ? options.subpath.startsWith("/")
+          ? options.subpath
+          : `/${options.subpath}`
+        : "/"
+      const from = `/media/startos/assets/${options.id}${subpath}`
+ 
+      await fs.mkdir(from, { recursive: true })
+      await fs.mkdir(path, { recursive: true })
+      await execFile("mount", ["--bind", from, path])
+    } else if (options.type === "pointer") {
+      await this.effects.mount({ location: path, target: options })
+    } else if (options.type === "backup") {
+      const subpath = options.subpath
+        ? options.subpath.startsWith("/")
+          ? options.subpath
+          : `/${options.subpath}`
+        : "/"
+      const from = `/media/startos/backup${subpath}`
+ 
+      await fs.mkdir(from, { recursive: true })
+      await fs.mkdir(path, { recursive: true })
+      await execFile("mount", ["--bind", from, path])
+    } else {
+      throw new Error(`unknown type ${(options as any).type}`)
+    }
+    return this
+  }
+ 
+  async destroy() {
+    const imageId = this.imageId
+    const guid = this.guid
+    await this.effects.destroyOverlayedImage({ guid })
+  }
+ 
+  async exec(
+    command: string[],
+    options?: CommandOptions,
+    timeoutMs: number | null = 30000,
+  ): Promise<{
+    exitCode: number | null
+    exitSignal: NodeJS.Signals | null
+    stdout: string | Buffer
+    stderr: string | Buffer
+  }> {
+    const imageMeta: T.ImageMetadata = await fs
+      .readFile(`/media/startos/images/${this.imageId}.json`, {
+        encoding: "utf8",
+      })
+      .catch(() => "{}")
+      .then(JSON.parse)
+    let extra: string[] = []
+    Iif (options?.user) {
+      extra.push(`--user=${options.user}`)
+      delete options.user
+    }
+    let workdir = imageMeta.workdir || "/"
+    Iif (options?.cwd) {
+      workdir = options.cwd
+      delete options.cwd
+    }
+    const child = cp.spawn(
+      "start-cli",
+      [
+        "chroot",
+        `--env=/media/startos/images/${this.imageId}.env`,
+        `--workdir=${workdir}`,
+        ...extra,
+        this.rootfs,
+        ...command,
+      ],
+      options || {},
+    )
+    const pid = child.pid
+    const stdout = { data: "" as string | Buffer }
+    const stderr = { data: "" as string | Buffer }
+    const appendData =
+      (appendTo: { data: string | Buffer }) =>
+      (chunk: string | Buffer | any) => {
+        if (typeof appendTo.data === "string" && typeof chunk === "string") {
+          appendTo.data += chunk
+        } else if (typeof chunk === "string" || chunk instanceof Buffer) {
+          appendTo.data = Buffer.concat([
+            Buffer.from(appendTo.data),
+            Buffer.from(chunk),
+          ])
+        } else {
+          console.error("received unexpected chunk", chunk)
+        }
+      }
+    return new Promise((resolve, reject) => {
+      child.on("error", reject)
+      Iif (timeoutMs !== null && pid) {
+        setTimeout(
+          () => execFile("pkill", ["-9", "-s", String(pid)]).catch((_) => {}),
+          timeoutMs,
+        )
+      }
+      child.stdout.on("data", appendData(stdout))
+      child.stderr.on("data", appendData(stderr))
+      child.on("exit", (code, signal) =>
+        resolve({
+          exitCode: code,
+          exitSignal: signal,
+          stdout: stdout.data,
+          stderr: stderr.data,
+        }),
+      )
+    })
+  }
+ 
+  async spawn(
+    command: string[],
+    options?: CommandOptions,
+  ): Promise<cp.ChildProcessWithoutNullStreams> {
+    const imageMeta: any = await fs
+      .readFile(`/media/startos/images/${this.imageId}.json`, {
+        encoding: "utf8",
+      })
+      .catch(() => "{}")
+      .then(JSON.parse)
+    let extra: string[] = []
+    Iif (options?.user) {
+      extra.push(`--user=${options.user}`)
+      delete options.user
+    }
+    let workdir = imageMeta.workdir || "/"
+    Iif (options?.cwd) {
+      workdir = options.cwd
+      delete options.cwd
+    }
+    return cp.spawn(
+      "start-cli",
+      [
+        "chroot",
+        `--env=/media/startos/images/${this.imageId}.env`,
+        `--workdir=${workdir}`,
+        ...extra,
+        this.rootfs,
+        ...command,
+      ],
+      options,
+    )
+  }
+}
+ 
+export type CommandOptions = {
+  env?: { [variable: string]: string }
+  cwd?: string
+  user?: string
+}
+ 
+export type MountOptions =
+  | MountOptionsVolume
+  | MountOptionsAssets
+  | MountOptionsPointer
+  | MountOptionsBackup
+ 
+export type MountOptionsVolume = {
+  type: "volume"
+  id: string
+  subpath: string | null
+  readonly: boolean
+}
+ 
+export type MountOptionsAssets = {
+  type: "assets"
+  id: string
+  subpath: string | null
+}
+ 
+export type MountOptionsPointer = {
+  type: "pointer"
+  packageId: string
+  volumeId: string
+  subpath: string | null
+  readonly: boolean
+}
+ 
+export type MountOptionsBackup = {
+  type: "backup"
+  subpath: string | null
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/util/SubContainer.ts.html b/sdk/lib/coverage/lcov-report/lib/util/SubContainer.ts.html new file mode 100644 index 000000000..6ad137560 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/util/SubContainer.ts.html @@ -0,0 +1,1387 @@ + + + + + + Code coverage report for lib/util/SubContainer.ts + + + + + + + + + +
+
+

All files / lib/util SubContainer.ts

+
+ +
+ 6.79% + Statements + 11/162 +
+ + +
+ 0% + Branches + 0/55 +
+ + +
+ 0% + Functions + 0/36 +
+ + +
+ 7% + Lines + 11/157 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335 +336 +337 +338 +339 +340 +341 +342 +343 +344 +345 +346 +347 +348 +349 +350 +351 +352 +353 +354 +355 +356 +357 +358 +359 +360 +361 +362 +363 +364 +365 +366 +367 +368 +369 +370 +371 +372 +373 +374 +375 +376 +377 +378 +379 +380 +381 +382 +383 +384 +385 +386 +387 +388 +389 +390 +391 +392 +393 +394 +395 +396 +397 +398 +399 +400 +401 +402 +403 +404 +405 +406 +407 +408 +409 +410 +411 +412 +413 +414 +415 +416 +417 +418 +419 +420 +421 +422 +423 +424 +425 +426 +427 +428 +429 +430 +431 +432 +433 +434 +4355x +  +5x +5x +5x +5x +5x +5x +5x +  +  +  +  +  +  +  +  +  +  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import * as fs from "fs/promises"
+import * as T from "../types"
+import * as cp from "child_process"
+import { promisify } from "util"
+import { Buffer } from "node:buffer"
+import { once } from "./once"
+export const execFile = promisify(cp.execFile)
+const WORKDIR = (imageId: string) => `/media/startos/images/${imageId}/`
+const False = () => false
+type ExecResults = {
+  exitCode: number | null
+  exitSignal: NodeJS.Signals | null
+  stdout: string | Buffer
+  stderr: string | Buffer
+}
+ 
+export type ExecOptions = {
+  input?: string | Buffer
+}
+ 
+const TIMES_TO_WAIT_FOR_PROC = 100
+ 
+/**
+ * This is the type that is going to describe what an subcontainer could do. The main point of the
+ * subcontainer is to have commands that run in a chrooted environment. This is useful for running
+ * commands in a containerized environment. But, I wanted the destroy to sometimes be doable, for example the
+ * case where the subcontainer isn't owned by the process, the subcontainer shouldn't be destroyed.
+ */
+export interface ExecSpawnable {
+  get destroy(): undefined | (() => Promise<void>)
+  exec(
+    command: string[],
+    options?: CommandOptions & ExecOptions,
+    timeoutMs?: number | null,
+  ): Promise<ExecResults>
+  spawn(
+    command: string[],
+    options?: CommandOptions,
+  ): Promise<cp.ChildProcessWithoutNullStreams>
+}
+/**
+ * Want to limit what we can do in a container, so we want to launch a container with a specific image and the mounts.
+ *
+ * Implements:
+ * @see {@link ExecSpawnable}
+ */
+export class SubContainer implements ExecSpawnable {
+  private leader: cp.ChildProcess
+  private leaderExited: boolean = false
+  private waitProc: () => Promise<void>
+  private constructor(
+    readonly effects: T.Effects,
+    readonly imageId: T.ImageId,
+    readonly rootfs: string,
+    readonly guid: T.Guid,
+  ) {
+    this.leaderExited = false
+    this.leader = cp.spawn("start-cli", ["subcontainer", "launch", rootfs], {
+      killSignal: "SIGKILL",
+      stdio: "ignore",
+    })
+    this.leader.on("exit", () => {
+      this.leaderExited = true
+    })
+    this.waitProc = once(
+      () =>
+        new Promise(async (resolve, reject) => {
+          let count = 0
+          while (
+            !(await fs.stat(`${this.rootfs}/proc/1`).then((x) => !!x, False))
+          ) {
+            Iif (count++ > TIMES_TO_WAIT_FOR_PROC) {
+              console.debug("Failed to start subcontainer", {
+                guid: this.guid,
+                imageId: this.imageId,
+                rootfs: this.rootfs,
+              })
+              reject(new Error(`Failed to start subcontainer ${this.imageId}`))
+            }
+            await wait(1)
+          }
+          resolve()
+        }),
+    )
+  }
+  static async of(
+    effects: T.Effects,
+    image: { id: T.ImageId; sharedRun?: boolean },
+  ) {
+    const { id, sharedRun } = image
+    const [rootfs, guid] = await effects.subcontainer.createFs({
+      imageId: id as string,
+    })
+ 
+    const shared = ["dev", "sys"]
+    Iif (!!sharedRun) {
+      shared.push("run")
+    }
+ 
+    fs.copyFile("/etc/resolv.conf", `${rootfs}/etc/resolv.conf`)
+ 
+    for (const dirPart of shared) {
+      const from = `/${dirPart}`
+      const to = `${rootfs}/${dirPart}`
+      await fs.mkdir(from, { recursive: true })
+      await fs.mkdir(to, { recursive: true })
+      await execFile("mount", ["--rbind", from, to])
+    }
+ 
+    return new SubContainer(effects, id, rootfs, guid)
+  }
+ 
+  static async with<T>(
+    effects: T.Effects,
+    image: { id: T.ImageId; sharedRun?: boolean },
+    mounts: { options: MountOptions; path: string }[],
+    fn: (subContainer: SubContainer) => Promise<T>,
+  ): Promise<T> {
+    const subContainer = await SubContainer.of(effects, image)
+    try {
+      for (let mount of mounts) {
+        await subContainer.mount(mount.options, mount.path)
+      }
+      return await fn(subContainer)
+    } finally {
+      await subContainer.destroy()
+    }
+  }
+ 
+  async mount(options: MountOptions, path: string): Promise<SubContainer> {
+    path = path.startsWith("/")
+      ? `${this.rootfs}${path}`
+      : `${this.rootfs}/${path}`
+    if (options.type === "volume") {
+      const subpath = options.subpath
+        ? options.subpath.startsWith("/")
+          ? options.subpath
+          : `/${options.subpath}`
+        : "/"
+      const from = `/media/startos/volumes/${options.id}${subpath}`
+ 
+      await fs.mkdir(from, { recursive: true })
+      await fs.mkdir(path, { recursive: true })
+      await execFile("mount", ["--bind", from, path])
+    } else if (options.type === "assets") {
+      const subpath = options.subpath
+        ? options.subpath.startsWith("/")
+          ? options.subpath
+          : `/${options.subpath}`
+        : "/"
+      const from = `/media/startos/assets/${options.id}${subpath}`
+ 
+      await fs.mkdir(from, { recursive: true })
+      await fs.mkdir(path, { recursive: true })
+      await execFile("mount", ["--bind", from, path])
+    } else if (options.type === "pointer") {
+      await this.effects.mount({ location: path, target: options })
+    } else if (options.type === "backup") {
+      const subpath = options.subpath
+        ? options.subpath.startsWith("/")
+          ? options.subpath
+          : `/${options.subpath}`
+        : "/"
+      const from = `/media/startos/backup${subpath}`
+ 
+      await fs.mkdir(from, { recursive: true })
+      await fs.mkdir(path, { recursive: true })
+      await execFile("mount", ["--bind", from, path])
+    } else {
+      throw new Error(`unknown type ${(options as any).type}`)
+    }
+    return this
+  }
+ 
+  private async killLeader() {
+    Iif (this.leaderExited) {
+      return
+    }
+    return new Promise<void>((resolve, reject) => {
+      try {
+        this.leader.on("exit", () => {
+          resolve()
+        })
+        Iif (!this.leader.kill("SIGKILL")) {
+          reject(new Error("kill(2) failed"))
+        }
+      } catch (e) {
+        reject(e)
+      }
+    })
+  }
+ 
+  get destroy() {
+    return async () => {
+      const guid = this.guid
+      await this.killLeader()
+      await this.effects.subcontainer.destroyFs({ guid })
+    }
+  }
+ 
+  async exec(
+    command: string[],
+    options?: CommandOptions & ExecOptions,
+    timeoutMs: number | null = 30000,
+  ): Promise<{
+    exitCode: number | null
+    exitSignal: NodeJS.Signals | null
+    stdout: string | Buffer
+    stderr: string | Buffer
+  }> {
+    await this.waitProc()
+    const imageMeta: T.ImageMetadata = await fs
+      .readFile(`/media/startos/images/${this.imageId}.json`, {
+        encoding: "utf8",
+      })
+      .catch(() => "{}")
+      .then(JSON.parse)
+    let extra: string[] = []
+    Iif (options?.user) {
+      extra.push(`--user=${options.user}`)
+      delete options.user
+    }
+    let workdir = imageMeta.workdir || "/"
+    Iif (options?.cwd) {
+      workdir = options.cwd
+      delete options.cwd
+    }
+    const child = cp.spawn(
+      "start-cli",
+      [
+        "subcontainer",
+        "exec",
+        `--env=/media/startos/images/${this.imageId}.env`,
+        `--workdir=${workdir}`,
+        ...extra,
+        this.rootfs,
+        ...command,
+      ],
+      options || {},
+    )
+    Iif (options?.input) {
+      await new Promise<void>((resolve, reject) =>
+        child.stdin.write(options.input, (e) => {
+          if (e) {
+            reject(e)
+          } else {
+            resolve()
+          }
+        }),
+      )
+      await new Promise<void>((resolve) => child.stdin.end(resolve))
+    }
+    const pid = child.pid
+    const stdout = { data: "" as string | Buffer }
+    const stderr = { data: "" as string | Buffer }
+    const appendData =
+      (appendTo: { data: string | Buffer }) =>
+      (chunk: string | Buffer | any) => {
+        if (typeof appendTo.data === "string" && typeof chunk === "string") {
+          appendTo.data += chunk
+        } else if (typeof chunk === "string" || chunk instanceof Buffer) {
+          appendTo.data = Buffer.concat([
+            Buffer.from(appendTo.data),
+            Buffer.from(chunk),
+          ])
+        } else {
+          console.error("received unexpected chunk", chunk)
+        }
+      }
+    return new Promise((resolve, reject) => {
+      child.on("error", reject)
+      let killTimeout: NodeJS.Timeout | undefined
+      Iif (timeoutMs !== null && child.pid) {
+        killTimeout = setTimeout(() => child.kill("SIGKILL"), timeoutMs)
+      }
+      child.stdout.on("data", appendData(stdout))
+      child.stderr.on("data", appendData(stderr))
+      child.on("exit", (code, signal) => {
+        clearTimeout(killTimeout)
+        resolve({
+          exitCode: code,
+          exitSignal: signal,
+          stdout: stdout.data,
+          stderr: stderr.data,
+        })
+      })
+    })
+  }
+ 
+  async launch(
+    command: string[],
+    options?: CommandOptions,
+  ): Promise<cp.ChildProcessWithoutNullStreams> {
+    await this.waitProc()
+    const imageMeta: any = await fs
+      .readFile(`/media/startos/images/${this.imageId}.json`, {
+        encoding: "utf8",
+      })
+      .catch(() => "{}")
+      .then(JSON.parse)
+    let extra: string[] = []
+    Iif (options?.user) {
+      extra.push(`--user=${options.user}`)
+      delete options.user
+    }
+    let workdir = imageMeta.workdir || "/"
+    Iif (options?.cwd) {
+      workdir = options.cwd
+      delete options.cwd
+    }
+    await this.killLeader()
+    this.leaderExited = false
+    this.leader = cp.spawn(
+      "start-cli",
+      [
+        "subcontainer",
+        "launch",
+        `--env=/media/startos/images/${this.imageId}.env`,
+        `--workdir=${workdir}`,
+        ...extra,
+        this.rootfs,
+        ...command,
+      ],
+      { ...options, stdio: "inherit" },
+    )
+    this.leader.on("exit", () => {
+      this.leaderExited = true
+    })
+    return this.leader as cp.ChildProcessWithoutNullStreams
+  }
+ 
+  async spawn(
+    command: string[],
+    options?: CommandOptions,
+  ): Promise<cp.ChildProcessWithoutNullStreams> {
+    await this.waitProc()
+    const imageMeta: any = await fs
+      .readFile(`/media/startos/images/${this.imageId}.json`, {
+        encoding: "utf8",
+      })
+      .catch(() => "{}")
+      .then(JSON.parse)
+    let extra: string[] = []
+    Iif (options?.user) {
+      extra.push(`--user=${options.user}`)
+      delete options.user
+    }
+    let workdir = imageMeta.workdir || "/"
+    Iif (options?.cwd) {
+      workdir = options.cwd
+      delete options.cwd
+    }
+    return cp.spawn(
+      "start-cli",
+      [
+        "subcontainer",
+        "exec",
+        `--env=/media/startos/images/${this.imageId}.env`,
+        `--workdir=${workdir}`,
+        ...extra,
+        this.rootfs,
+        ...command,
+      ],
+      options,
+    )
+  }
+}
+ 
+/**
+ * Take an subcontainer but remove the ability to add the mounts and the destroy function.
+ * Lets other functions, like health checks, to not destroy the parents.
+ *
+ */
+export class SubContainerHandle implements ExecSpawnable {
+  constructor(private subContainer: ExecSpawnable) {}
+  get destroy() {
+    return undefined
+  }
+ 
+  exec(
+    command: string[],
+    options?: CommandOptions,
+    timeoutMs?: number | null,
+  ): Promise<ExecResults> {
+    return this.subContainer.exec(command, options, timeoutMs)
+  }
+  spawn(
+    command: string[],
+    options?: CommandOptions,
+  ): Promise<cp.ChildProcessWithoutNullStreams> {
+    return this.subContainer.spawn(command, options)
+  }
+}
+ 
+export type CommandOptions = {
+  env?: { [variable: string]: string }
+  cwd?: string
+  user?: string
+}
+ 
+export type MountOptions =
+  | MountOptionsVolume
+  | MountOptionsAssets
+  | MountOptionsPointer
+  | MountOptionsBackup
+ 
+export type MountOptionsVolume = {
+  type: "volume"
+  id: string
+  subpath: string | null
+  readonly: boolean
+}
+ 
+export type MountOptionsAssets = {
+  type: "assets"
+  id: string
+  subpath: string | null
+}
+ 
+export type MountOptionsPointer = {
+  type: "pointer"
+  packageId: string
+  volumeId: string
+  subpath: string | null
+  readonly: boolean
+}
+ 
+export type MountOptionsBackup = {
+  type: "backup"
+  subpath: string | null
+}
+function wait(time: number) {
+  return new Promise((resolve) => setTimeout(resolve, time))
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/util/asError.ts.html b/sdk/lib/coverage/lcov-report/lib/util/asError.ts.html new file mode 100644 index 000000000..2dac8daf6 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/util/asError.ts.html @@ -0,0 +1,103 @@ + + + + + + Code coverage report for lib/util/asError.ts + + + + + + + + + +
+
+

All files / lib/util asError.ts

+
+ +
+ 40% + Statements + 2/5 +
+ + +
+ 0% + Branches + 0/1 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 25% + Lines + 1/4 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +75x +  +  +  +  +  + 
export const asError = (e: unknown) => {
+  Iif (e instanceof Error) {
+    return new Error(e as any)
+  }
+  return new Error(`${e}`)
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/util/deepEqual.ts.html b/sdk/lib/coverage/lcov-report/lib/util/deepEqual.ts.html new file mode 100644 index 000000000..dba969e68 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/util/deepEqual.ts.html @@ -0,0 +1,142 @@ + + + + + + Code coverage report for lib/util/deepEqual.ts + + + + + + + + + +
+
+

All files / lib/util deepEqual.ts

+
+ +
+ 66.66% + Statements + 14/21 +
+ + +
+ 16.66% + Branches + 1/6 +
+ + +
+ 100% + Functions + 2/2 +
+ + +
+ 85.71% + Lines + 12/14 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +206x +  +6x +11x +3x +3x +  +  +  +3x +6x +3x +5x +10x +10x +  +  +3x +  + 
import { object } from "ts-matches"
+ 
+export function deepEqual(...args: unknown[]) {
+  if (!object.test(args[args.length - 1])) return args[args.length - 1]
+  const objects = args.filter(object.test)
+  Iif (objects.length === 0) {
+    for (const x of args) Iif (x !== args[0]) return false
+    return true
+  }
+  Iif (objects.length !== args.length) return false
+  const allKeys = new Set(objects.flatMap((x) => Object.keys(x)))
+  for (const key of allKeys) {
+    for (const x of objects) {
+      Iif (!(key in x)) return false
+      Iif (!deepEqual((objects[0] as any)[key], (x as any)[key])) return false
+    }
+  }
+  return true
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/util/deepMerge.ts.html b/sdk/lib/coverage/lcov-report/lib/util/deepMerge.ts.html new file mode 100644 index 000000000..4edc6d77d --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/util/deepMerge.ts.html @@ -0,0 +1,136 @@ + + + + + + Code coverage report for lib/util/deepMerge.ts + + + + + + + + + +
+
+

All files / lib/util deepMerge.ts

+
+ +
+ 100% + Statements + 18/18 +
+ + +
+ 100% + Branches + 5/5 +
+ + +
+ 100% + Functions + 4/4 +
+ + +
+ 100% + Lines + 13/13 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +186x +  +6x +253x +253x +126x +97x +71x +149x +71x +242x +528x +  +242x +  +71x +  + 
import { object } from "ts-matches"
+ 
+export function deepMerge(...args: unknown[]): unknown {
+  const lastItem = (args as any)[args.length - 1]
+  if (!object.test(lastItem)) return lastItem
+  const objects = args.filter(object.test).filter((x) => !Array.isArray(x))
+  if (objects.length === 0) return lastItem as any
+  if (objects.length === 1) objects.unshift({})
+  const allKeys = new Set(objects.flatMap((x) => Object.keys(x)))
+  for (const key of allKeys) {
+    const filteredValues = objects.flatMap((x) =>
+      key in x ? [(x as any)[key]] : [],
+    )
+    ;(objects as any)[0][key] = deepMerge(...filteredValues)
+  }
+  return objects[0] as any
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/util/fileHelper.ts.html b/sdk/lib/coverage/lcov-report/lib/util/fileHelper.ts.html new file mode 100644 index 000000000..27c6422f7 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/util/fileHelper.ts.html @@ -0,0 +1,535 @@ + + + + + + Code coverage report for lib/util/fileHelper.ts + + + + + + + + + +
+
+

All files / lib/util fileHelper.ts

+
+ +
+ 20.58% + Statements + 7/34 +
+ + +
+ 0% + Branches + 0/4 +
+ + +
+ 0% + Functions + 0/18 +
+ + +
+ 21.21% + Lines + 7/33 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151  +5x +5x +5x +  +5x +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +5x + 
import * as matches from "ts-matches"
+import * as YAML from "yaml"
+import * as TOML from "@iarna/toml"
+import merge from "lodash.merge"
+import * as T from "../types"
+import * as fs from "node:fs/promises"
+ 
+const previousPath = /(.+?)\/([^/]*)$/
+ 
+/**
+ * Used in the get config and the set config exported functions.
+ * The idea is that we are going to be reading/ writing to a file, or multiple files. And then we use this tool
+ * to keep the same path on the read and write, and have methods for helping with structured data.
+ * And if we are not using a structured data, we can use the raw method which forces the construction of a BiMap
+ * ```ts
+        import {InputSpec} from './InputSpec.ts'
+        import {matches, T} from '../deps.ts';
+        const { object, string, number, boolean, arrayOf, array, anyOf, allOf } = matches
+        const someValidator = object({
+        data: string
+        })
+        const jsonFile = FileHelper.json({
+        path: 'data.json',
+        validator: someValidator,
+        volume: 'main'
+        })
+        const  tomlFile = FileHelper.toml({
+        path: 'data.toml',
+        validator: someValidator,
+        volume: 'main'
+        })
+        const rawFile = FileHelper.raw({
+        path: 'data.amazingSettings',
+        volume: 'main'
+        fromData(dataIn: Data): string {
+            return `myDatais ///- ${dataIn.data}`
+        },
+        toData(rawData: string): Data {
+        const [,data] = /myDatais \/\/\/- (.*)/.match(rawData)
+        return {data}
+        }
+        })
+ 
+        export const setConfig : T.ExpectedExports.setConfig= async (effects, config) => {
+        await  jsonFile.write({ data: 'here lies data'}, effects)
+        }
+ 
+        export const getConfig: T.ExpectedExports.getConfig = async (effects, config) => ({
+        spec: InputSpec,
+        config: nullIfEmpty({
+            ...jsonFile.get(effects)
+        })
+    ```
+ */
+export class FileHelper<A> {
+  protected constructor(
+    readonly path: string,
+    readonly writeData: (dataIn: A) => string,
+    readonly readData: (stringValue: string) => A,
+  ) {}
+  async write(data: A, effects: T.Effects) {
+    const parent = previousPath.exec(this.path)
+    Iif (parent) {
+      await fs.mkdir(parent[1], { recursive: true })
+    }
+ 
+    await fs.writeFile(this.path, this.writeData(data))
+  }
+  async read(effects: T.Effects) {
+    Iif (
+      !(await fs.access(this.path).then(
+        () => true,
+        () => false,
+      ))
+    ) {
+      return null
+    }
+    return this.readData(
+      await fs.readFile(this.path).then((data) => data.toString("utf-8")),
+    )
+  }
+ 
+  async merge(data: A, effects: T.Effects) {
+    const fileData = (await this.read(effects).catch(() => ({}))) || {}
+    const mergeData = merge({}, fileData, data)
+    return await this.write(mergeData, effects)
+  }
+  /**
+   * Create a File Helper for an arbitrary file type.
+   *
+   * Provide custom functions for translating data to the file format and visa versa.
+   */
+  static raw<A>(
+    path: string,
+    toFile: (dataIn: A) => string,
+    fromFile: (rawData: string) => A,
+  ) {
+    return new FileHelper<A>(path, toFile, fromFile)
+  }
+  /**
+   * Create a File Helper for a .json file
+   */
+  static json<A>(path: string, shape: matches.Validator<unknown, A>) {
+    return new FileHelper<A>(
+      path,
+      (inData) => {
+        return JSON.stringify(inData, null, 2)
+      },
+      (inString) => {
+        return shape.unsafeCast(JSON.parse(inString))
+      },
+    )
+  }
+  /**
+   * Create a File Helper for a .toml file
+   */
+  static toml<A extends Record<string, unknown>>(
+    path: string,
+    shape: matches.Validator<unknown, A>,
+  ) {
+    return new FileHelper<A>(
+      path,
+      (inData) => {
+        return TOML.stringify(inData as any)
+      },
+      (inString) => {
+        return shape.unsafeCast(TOML.parse(inString))
+      },
+    )
+  }
+  /**
+   * Create a File Helper for a .yaml file
+   */
+  static yaml<A extends Record<string, unknown>>(
+    path: string,
+    shape: matches.Validator<unknown, A>,
+  ) {
+    return new FileHelper<A>(
+      path,
+      (inData) => {
+        return YAML.stringify(inData, null, 2)
+      },
+      (inString) => {
+        return shape.unsafeCast(YAML.parse(inString))
+      },
+    )
+  }
+}
+ 
+export default FileHelper
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/util/getDefaultString.ts.html b/sdk/lib/coverage/lcov-report/lib/util/getDefaultString.ts.html new file mode 100644 index 000000000..d4c4f9f96 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/util/getDefaultString.ts.html @@ -0,0 +1,115 @@ + + + + + + Code coverage report for lib/util/getDefaultString.ts + + + + + + + + + +
+
+

All files / lib/util getDefaultString.ts

+
+ +
+ 40% + Statements + 2/5 +
+ + +
+ 0% + Branches + 0/2 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 40% + Lines + 2/5 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11  +5x +  +5x +  +  +  +  +  +  + 
import { DefaultString } from "../config/configTypes"
+import { getRandomString } from "./getRandomString"
+ 
+export function getDefaultString(defaultSpec: DefaultString): string {
+  if (typeof defaultSpec === "string") {
+    return defaultSpec
+  } else {
+    return getRandomString(defaultSpec)
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/util/getRandomCharInSet.ts.html b/sdk/lib/coverage/lcov-report/lib/util/getRandomCharInSet.ts.html new file mode 100644 index 000000000..9f9ff1a4b --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/util/getRandomCharInSet.ts.html @@ -0,0 +1,382 @@ + + + + + + Code coverage report for lib/util/getRandomCharInSet.ts + + + + + + + + + +
+
+

All files / lib/util getRandomCharInSet.ts

+
+ +
+ 1.78% + Statements + 1/56 +
+ + +
+ 0% + Branches + 0/42 +
+ + +
+ 0% + Functions + 0/2 +
+ + +
+ 1.78% + Lines + 1/56 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
// a,g,h,A-Z,,,,-
+ 
+export function getRandomCharInSet(charset: string): string {
+  const set = stringToCharSet(charset)
+  let charIdx = Math.floor(
+    (crypto.getRandomValues(new Uint32Array(1))[0] / 2 ** 32) * set.len,
+  )
+  for (let range of set.ranges) {
+    Iif (range.len > charIdx) {
+      return String.fromCharCode(range.start.charCodeAt(0) + charIdx)
+    }
+    charIdx -= range.len
+  }
+  throw new Error("unreachable")
+}
+function stringToCharSet(charset: string): CharSet {
+  let set: CharSet = { ranges: [], len: 0 }
+  let start: string | null = null
+  let end: string | null = null
+  let in_range = false
+  for (let char of charset) {
+    switch (char) {
+      case ",":
+        if (start !== null && end !== null) {
+          Iif (start!.charCodeAt(0) > end!.charCodeAt(0)) {
+            throw new Error("start > end of charset")
+          }
+          const len = end.charCodeAt(0) - start.charCodeAt(0) + 1
+          set.ranges.push({
+            start,
+            end,
+            len,
+          })
+          set.len += len
+          start = null
+          end = null
+          in_range = false
+        } else if (start !== null && !in_range) {
+          set.len += 1
+          set.ranges.push({ start, end: start, len: 1 })
+          start = null
+        } else if (start !== null && in_range) {
+          end = ","
+        } else if (start === null && end === null && !in_range) {
+          start = ","
+        } else {
+          throw new Error('unexpected ","')
+        }
+        break
+      case "-":
+        if (start === null) {
+          start = "-"
+        } else if (!in_range) {
+          in_range = true
+        } else if (in_range && end === null) {
+          end = "-"
+        } else {
+          throw new Error('unexpected "-"')
+        }
+        break
+      default:
+        if (start === null) {
+          start = char
+        } else if (in_range && end === null) {
+          end = char
+        } else {
+          throw new Error(`unexpected "${char}"`)
+        }
+    }
+  }
+  if (start !== null && end !== null) {
+    Iif (start!.charCodeAt(0) > end!.charCodeAt(0)) {
+      throw new Error("start > end of charset")
+    }
+    const len = end.charCodeAt(0) - start.charCodeAt(0) + 1
+    set.ranges.push({
+      start,
+      end,
+      len,
+    })
+    set.len += len
+  } else Iif (start !== null) {
+    set.len += 1
+    set.ranges.push({
+      start,
+      end: start,
+      len: 1,
+    })
+  }
+  return set
+}
+type CharSet = {
+  ranges: {
+    start: string
+    end: string
+    len: number
+  }[]
+  len: number
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/util/getRandomString.ts.html b/sdk/lib/coverage/lcov-report/lib/util/getRandomString.ts.html new file mode 100644 index 000000000..092f03b3c --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/util/getRandomString.ts.html @@ -0,0 +1,118 @@ + + + + + + Code coverage report for lib/util/getRandomString.ts + + + + + + + + + +
+
+

All files / lib/util getRandomString.ts

+
+ +
+ 28.57% + Statements + 2/7 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 33.33% + Lines + 2/6 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12  +5x +  +5x +  +  +  +  +  +  +  + 
import { RandomString } from "../config/configTypes"
+import { getRandomCharInSet } from "./getRandomCharInSet"
+ 
+export function getRandomString(generator: RandomString): string {
+  let s = ""
+  for (let i = 0; i < generator.len; i++) {
+    s = s + getRandomCharInSet(generator.charset)
+  }
+ 
+  return s
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/util/getServiceInterface.ts.html b/sdk/lib/coverage/lcov-report/lib/util/getServiceInterface.ts.html new file mode 100644 index 000000000..617f62061 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/util/getServiceInterface.ts.html @@ -0,0 +1,937 @@ + + + + + + Code coverage report for lib/util/getServiceInterface.ts + + + + + + + + + +
+
+

All files / lib/util getServiceInterface.ts

+
+ +
+ 20.43% + Statements + 19/93 +
+ + +
+ 0% + Branches + 0/37 +
+ + +
+ 2.63% + Functions + 1/38 +
+ + +
+ 18.82% + Lines + 16/85 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285  +6x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +6x +6x +8x +8x +8x +8x +8x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +6x +  +  +  +6x +  +  +6x +6x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +6x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +6x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +6x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +6x +  +  +  +  +  + 
import { ServiceInterfaceType } from "../StartSdk"
+import { knownProtocols } from "../interfaces/Host"
+import {
+  AddressInfo,
+  Effects,
+  Host,
+  HostAddress,
+  Hostname,
+  HostnameInfo,
+  HostnameInfoIp,
+  HostnameInfoOnion,
+  IpInfo,
+} from "../types"
+ 
+export type UrlString = string
+export type HostId = string
+ 
+const getHostnameRegex = /^(\w+:\/\/)?([^\/\:]+)(:\d{1,3})?(\/)?/
+export const getHostname = (url: string): Hostname | null => {
+  const founds = url.match(getHostnameRegex)?.[2]
+  Iif (!founds) return null
+  const parts = founds.split("@")
+  const last = parts[parts.length - 1] as Hostname | null
+  return last
+}
+ 
+export type Filled = {
+  hostnames: HostnameInfo[]
+  onionHostnames: HostnameInfo[]
+  localHostnames: HostnameInfo[]
+  ipHostnames: HostnameInfo[]
+  ipv4Hostnames: HostnameInfo[]
+  ipv6Hostnames: HostnameInfo[]
+  nonIpHostnames: HostnameInfo[]
+ 
+  urls: UrlString[]
+  onionUrls: UrlString[]
+  localUrls: UrlString[]
+  ipUrls: UrlString[]
+  ipv4Urls: UrlString[]
+  ipv6Urls: UrlString[]
+  nonIpUrls: UrlString[]
+}
+export type FilledAddressInfo = AddressInfo & Filled
+export type ServiceInterfaceFilled = {
+  id: string
+  /** The title of this field to be displayed */
+  name: string
+  /** Human readable description, used as tooltip usually */
+  description: string
+  /** Whether or not the interface has a primary URL */
+  hasPrimary: boolean
+  /** Whether or not to mask the URIs for this interface. Useful if the URIs contain sensitive information, such as a password, macaroon, or API key */
+  masked: boolean
+  /** Information about the host for this binding */
+  host: Host | null
+  /** URI information */
+  addressInfo: FilledAddressInfo | null
+  /** Indicates if we are a ui/p2p/api for the kind of interface that this is representing */
+  type: ServiceInterfaceType
+  /** The primary hostname for the service, as chosen by the user */
+  primaryHostname: Hostname | null
+  /** The primary URL for the service, as chosen by the user */
+  primaryUrl: UrlString | null
+}
+const either =
+  <A>(...args: ((a: A) => boolean)[]) =>
+  (a: A) =>
+    args.some((x) => x(a))
+const negate =
+  <A>(fn: (a: A) => boolean) =>
+  (a: A) =>
+    !fn(a)
+const unique = <A>(values: A[]) => Array.from(new Set(values))
+export const addressHostToUrl = (
+  { scheme, sslScheme, username, suffix }: AddressInfo,
+  host: HostnameInfo,
+): UrlString[] => {
+  const res = []
+  const fmt = (scheme: string | null, host: HostnameInfo, port: number) => {
+    const excludePort =
+      scheme &&
+      scheme in knownProtocols &&
+      port === knownProtocols[scheme as keyof typeof knownProtocols].defaultPort
+    let hostname
+    if (host.kind === "onion") {
+      hostname = host.hostname.value
+    } else Iif (host.kind === "ip") {
+      if (host.hostname.kind === "domain") {
+        hostname = `${host.hostname.subdomain ? `${host.hostname.subdomain}.` : ""}${host.hostname.domain}`
+      } else if (host.hostname.kind === "ipv6") {
+        hostname = `[${host.hostname.value}]`
+      } else {
+        hostname = host.hostname.value
+      }
+    }
+    return `${scheme ? `${scheme}://` : ""}${
+      username ? `${username}@` : ""
+    }${hostname}${excludePort ? "" : `:${port}`}${suffix}`
+  }
+  Iif (host.hostname.sslPort !== null) {
+    res.push(fmt(sslScheme, host, host.hostname.sslPort))
+  }
+  Iif (host.hostname.port !== null) {
+    res.push(fmt(scheme, host, host.hostname.port))
+  }
+ 
+  return res
+}
+ 
+export const filledAddress = (
+  host: Host,
+  addressInfo: AddressInfo,
+): FilledAddressInfo => {
+  const toUrl = addressHostToUrl.bind(null, addressInfo)
+  const hostnames = host.hostnameInfo[addressInfo.internalPort]
+ 
+  return {
+    ...addressInfo,
+    hostnames,
+    get onionHostnames() {
+      return hostnames.filter((h) => h.kind === "onion")
+    },
+    get localHostnames() {
+      return hostnames.filter(
+        (h) => h.kind === "ip" && h.hostname.kind === "local",
+      )
+    },
+    get ipHostnames() {
+      return hostnames.filter(
+        (h) =>
+          h.kind === "ip" &&
+          (h.hostname.kind === "ipv4" || h.hostname.kind === "ipv6"),
+      )
+    },
+    get ipv4Hostnames() {
+      return hostnames.filter(
+        (h) => h.kind === "ip" && h.hostname.kind === "ipv4",
+      )
+    },
+    get ipv6Hostnames() {
+      return hostnames.filter(
+        (h) => h.kind === "ip" && h.hostname.kind === "ipv6",
+      )
+    },
+    get nonIpHostnames() {
+      return hostnames.filter(
+        (h) =>
+          h.kind === "ip" &&
+          h.hostname.kind !== "ipv4" &&
+          h.hostname.kind !== "ipv6",
+      )
+    },
+    get urls() {
+      return this.hostnames.flatMap(toUrl)
+    },
+    get onionUrls() {
+      return this.onionHostnames.flatMap(toUrl)
+    },
+    get localUrls() {
+      return this.localHostnames.flatMap(toUrl)
+    },
+    get ipUrls() {
+      return this.ipHostnames.flatMap(toUrl)
+    },
+    get ipv4Urls() {
+      return this.ipv4Hostnames.flatMap(toUrl)
+    },
+    get ipv6Urls() {
+      return this.ipv6Hostnames.flatMap(toUrl)
+    },
+    get nonIpUrls() {
+      return this.nonIpHostnames.flatMap(toUrl)
+    },
+  }
+}
+ 
+const makeInterfaceFilled = async ({
+  effects,
+  id,
+  packageId,
+  callback,
+}: {
+  effects: Effects
+  id: string
+  packageId?: string
+  callback?: () => void
+}) => {
+  const serviceInterfaceValue = await effects.getServiceInterface({
+    serviceInterfaceId: id,
+    packageId,
+    callback,
+  })
+  Iif (!serviceInterfaceValue) {
+    return null
+  }
+  const hostId = serviceInterfaceValue.addressInfo.hostId
+  const host = await effects.getHostInfo({
+    packageId,
+    hostId,
+    callback,
+  })
+  const primaryUrl = await effects.getPrimaryUrl({
+    hostId,
+    packageId,
+    callback,
+  })
+ 
+  const interfaceFilled: ServiceInterfaceFilled = {
+    ...serviceInterfaceValue,
+    primaryUrl: primaryUrl,
+    host,
+    addressInfo: host
+      ? filledAddress(host, serviceInterfaceValue.addressInfo)
+      : null,
+    get primaryHostname() {
+      Iif (primaryUrl == null) return null
+      return getHostname(primaryUrl)
+    },
+  }
+  return interfaceFilled
+}
+ 
+export class GetServiceInterface {
+  constructor(
+    readonly effects: Effects,
+    readonly opts: { id: string; packageId?: string },
+  ) {}
+ 
+  /**
+   * Returns the value of Store at the provided path. Restart the service if the value changes
+   */
+  async const() {
+    const { id, packageId } = this.opts
+    const callback = this.effects.restart
+    const interfaceFilled = await makeInterfaceFilled({
+      effects: this.effects,
+      id,
+      packageId,
+      callback,
+    })
+ 
+    return interfaceFilled
+  }
+  /**
+   * Returns the value of ServiceInterfacesFilled at the provided path. Does nothing if the value changes
+   */
+  async once() {
+    const { id, packageId } = this.opts
+    const interfaceFilled = await makeInterfaceFilled({
+      effects: this.effects,
+      id,
+      packageId,
+    })
+ 
+    return interfaceFilled
+  }
+ 
+  /**
+   * Watches the value of ServiceInterfacesFilled at the provided path. Takes a custom callback function to run whenever the value changes
+   */
+  async *watch() {
+    const { id, packageId } = this.opts
+    while (true) {
+      let callback: () => void = () => {}
+      const waitForNext = new Promise<void>((resolve) => {
+        callback = resolve
+      })
+      yield await makeInterfaceFilled({
+        effects: this.effects,
+        id,
+        packageId,
+        callback,
+      })
+      await waitForNext
+    }
+  }
+}
+export function getServiceInterface(
+  effects: Effects,
+  opts: { id: string; packageId?: string },
+) {
+  return new GetServiceInterface(effects, opts)
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/util/getServiceInterfaces.ts.html b/sdk/lib/coverage/lcov-report/lib/util/getServiceInterfaces.ts.html new file mode 100644 index 000000000..e4fa4a190 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/util/getServiceInterfaces.ts.html @@ -0,0 +1,427 @@ + + + + + + Code coverage report for lib/util/getServiceInterfaces.ts + + + + + + + + + +
+
+

All files / lib/util getServiceInterfaces.ts

+
+ +
+ 11.76% + Statements + 4/34 +
+ + +
+ 0% + Branches + 0/2 +
+ + +
+ 0% + Functions + 0/11 +
+ + +
+ 12.12% + Lines + 4/33 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115  +5x +  +  +  +  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +5x +  +  +  +  +  + 
import { Effects } from "../types"
+import {
+  ServiceInterfaceFilled,
+  filledAddress,
+  getHostname,
+} from "./getServiceInterface"
+ 
+const makeManyInterfaceFilled = async ({
+  effects,
+  packageId,
+  callback,
+}: {
+  effects: Effects
+  packageId?: string
+  callback?: () => void
+}) => {
+  const serviceInterfaceValues = await effects.listServiceInterfaces({
+    packageId,
+    callback,
+  })
+ 
+  const serviceInterfacesFilled: ServiceInterfaceFilled[] = await Promise.all(
+    Object.values(serviceInterfaceValues).map(async (serviceInterfaceValue) => {
+      const hostId = serviceInterfaceValue.addressInfo.hostId
+      const host = await effects.getHostInfo({
+        packageId,
+        hostId,
+        callback,
+      })
+      Iif (!host) {
+        throw new Error(`host ${hostId} not found!`)
+      }
+      const primaryUrl = await effects
+        .getPrimaryUrl({
+          hostId,
+          packageId,
+          callback,
+        })
+        .catch(() => null)
+      return {
+        ...serviceInterfaceValue,
+        primaryUrl: primaryUrl,
+        host,
+        addressInfo: filledAddress(host, serviceInterfaceValue.addressInfo),
+        get primaryHostname() {
+          Iif (primaryUrl == null) return null
+          return getHostname(primaryUrl)
+        },
+      }
+    }),
+  )
+  return serviceInterfacesFilled
+}
+ 
+export class GetServiceInterfaces {
+  constructor(
+    readonly effects: Effects,
+    readonly opts: { packageId?: string },
+  ) {}
+ 
+  /**
+   * Returns the value of Store at the provided path. Restart the service if the value changes
+   */
+  async const() {
+    const { packageId } = this.opts
+    const callback = this.effects.restart
+    const interfaceFilled: ServiceInterfaceFilled[] =
+      await makeManyInterfaceFilled({
+        effects: this.effects,
+        packageId,
+        callback,
+      })
+ 
+    return interfaceFilled
+  }
+  /**
+   * Returns the value of ServiceInterfacesFilled at the provided path. Does nothing if the value changes
+   */
+  async once() {
+    const { packageId } = this.opts
+    const interfaceFilled: ServiceInterfaceFilled[] =
+      await makeManyInterfaceFilled({
+        effects: this.effects,
+        packageId,
+      })
+ 
+    return interfaceFilled
+  }
+ 
+  /**
+   * Watches the value of ServiceInterfacesFilled at the provided path. Takes a custom callback function to run whenever the value changes
+   */
+  async *watch() {
+    const { packageId } = this.opts
+    while (true) {
+      let callback: () => void = () => {}
+      const waitForNext = new Promise<void>((resolve) => {
+        callback = resolve
+      })
+      yield await makeManyInterfaceFilled({
+        effects: this.effects,
+        packageId,
+        callback,
+      })
+      await waitForNext
+    }
+  }
+}
+export function getServiceInterfaces(
+  effects: Effects,
+  opts: { packageId?: string },
+) {
+  return new GetServiceInterfaces(effects, opts)
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/util/graph.ts.html b/sdk/lib/coverage/lcov-report/lib/util/graph.ts.html new file mode 100644 index 000000000..e621cdbc1 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/util/graph.ts.html @@ -0,0 +1,817 @@ + + + + + + Code coverage report for lib/util/graph.ts + + + + + + + + + +
+
+

All files / lib/util graph.ts

+
+ +
+ 89.83% + Statements + 106/118 +
+ + +
+ 75% + Branches + 18/24 +
+ + +
+ 95.23% + Functions + 20/21 +
+ + +
+ 90.59% + Lines + 106/117 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245  +  +  +  +  +  +  +  +  +  +  +  +  +5x +11x +  +  +  +  +  +  +39x +  +  +  +39x +20x +  +  +  +  +20x +20x +  +39x +1x +  +  +  +  +1x +1x +  +39x +39x +  +  +  +  +1x +  +1x +4x +1x +  +  +  +1x +  +  +  +  +  +  +12x +  +  +  +  +12x +12x +12x +  +  +  +  +  +  +6x +  +  +  +15x +1x +  +14x +14x +14x +23x +9x +14x +16x +16x +16x +18x +18x +9x +9x +  +  +  +  +  +6x +5x +5x +5x +15x +15x +15x +15x +15x +10x +10x +  +  +  +  +  +1x +  +  +  +  +  +  +  +6x +  +  +  +15x +1x +  +14x +14x +14x +23x +9x +14x +16x +16x +16x +18x +18x +9x +9x +  +  +  +  +  +6x +5x +5x +5x +15x +15x +15x +15x +15x +10x +10x +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +3x +  +11x +3x +3x +  +  +  +  +11x +3x +  +8x +  +  +8x +8x +6x +12x +8x +6x +11x +11x +11x +13x +13x +6x +6x +  +  +7x +7x +  +  +  +  +  +3x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +3x +3x +11x +11x +3x +  +  +  +  +  + 
import { boolean } from "ts-matches"
+ 
+export type Vertex<VMetadata = void, EMetadata = void> = {
+  metadata: VMetadata
+  edges: Array<Edge<EMetadata, VMetadata>>
+}
+ 
+export type Edge<EMetadata = void, VMetadata = void> = {
+  metadata: EMetadata
+  from: Vertex<VMetadata, EMetadata>
+  to: Vertex<VMetadata, EMetadata>
+}
+ 
+export class Graph<VMetadata = void, EMetadata = void> {
+  private readonly vertices: Array<Vertex<VMetadata, EMetadata>> = []
+  constructor() {}
+  addVertex(
+    metadata: VMetadata,
+    fromEdges: Array<Omit<Edge<EMetadata, VMetadata>, "to">>,
+    toEdges: Array<Omit<Edge<EMetadata, VMetadata>, "from">>,
+  ): Vertex<VMetadata, EMetadata> {
+    const vertex: Vertex<VMetadata, EMetadata> = {
+      metadata,
+      edges: [],
+    }
+    for (let edge of fromEdges) {
+      const vEdge = {
+        metadata: edge.metadata,
+        from: edge.from,
+        to: vertex,
+      }
+      edge.from.edges.push(vEdge)
+      vertex.edges.push(vEdge)
+    }
+    for (let edge of toEdges) {
+      const vEdge = {
+        metadata: edge.metadata,
+        from: vertex,
+        to: edge.to,
+      }
+      edge.to.edges.push(vEdge)
+      vertex.edges.push(vEdge)
+    }
+    this.vertices.push(vertex)
+    return vertex
+  }
+  findVertex(
+    predicate: (vertex: Vertex<VMetadata, EMetadata>) => boolean,
+  ): Generator<Vertex<VMetadata, EMetadata>, void> {
+    const veritces = this.vertices
+    function* gen() {
+      for (let vertex of veritces) {
+        if (predicate(vertex)) {
+          yield vertex
+        }
+      }
+    }
+    return gen()
+  }
+  addEdge(
+    metadata: EMetadata,
+    from: Vertex<VMetadata, EMetadata>,
+    to: Vertex<VMetadata, EMetadata>,
+  ): Edge<EMetadata, VMetadata> {
+    const edge = {
+      metadata,
+      from,
+      to,
+    }
+    edge.from.edges.push(edge)
+    edge.to.edges.push(edge)
+    return edge
+  }
+  breadthFirstSearch(
+    from:
+      | Vertex<VMetadata, EMetadata>
+      | ((vertex: Vertex<VMetadata, EMetadata>) => boolean),
+  ): Generator<Vertex<VMetadata, EMetadata>, void> {
+    const visited: Array<Vertex<VMetadata, EMetadata>> = []
+    function* rec(
+      vertex: Vertex<VMetadata, EMetadata>,
+    ): Generator<Vertex<VMetadata, EMetadata>, void> {
+      if (visited.includes(vertex)) {
+        return
+      }
+      visited.push(vertex)
+      yield vertex
+      let generators = vertex.edges
+        .filter((e) => e.from === vertex)
+        .map((e) => rec(e.to))
+      while (generators.length) {
+        let prev = generators
+        generators = []
+        for (let gen of prev) {
+          const next = gen.next()
+          if (!next.done) {
+            generators.push(gen)
+            yield next.value
+          }
+        }
+      }
+    }
+ 
+    if (from instanceof Function) {
+      let generators = this.vertices.filter(from).map(rec)
+      return (function* () {
+        while (generators.length) {
+          let prev = generators
+          generators = []
+          for (let gen of prev) {
+            const next = gen.next()
+            if (!next.done) {
+              generators.push(gen)
+              yield next.value
+            }
+          }
+        }
+      })()
+    } else {
+      return rec(from)
+    }
+  }
+  reverseBreadthFirstSearch(
+    to:
+      | Vertex<VMetadata, EMetadata>
+      | ((vertex: Vertex<VMetadata, EMetadata>) => boolean),
+  ): Generator<Vertex<VMetadata, EMetadata>, void> {
+    const visited: Array<Vertex<VMetadata, EMetadata>> = []
+    function* rec(
+      vertex: Vertex<VMetadata, EMetadata>,
+    ): Generator<Vertex<VMetadata, EMetadata>, void> {
+      if (visited.includes(vertex)) {
+        return
+      }
+      visited.push(vertex)
+      yield vertex
+      let generators = vertex.edges
+        .filter((e) => e.to === vertex)
+        .map((e) => rec(e.from))
+      while (generators.length) {
+        let prev = generators
+        generators = []
+        for (let gen of prev) {
+          const next = gen.next()
+          if (!next.done) {
+            generators.push(gen)
+            yield next.value
+          }
+        }
+      }
+    }
+ 
+    if (to instanceof Function) {
+      let generators = this.vertices.filter(to).map(rec)
+      return (function* () {
+        while (generators.length) {
+          let prev = generators
+          generators = []
+          for (let gen of prev) {
+            const next = gen.next()
+            if (!next.done) {
+              generators.push(gen)
+              yield next.value
+            }
+          }
+        }
+      })()
+    } else {
+      return rec(to)
+    }
+  }
+  shortestPath(
+    from:
+      | Vertex<VMetadata, EMetadata>
+      | ((vertex: Vertex<VMetadata, EMetadata>) => boolean),
+    to:
+      | Vertex<VMetadata, EMetadata>
+      | ((vertex: Vertex<VMetadata, EMetadata>) => boolean),
+  ): Array<Edge<EMetadata, VMetadata>> | void {
+    const isDone =
+      to instanceof Function
+        ? to
+        : (v: Vertex<VMetadata, EMetadata>) => v === to
+    const path: Array<Edge<EMetadata, VMetadata>> = []
+    const visited: Array<Vertex<VMetadata, EMetadata>> = []
+    function* check(
+      vertex: Vertex<VMetadata, EMetadata>,
+      path: Array<Edge<EMetadata, VMetadata>>,
+    ): Generator<undefined, Array<Edge<EMetadata, VMetadata>> | undefined> {
+      if (isDone(vertex)) {
+        return path
+      }
+      Iif (visited.includes(vertex)) {
+        return
+      }
+      visited.push(vertex)
+      yield
+      let generators = vertex.edges
+        .filter((e) => e.from === vertex)
+        .map((e) => check(e.to, [...path, e]))
+      while (generators.length) {
+        let prev = generators
+        generators = []
+        for (let gen of prev) {
+          const next = gen.next()
+          if (next.done === true) {
+            if (next.value) {
+              return next.value
+            }
+          } else {
+            generators.push(gen)
+            yield
+          }
+        }
+      }
+    }
+ 
+    Iif (from instanceof Function) {
+      let generators = this.vertices.filter(from).map((v) => check(v, []))
+      while (generators.length) {
+        let prev = generators
+        generators = []
+        for (let gen of prev) {
+          const next = gen.next()
+          if (next.done === true) {
+            Iif (next.value) {
+              return next.value
+            }
+          } else {
+            generators.push(gen)
+          }
+        }
+      }
+    } else {
+      const gen = check(from, [])
+      while (true) {
+        const next = gen.next()
+        if (next.done) {
+          return next.value
+        }
+      }
+    }
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/util/inMs.ts.html b/sdk/lib/coverage/lcov-report/lib/util/inMs.ts.html new file mode 100644 index 000000000..2ae621271 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/util/inMs.ts.html @@ -0,0 +1,178 @@ + + + + + + Code coverage report for lib/util/inMs.ts + + + + + + + + + +
+
+

All files / lib/util inMs.ts

+
+ +
+ 22.85% + Statements + 8/35 +
+ + +
+ 8.33% + Branches + 1/12 +
+ + +
+ 33.33% + Functions + 1/3 +
+ + +
+ 25% + Lines + 6/24 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32  +  +6x +  +6x +  +  +  +  +  +  +  +  +6x +  +  +  +  +  +6x +1x +1x +  +  +  +  +  +  +  +  +  + 
import { DEFAULT_SIGTERM_TIMEOUT } from "../mainFn"
+ 
+const matchTimeRegex = /^\s*(\d+)?(\.\d+)?\s*(ms|s|m|h|d)/
+ 
+const unitMultiplier = (unit?: string) => {
+  Iif (!unit) return 1
+  Iif (unit === "ms") return 1
+  Iif (unit === "s") return 1000
+  Iif (unit === "m") return 1000 * 60
+  Iif (unit === "h") return 1000 * 60 * 60
+  Iif (unit === "d") return 1000 * 60 * 60 * 24
+  throw new Error(`Invalid unit: ${unit}`)
+}
+const digitsMs = (digits: string | null, multiplier: number) => {
+  Iif (!digits) return 0
+  const value = parseInt(digits.slice(1))
+  const divideBy = multiplier / Math.pow(10, digits.length - 1)
+  return Math.round(value * divideBy)
+}
+export const inMs = (time?: string | number) => {
+  Iif (typeof time === "number") return time
+  if (!time) return undefined
+  const matches = time.match(matchTimeRegex)
+  Iif (!matches) throw new Error(`Invalid time format: ${time}`)
+  const [_, leftHandSide, digits, unit] = matches
+  const multiplier = unitMultiplier(unit)
+  const firstValue = parseInt(leftHandSide || "0") * multiplier
+  const secondValue = digitsMs(digits, multiplier)
+ 
+  return firstValue + secondValue
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/util/index.html b/sdk/lib/coverage/lcov-report/lib/util/index.html new file mode 100644 index 000000000..cb7194015 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/util/index.html @@ -0,0 +1,446 @@ + + + + + + Code coverage report for lib/util + + + + + + + + + +
+
+

All files lib/util

+
+ +
+ 36.83% + Statements + 256/695 +
+ + +
+ 12.2% + Branches + 26/213 +
+ + +
+ 17.96% + Functions + 30/167 +
+ + +
+ 36.29% + Lines + 233/642 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
GetSslCertificate.ts +
+
8.33%1/12100%0/00%0/68.33%1/12
GetSystemSmtp.ts +
+
10%1/10100%0/00%0/610%1/10
Hostname.ts +
+
6.66%1/150%0/130%0/16.66%1/15
SubContainer.ts +
+
6.79%11/1620%0/550%0/367%11/157
asError.ts +
+
40%2/50%0/10%0/125%1/4
deepEqual.ts +
+
66.66%14/2116.66%1/6100%2/285.71%12/14
deepMerge.ts +
+
100%18/18100%5/5100%4/4100%13/13
fileHelper.ts +
+
20.58%7/340%0/40%0/1821.21%7/33
getDefaultString.ts +
+
40%2/50%0/20%0/140%2/5
getRandomCharInSet.ts +
+
1.78%1/560%0/420%0/21.78%1/56
getRandomString.ts +
+
28.57%2/7100%0/00%0/133.33%2/6
getServiceInterface.ts +
+
20.43%19/930%0/372.63%1/3818.82%16/85
getServiceInterfaces.ts +
+
11.76%4/340%0/20%0/1112.12%4/33
graph.ts +
+
89.83%106/11875%18/2495.23%20/2190.59%106/117
inMs.ts +
+
22.85%8/358.33%1/1233.33%1/325%6/24
index.ts +
+
100%23/23100%0/00%0/8100%15/15
nullIfEmpty.ts +
+
25%1/40%0/30%0/133.33%1/3
once.ts +
+
100%6/6100%1/1100%2/2100%6/6
patterns.ts +
+
100%12/12100%0/0100%0/0100%12/12
regexes.ts +
+
100%11/11100%0/0100%0/0100%11/11
splitCommand.ts +
+
50%3/60%0/10%0/150%2/4
stringFromStdErrOut.ts +
+
50%1/20%0/20%0/150%1/2
typeHelpers.ts +
+
33.33%2/60%0/30%0/320%1/5
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/util/index.ts.html b/sdk/lib/coverage/lcov-report/lib/util/index.ts.html new file mode 100644 index 000000000..df7e72aaf --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/util/index.ts.html @@ -0,0 +1,133 @@ + + + + + + Code coverage report for lib/util/index.ts + + + + + + + + + +
+
+

All files / lib/util index.ts

+
+ +
+ 100% + Statements + 23/23 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 0% + Functions + 0/8 +
+ + +
+ 100% + Lines + 15/15 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +175x +5x +5x +5x +5x +5x +5x +  +5x +5x +5x +5x +5x +5x +5x +5x + 
import "./nullIfEmpty"
+import "./fileHelper"
+import "../store/getStore"
+import "./deepEqual"
+import "./deepMerge"
+import "./SubContainer"
+import "./once"
+ 
+export { GetServiceInterface, getServiceInterface } from "./getServiceInterface"
+export { asError } from "./asError"
+export { getServiceInterfaces } from "./getServiceInterfaces"
+export { addressHostToUrl } from "./getServiceInterface"
+export { hostnameInfoToAddress } from "./Hostname"
+export * from "./typeHelpers"
+export { getDefaultString } from "./getDefaultString"
+export { inMs } from "./inMs"
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/util/nullIfEmpty.ts.html b/sdk/lib/coverage/lcov-report/lib/util/nullIfEmpty.ts.html new file mode 100644 index 000000000..e2a633c89 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/util/nullIfEmpty.ts.html @@ -0,0 +1,121 @@ + + + + + + Code coverage report for lib/util/nullIfEmpty.ts + + + + + + + + + +
+
+

All files / lib/util nullIfEmpty.ts

+
+ +
+ 25% + Statements + 1/4 +
+ + +
+ 0% + Branches + 0/3 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 33.33% + Lines + 1/3 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13  +  +  +  +  +  +5x +  +  +  +  +  + 
/**
+ * A useful tool when doing a getConfig.
+ * Look into the config {@link FileHelper} for an example of the use.
+ * @param s
+ * @returns
+ */
+export default function nullIfEmpty<A extends Record<string, any>>(
+  s: null | A,
+) {
+  Iif (s === null) return null
+  return Object.keys(s).length === 0 ? null : s
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/util/once.ts.html b/sdk/lib/coverage/lcov-report/lib/util/once.ts.html new file mode 100644 index 000000000..f831ce135 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/util/once.ts.html @@ -0,0 +1,112 @@ + + + + + + Code coverage report for lib/util/once.ts + + + + + + + + + +
+
+

All files / lib/util once.ts

+
+ +
+ 100% + Statements + 6/6 +
+ + +
+ 100% + Branches + 1/1 +
+ + +
+ 100% + Functions + 2/2 +
+ + +
+ 100% + Lines + 6/6 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +106x +26x +26x +139x +25x +  +139x +  +  + 
export function once<B>(fn: () => B): () => B {
+  let result: [B] | [] = []
+  return () => {
+    if (!result.length) {
+      result = [fn()]
+    }
+    return result[0]
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/util/patterns.ts.html b/sdk/lib/coverage/lcov-report/lib/util/patterns.ts.html new file mode 100644 index 000000000..fb1cd6618 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/util/patterns.ts.html @@ -0,0 +1,262 @@ + + + + + + Code coverage report for lib/util/patterns.ts + + + + + + + + + +
+
+

All files / lib/util patterns.ts

+
+ +
+ 100% + Statements + 12/12 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 100% + Functions + 0/0 +
+ + +
+ 100% + Lines + 12/12 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60  +5x +  +5x +  +  +  +  +5x +  +  +  +  +5x +  +  +  +  +5x +  +  +  +  +5x +  +  +  +  +5x +  +  +  +  +5x +  +  +  +  +5x +  +  +  +  +5x +  +  +  +  +  +5x +  +  +  +  +5x +  +  +  +  + 
import { Pattern } from "../config/configTypes"
+import * as regexes from "./regexes"
+ 
+export const ipv6: Pattern = {
+  regex: regexes.ipv6.toString(),
+  description: "Must be a valid IPv6 address",
+}
+ 
+export const ipv4: Pattern = {
+  regex: regexes.ipv4.toString(),
+  description: "Must be a valid IPv4 address",
+}
+ 
+export const hostname: Pattern = {
+  regex: regexes.hostname.toString(),
+  description: "Must be a valid hostname",
+}
+ 
+export const localHostname: Pattern = {
+  regex: regexes.localHostname.toString(),
+  description: 'Must be a valid ".local" hostname',
+}
+ 
+export const torHostname: Pattern = {
+  regex: regexes.torHostname.toString(),
+  description: 'Must be a valid Tor (".onion") hostname',
+}
+ 
+export const url: Pattern = {
+  regex: regexes.url.toString(),
+  description: "Must be a valid URL",
+}
+ 
+export const localUrl: Pattern = {
+  regex: regexes.localUrl.toString(),
+  description: 'Must be a valid ".local" URL',
+}
+ 
+export const torUrl: Pattern = {
+  regex: regexes.torUrl.toString(),
+  description: 'Must be a valid Tor (".onion") URL',
+}
+ 
+export const ascii: Pattern = {
+  regex: regexes.ascii.toString(),
+  description:
+    "May only contain ASCII characters. See https://www.w3schools.com/charsets/ref_html_ascii.asp",
+}
+ 
+export const email: Pattern = {
+  regex: regexes.email.toString(),
+  description: "Must be a valid email address",
+}
+ 
+export const base64: Pattern = {
+  regex: regexes.base64.toString(),
+  description:
+    "May only contain base64 characters. See https://base64.guru/learn/base64-characters",
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/util/regexes.ts.html b/sdk/lib/coverage/lcov-report/lib/util/regexes.ts.html new file mode 100644 index 000000000..1c6298f23 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/util/regexes.ts.html @@ -0,0 +1,187 @@ + + + + + + Code coverage report for lib/util/regexes.ts + + + + + + + + + +
+
+

All files / lib/util regexes.ts

+
+ +
+ 100% + Statements + 11/11 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 100% + Functions + 0/0 +
+ + +
+ 100% + Lines + 11/11 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35  +5x +  +  +  +5x +  +  +5x +  +  +5x +  +5x +  +  +5x +  +  +5x +  +  +5x +  +  +  +5x +  +  +5x +  +  +5x +  + 
// https://ihateregex.io/expr/ipv6/
+export const ipv6 =
+  /(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))/
+ 
+// https://ihateregex.io/expr/ipv4/
+export const ipv4 =
+  /(\b25[0-5]|\b2[0-4][0-9]|\b[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}/
+ 
+export const hostname =
+  /^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$/
+ 
+export const localHostname = /[-a-zA-Z0-9@:%._\+~#=]{1,256}\.local/
+ 
+export const torHostname = /[-a-zA-Z0-9@:%._\+~#=]{1,256}\.onion/
+ 
+// https://ihateregex.io/expr/url/
+export const url =
+  /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()!@:%_\+.~#?&\/\/=]*)/
+ 
+export const localUrl =
+  /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.local\b([-a-zA-Z0-9()!@:%_\+.~#?&\/\/=]*)/
+ 
+export const torUrl =
+  /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.onion\b([-a-zA-Z0-9()!@:%_\+.~#?&\/\/=]*)/
+ 
+// https://ihateregex.io/expr/ascii/
+export const ascii = /^[ -~]*$/
+ 
+//https://ihateregex.io/expr/email/
+export const email = /[^@ \t\r\n]+@[^@ \t\r\n]+\.[^@ \t\r\n]+/
+ 
+//https://rgxdb.com/r/1NUN74O6
+export const base64 =
+  /^(?:[a-zA-Z0-9+\/]{4})*(?:|(?:[a-zA-Z0-9+\/]{3}=)|(?:[a-zA-Z0-9+\/]{2}==)|(?:[a-zA-Z0-9+\/]{1}===))$/
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/util/splitCommand.ts.html b/sdk/lib/coverage/lcov-report/lib/util/splitCommand.ts.html new file mode 100644 index 000000000..5614227a2 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/util/splitCommand.ts.html @@ -0,0 +1,109 @@ + + + + + + Code coverage report for lib/util/splitCommand.ts + + + + + + + + + +
+
+

All files / lib/util splitCommand.ts

+
+ +
+ 50% + Statements + 3/6 +
+ + +
+ 0% + Branches + 0/1 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 50% + Lines + 2/4 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +95x +  +5x +  +  +  +  +  + 
import { arrayOf, string } from "ts-matches"
+ 
+export const splitCommand = (
+  command: string | [string, ...string[]],
+): string[] => {
+  Iif (arrayOf(string).test(command)) return command
+  return ["sh", "-c", command]
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/util/stringFromStdErrOut.ts.html b/sdk/lib/coverage/lcov-report/lib/util/stringFromStdErrOut.ts.html new file mode 100644 index 000000000..e0c017b47 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/util/stringFromStdErrOut.ts.html @@ -0,0 +1,103 @@ + + + + + + Code coverage report for lib/util/stringFromStdErrOut.ts + + + + + + + + + +
+
+

All files / lib/util stringFromStdErrOut.ts

+
+ +
+ 50% + Statements + 1/2 +
+ + +
+ 0% + Branches + 0/2 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 50% + Lines + 1/2 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +76x +  +  +  +  +  + 
export async function stringFromStdErrOut(x: {
+  stdout: string
+  stderr: string
+}) {
+  return x?.stderr ? Promise.reject(x.stderr) : x.stdout
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/util/typeHelpers.ts.html b/sdk/lib/coverage/lcov-report/lib/util/typeHelpers.ts.html new file mode 100644 index 000000000..4c100e991 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/util/typeHelpers.ts.html @@ -0,0 +1,433 @@ + + + + + + Code coverage report for lib/util/typeHelpers.ts + + + + + + + + + +
+
+

All files / lib/util typeHelpers.ts

+
+ +
+ 33.33% + Statements + 2/6 +
+ + +
+ 0% + Branches + 0/3 +
+ + +
+ 0% + Functions + 0/3 +
+ + +
+ 20% + Lines + 1/5 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117  +  +  +  +  +  +  +  +  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import * as T from "../types"
+ 
+// prettier-ignore
+export type FlattenIntersection<T> = 
+T extends ArrayLike<any> ? T :
+T extends object ? {} & {[P in keyof T]: T[P]} :
+ T;
+ 
+export type _<T> = FlattenIntersection<T>
+ 
+export const isKnownError = (e: unknown): e is T.KnownError =>
+  e instanceof Object && ("error" in e || "error-code" in e)
+ 
+declare const affine: unique symbol
+ 
+export type Affine<A> = { [affine]: A }
+ 
+type NeverPossible = { [affine]: string }
+export type NoAny<A> = NeverPossible extends A
+  ? keyof NeverPossible extends keyof A
+    ? never
+    : A
+  : A
+ 
+type CapitalLetters =
+  | "A"
+  | "B"
+  | "C"
+  | "D"
+  | "E"
+  | "F"
+  | "G"
+  | "H"
+  | "I"
+  | "J"
+  | "K"
+  | "L"
+  | "M"
+  | "N"
+  | "O"
+  | "P"
+  | "Q"
+  | "R"
+  | "S"
+  | "T"
+  | "U"
+  | "V"
+  | "W"
+  | "X"
+  | "Y"
+  | "Z"
+ 
+type Numbers = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
+ 
+type CapitalChars = CapitalLetters | Numbers
+ 
+export type ToKebab<S extends string> = S extends string
+  ? S extends `${infer Head}${CapitalChars}${infer Tail}` // string has a capital char somewhere
+    ? Head extends "" // there is a capital char in the first position
+      ? Tail extends ""
+        ? Lowercase<S> /*  'A' */
+        : S extends `${infer Caps}${Tail}` // tail exists, has capital characters
+          ? Caps extends CapitalChars
+            ? Tail extends CapitalLetters
+              ? `${Lowercase<Caps>}-${Lowercase<Tail>}` /* 'AB' */
+              : Tail extends `${CapitalLetters}${string}`
+                ? `${ToKebab<Caps>}-${ToKebab<Tail>}` /* first tail char is upper? 'ABcd' */
+                : `${ToKebab<Caps>}${ToKebab<Tail>}` /* 'AbCD','AbcD',  */ /* TODO: if tail is only numbers, append without underscore */
+            : never /* never reached, used for inference of caps */
+          : never
+      : Tail extends "" /* 'aB' 'abCD' 'ABCD' 'AB' */
+        ? S extends `${Head}${infer Caps}`
+          ? Caps extends CapitalChars
+            ? Head extends Lowercase<Head> /* 'abcD' */
+              ? Caps extends Numbers
+                ? // Head exists and is lowercase, tail does not, Caps is a number, we may be in a sub-select
+                  // if head ends with number, don't split head an Caps, keep contiguous numbers together
+                  Head extends `${string}${Numbers}`
+                  ? never
+                  : // head does not end in number, safe to split. 'abc2' -> 'abc-2'
+                    `${ToKebab<Head>}-${Caps}`
+                : `${ToKebab<Head>}-${ToKebab<Caps>}` /* 'abcD' 'abc25' */
+              : never /* stop union type forming */
+            : never
+          : never /* never reached, used for inference of caps */
+        : S extends `${Head}${infer Caps}${Tail}` /* 'abCd' 'ABCD' 'AbCd' 'ABcD' */
+          ? Caps extends CapitalChars
+            ? Head extends Lowercase<Head> /* is 'abCd' 'abCD' ? */
+              ? Tail extends CapitalLetters /* is 'abCD' where Caps = 'C' */
+                ? `${ToKebab<Head>}-${ToKebab<Caps>}-${Lowercase<Tail>}` /* aBCD Tail = 'D', Head = 'aB' */
+                : Tail extends `${CapitalLetters}${string}` /* is 'aBCd' where Caps = 'B' */
+                  ? Head extends Numbers
+                    ? never /* stop union type forming */
+                    : Head extends `${string}${Numbers}`
+                      ? never /* stop union type forming */
+                      : `${Head}-${ToKebab<Caps>}-${ToKebab<Tail>}` /* 'aBCd' => `${'a'}-${Lowercase<'B'>}-${ToSnake<'Cd'>}` */
+                  : `${ToKebab<Head>}-${Lowercase<Caps>}${ToKebab<Tail>}` /* 'aBcD' where Caps = 'B' tail starts as lowercase */
+              : never
+            : never
+          : never
+    : S /* 'abc'  */
+  : never
+ 
+export type StringObject = Record<string, unknown>
+ 
+function test() {
+  // prettier-ignore
+  const t = <A, B>(a: (
+    A extends B ? (
+      B extends A ? null : never
+    ) : never
+  )) =>{ }
+  t<"foo-bar", ToKebab<"FooBar">>(null)
+  // @ts-expect-error
+  t<"foo-3ar", ToKebab<"FooBar">>(null)
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/version/VersionGraph.ts.html b/sdk/lib/coverage/lcov-report/lib/version/VersionGraph.ts.html new file mode 100644 index 000000000..9e6463a4b --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/version/VersionGraph.ts.html @@ -0,0 +1,685 @@ + + + + + + Code coverage report for lib/version/VersionGraph.ts + + + + + + + + + +
+
+

All files / lib/version VersionGraph.ts

+
+ +
+ 64.17% + Statements + 43/67 +
+ + +
+ 51.35% + Branches + 19/37 +
+ + +
+ 66.66% + Functions + 10/15 +
+ + +
+ 65.15% + Lines + 43/66 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +2014x +  +  +4x +4x +4x +  +4x +  +  +  +  +  +5x +  +  +5x +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +5x +5x +5x +5x +5x +5x +5x +  +5x +  +5x +5x +  +  +  +  +  +  +  +  +  +5x +5x +5x +  +5x +  +  +  +  +  +5x +  +5x +5x +  +  +5x +  +5x +  +  +  +  +  +5x +  +5x +5x +  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +5x +  +  +5x +5x +  +  +  +  +  +  +  +  +5x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +5x +5x +  +  +15x +  +  +  +  +  +  +10x +  +  +  +  +  +  +  +5x +5x +  +  +15x +  +  +  +  +  +  +10x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { ExtendedVersion, VersionRange } from "../exver"
+ 
+import * as T from "../types"
+import { Graph, Vertex } from "../util/graph"
+import { once } from "../util/once"
+import { IMPOSSIBLE, VersionInfo } from "./VersionInfo"
+ 
+export class VersionGraph<CurrentVersion extends string> {
+  private readonly graph: () => Graph<
+    ExtendedVersion | VersionRange,
+    ((opts: { effects: T.Effects }) => Promise<void>) | undefined
+  >
+  private constructor(
+    readonly current: VersionInfo<CurrentVersion>,
+    versions: Array<VersionInfo<any>>,
+  ) {
+    this.graph = once(() => {
+      const graph = new Graph<
+        ExtendedVersion | VersionRange,
+        ((opts: { effects: T.Effects }) => Promise<void>) | undefined
+      >()
+      const flavorMap: Record<
+        string,
+        [
+          ExtendedVersion,
+          VersionInfo<any>,
+          Vertex<
+            ExtendedVersion | VersionRange,
+            ((opts: { effects: T.Effects }) => Promise<void>) | undefined
+          >,
+        ][]
+      > = {}
+      for (let version of [current, ...versions]) {
+        const v = ExtendedVersion.parse(version.options.version)
+        const vertex = graph.addVertex(v, [], [])
+        const flavor = v.flavor || ""
+        if (!flavorMap[flavor]) {
+          flavorMap[flavor] = []
+        }
+        flavorMap[flavor].push([v, version, vertex])
+      }
+      for (let flavor in flavorMap) {
+        flavorMap[flavor].sort((a, b) => a[0].compareForSort(b[0]))
+        let prev:
+          | [
+              ExtendedVersion,
+              VersionInfo<any>,
+              Vertex<
+                ExtendedVersion | VersionRange,
+                (opts: { effects: T.Effects }) => Promise<void>
+              >,
+            ]
+          | undefined = undefined
+        for (let [v, version, vertex] of flavorMap[flavor]) {
+          if (version.options.migrations.up !== IMPOSSIBLE) {
+            let range
+            Iif (prev) {
+              graph.addEdge(version.options.migrations.up, prev[2], vertex)
+              range = VersionRange.anchor(">=", prev[0]).and(
+                VersionRange.anchor("<", v),
+              )
+            } else {
+              range = VersionRange.anchor("<", v)
+            }
+            const vRange = graph.addVertex(range, [], [])
+            graph.addEdge(version.options.migrations.up, vRange, vertex)
+          }
+ 
+          if (version.options.migrations.down !== IMPOSSIBLE) {
+            let range
+            Iif (prev) {
+              graph.addEdge(version.options.migrations.down, vertex, prev[2])
+              range = VersionRange.anchor(">=", prev[0]).and(
+                VersionRange.anchor("<", v),
+              )
+            } else {
+              range = VersionRange.anchor("<", v)
+            }
+            const vRange = graph.addVertex(range, [], [])
+            graph.addEdge(version.options.migrations.down, vertex, vRange)
+          }
+ 
+          Iif (version.options.migrations.other) {
+            for (let rangeStr in version.options.migrations.other) {
+              const range = VersionRange.parse(rangeStr)
+              const vRange = graph.addVertex(range, [], [])
+              graph.addEdge(
+                version.options.migrations.other[rangeStr],
+                vRange,
+                vertex,
+              )
+              for (let matching of graph.findVertex(
+                (v) =>
+                  v.metadata instanceof ExtendedVersion &&
+                  v.metadata.satisfies(range),
+              )) {
+                graph.addEdge(
+                  version.options.migrations.other[rangeStr],
+                  matching,
+                  vertex,
+                )
+              }
+            }
+          }
+        }
+      }
+      return graph
+    })
+  }
+  currentVersion = once(() =>
+    ExtendedVersion.parse(this.current.options.version),
+  )
+  static of<
+    CurrentVersion extends string,
+    OtherVersions extends Array<VersionInfo<any>>,
+  >(
+    currentVersion: VersionInfo<CurrentVersion>,
+    ...other: EnsureUniqueId<OtherVersions, OtherVersions, CurrentVersion>
+  ) {
+    return new VersionGraph(currentVersion, other as Array<VersionInfo<any>>)
+  }
+  async migrate({
+    effects,
+    from,
+    to,
+  }: {
+    effects: T.Effects
+    from: ExtendedVersion
+    to: ExtendedVersion
+  }) {
+    const graph = this.graph()
+    Iif (from && to) {
+      const path = graph.shortestPath(
+        (v) =>
+          (v.metadata instanceof VersionRange &&
+            v.metadata.satisfiedBy(from)) ||
+          (v.metadata instanceof ExtendedVersion && v.metadata.equals(from)),
+        (v) =>
+          (v.metadata instanceof VersionRange && v.metadata.satisfiedBy(to)) ||
+          (v.metadata instanceof ExtendedVersion && v.metadata.equals(to)),
+      )
+      Iif (path) {
+        for (let edge of path) {
+          Iif (edge.metadata) {
+            await edge.metadata({ effects })
+          }
+          await effects.setDataVersion({ version: edge.to.metadata.toString() })
+        }
+        return
+      }
+    }
+    throw new Error()
+  }
+  canMigrateFrom = once(() =>
+    Array.from(
+      this.graph().reverseBreadthFirstSearch(
+        (v) =>
+          (v.metadata instanceof VersionRange &&
+            v.metadata.satisfiedBy(this.currentVersion())) ||
+          (v.metadata instanceof ExtendedVersion &&
+            v.metadata.equals(this.currentVersion())),
+      ),
+    ).reduce(
+      (acc, x) =>
+        acc.or(
+          x.metadata instanceof VersionRange
+            ? x.metadata
+            : VersionRange.anchor("=", x.metadata),
+        ),
+      VersionRange.none(),
+    ),
+  )
+  canMigrateTo = once(() =>
+    Array.from(
+      this.graph().breadthFirstSearch(
+        (v) =>
+          (v.metadata instanceof VersionRange &&
+            v.metadata.satisfiedBy(this.currentVersion())) ||
+          (v.metadata instanceof ExtendedVersion &&
+            v.metadata.equals(this.currentVersion())),
+      ),
+    ).reduce(
+      (acc, x) =>
+        acc.or(
+          x.metadata instanceof VersionRange
+            ? x.metadata
+            : VersionRange.anchor("=", x.metadata),
+        ),
+      VersionRange.none(),
+    ),
+  )
+}
+ 
+// prettier-ignore
+export type EnsureUniqueId<A, B = A, OtherVersions = never> =
+  B extends [] ? A : 
+  B extends [VersionInfo<infer Version>, ...infer Rest] ? (
+    Version extends OtherVersions ?  "One or more versions are not unique"[] :
+    EnsureUniqueId<A, Rest, Version | OtherVersions>
+  ) : "There exists a migration that is not a Migration"[]
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/version/VersionInfo.ts.html b/sdk/lib/coverage/lcov-report/lib/version/VersionInfo.ts.html new file mode 100644 index 000000000..5c9209195 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/version/VersionInfo.ts.html @@ -0,0 +1,319 @@ + + + + + + Code coverage report for lib/version/VersionInfo.ts + + + + + + + + + +
+
+

All files / lib/version VersionInfo.ts

+
+ +
+ 54.54% + Statements + 6/11 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 75% + Functions + 3/4 +
+ + +
+ 54.54% + Lines + 6/11 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79  +  +  +4x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +4x +13x +  +13x +  +  +5x +  +  +  +  +  +8x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { ValidateExVer } from "../exver"
+import * as T from "../types"
+ 
+export const IMPOSSIBLE = Symbol("IMPOSSIBLE")
+ 
+export type VersionOptions<Version extends string> = {
+  /** The version being described */
+  version: Version & ValidateExVer<Version>
+  /** The release notes for this version */
+  releaseNotes: string
+  /** Data migrations for this version */
+  migrations: {
+    /**
+     * A migration from the previous version
+     *    Leave blank to indicate no migration is necessary
+     *    Set to `IMPOSSIBLE` to indicate migrating from the previous version is not possible
+     */
+    up?: ((opts: { effects: T.Effects }) => Promise<void>) | typeof IMPOSSIBLE
+    /**
+     * A migration to the previous version
+     *    Leave blank to indicate no migration is necessary
+     *    Set to `IMPOSSIBLE` to indicate downgrades are prohibited
+     */
+    down?: ((opts: { effects: T.Effects }) => Promise<void>) | typeof IMPOSSIBLE
+    /**
+     * Additional migrations, such as fast-forward migrations, or migrations from other flavors
+     */
+    other?: Record<string, (opts: { effects: T.Effects }) => Promise<void>>
+  }
+}
+ 
+export class VersionInfo<Version extends string> {
+  private _version: null | Version = null
+  private constructor(
+    readonly options: VersionOptions<Version> & { satisfies: string[] },
+  ) {}
+  static of<Version extends string>(options: VersionOptions<Version>) {
+    return new VersionInfo<Version>({ ...options, satisfies: [] })
+  }
+  /** Specify a version that this version is 100% backwards compatible to */
+  satisfies<V extends string>(
+    version: V & ValidateExVer<V>,
+  ): VersionInfo<Version> {
+    return new VersionInfo({
+      ...this.options,
+      satisfies: [...this.options.satisfies, version],
+    })
+  }
+}
+ 
+function __type_tests() {
+  const version: VersionInfo<"1.0.0:0"> = VersionInfo.of({
+    version: "1.0.0:0",
+    releaseNotes: "",
+    migrations: {},
+  })
+    .satisfies("#other:1.0.0:0")
+    .satisfies("#other:2.0.0:0")
+    // @ts-expect-error
+    .satisfies("#other:2.f.0:0")
+ 
+  let a: VersionInfo<"1.0.0:0"> = version
+  // @ts-expect-error
+  let b: VersionInfo<"1.0.0:3"> = version
+ 
+  VersionInfo.of({
+    // @ts-expect-error
+    version: "test",
+    releaseNotes: "",
+    migrations: {},
+  })
+  VersionInfo.of({
+    // @ts-expect-error
+    version: "test" as string,
+    releaseNotes: "",
+    migrations: {},
+  })
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/lib/version/index.html b/sdk/lib/coverage/lcov-report/lib/version/index.html new file mode 100644 index 000000000..8373ca0af --- /dev/null +++ b/sdk/lib/coverage/lcov-report/lib/version/index.html @@ -0,0 +1,131 @@ + + + + + + Code coverage report for lib/version + + + + + + + + + +
+
+

All files lib/version

+
+ +
+ 62.82% + Statements + 49/78 +
+ + +
+ 51.35% + Branches + 19/37 +
+ + +
+ 68.42% + Functions + 13/19 +
+ + +
+ 63.63% + Lines + 49/77 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
VersionGraph.ts +
+
64.17%43/6751.35%19/3766.66%10/1565.15%43/66
VersionInfo.ts +
+
54.54%6/11100%0/075%3/454.54%6/11
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/prettify.css b/sdk/lib/coverage/lcov-report/prettify.css new file mode 100644 index 000000000..b317a7cda --- /dev/null +++ b/sdk/lib/coverage/lcov-report/prettify.css @@ -0,0 +1 @@ +.pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} diff --git a/sdk/lib/coverage/lcov-report/prettify.js b/sdk/lib/coverage/lcov-report/prettify.js new file mode 100644 index 000000000..b3225238f --- /dev/null +++ b/sdk/lib/coverage/lcov-report/prettify.js @@ -0,0 +1,2 @@ +/* eslint-disable */ +window.PR_SHOULD_USE_CONTINUATION=true;(function(){var h=["break,continue,do,else,for,if,return,while"];var u=[h,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"];var p=[u,"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"];var l=[p,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"];var x=[p,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"];var R=[x,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"];var r="all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes";var w=[p,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"];var s="caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END";var I=[h,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"];var f=[h,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"];var H=[h,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"];var A=[l,R,w,s+I,f,H];var e=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/;var C="str";var z="kwd";var j="com";var O="typ";var G="lit";var L="pun";var F="pln";var m="tag";var E="dec";var J="src";var P="atn";var n="atv";var N="nocode";var M="(?:^^\\.?|[+-]|\\!|\\!=|\\!==|\\#|\\%|\\%=|&|&&|&&=|&=|\\(|\\*|\\*=|\\+=|\\,|\\-=|\\->|\\/|\\/=|:|::|\\;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\@|\\[|\\^|\\^=|\\^\\^|\\^\\^=|\\{|\\||\\|=|\\|\\||\\|\\|=|\\~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*";function k(Z){var ad=0;var S=false;var ac=false;for(var V=0,U=Z.length;V122)){if(!(al<65||ag>90)){af.push([Math.max(65,ag)|32,Math.min(al,90)|32])}if(!(al<97||ag>122)){af.push([Math.max(97,ag)&~32,Math.min(al,122)&~32])}}}}af.sort(function(av,au){return(av[0]-au[0])||(au[1]-av[1])});var ai=[];var ap=[NaN,NaN];for(var ar=0;arat[0]){if(at[1]+1>at[0]){an.push("-")}an.push(T(at[1]))}}an.push("]");return an.join("")}function W(al){var aj=al.source.match(new RegExp("(?:\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]|\\\\u[A-Fa-f0-9]{4}|\\\\x[A-Fa-f0-9]{2}|\\\\[0-9]+|\\\\[^ux0-9]|\\(\\?[:!=]|[\\(\\)\\^]|[^\\x5B\\x5C\\(\\)\\^]+)","g"));var ah=aj.length;var an=[];for(var ak=0,am=0;ak=2&&ai==="["){aj[ak]=X(ag)}else{if(ai!=="\\"){aj[ak]=ag.replace(/[a-zA-Z]/g,function(ao){var ap=ao.charCodeAt(0);return"["+String.fromCharCode(ap&~32,ap|32)+"]"})}}}}return aj.join("")}var aa=[];for(var V=0,U=Z.length;V=0;){S[ac.charAt(ae)]=Y}}var af=Y[1];var aa=""+af;if(!ag.hasOwnProperty(aa)){ah.push(af);ag[aa]=null}}ah.push(/[\0-\uffff]/);V=k(ah)})();var X=T.length;var W=function(ah){var Z=ah.sourceCode,Y=ah.basePos;var ad=[Y,F];var af=0;var an=Z.match(V)||[];var aj={};for(var ae=0,aq=an.length;ae=5&&"lang-"===ap.substring(0,5);if(am&&!(ai&&typeof ai[1]==="string")){am=false;ap=J}if(!am){aj[ag]=ap}}var ab=af;af+=ag.length;if(!am){ad.push(Y+ab,ap)}else{var al=ai[1];var ak=ag.indexOf(al);var ac=ak+al.length;if(ai[2]){ac=ag.length-ai[2].length;ak=ac-al.length}var ar=ap.substring(5);B(Y+ab,ag.substring(0,ak),W,ad);B(Y+ab+ak,al,q(ar,al),ad);B(Y+ab+ac,ag.substring(ac),W,ad)}}ah.decorations=ad};return W}function i(T){var W=[],S=[];if(T.tripleQuotedStrings){W.push([C,/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,null,"'\""])}else{if(T.multiLineStrings){W.push([C,/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,"'\"`"])}else{W.push([C,/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,"\"'"])}}if(T.verbatimStrings){S.push([C,/^@\"(?:[^\"]|\"\")*(?:\"|$)/,null])}var Y=T.hashComments;if(Y){if(T.cStyleComments){if(Y>1){W.push([j,/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,null,"#"])}else{W.push([j,/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\r\n]*)/,null,"#"])}S.push([C,/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,null])}else{W.push([j,/^#[^\r\n]*/,null,"#"])}}if(T.cStyleComments){S.push([j,/^\/\/[^\r\n]*/,null]);S.push([j,/^\/\*[\s\S]*?(?:\*\/|$)/,null])}if(T.regexLiterals){var X=("/(?=[^/*])(?:[^/\\x5B\\x5C]|\\x5C[\\s\\S]|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+/");S.push(["lang-regex",new RegExp("^"+M+"("+X+")")])}var V=T.types;if(V){S.push([O,V])}var U=(""+T.keywords).replace(/^ | $/g,"");if(U.length){S.push([z,new RegExp("^(?:"+U.replace(/[\s,]+/g,"|")+")\\b"),null])}W.push([F,/^\s+/,null," \r\n\t\xA0"]);S.push([G,/^@[a-z_$][a-z_$@0-9]*/i,null],[O,/^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/,null],[F,/^[a-z_$][a-z_$@0-9]*/i,null],[G,new RegExp("^(?:0x[a-f0-9]+|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)(?:e[+\\-]?\\d+)?)[a-z]*","i"),null,"0123456789"],[F,/^\\[\s\S]?/,null],[L,/^.[^\s\w\.$@\'\"\`\/\#\\]*/,null]);return g(W,S)}var K=i({keywords:A,hashComments:true,cStyleComments:true,multiLineStrings:true,regexLiterals:true});function Q(V,ag){var U=/(?:^|\s)nocode(?:\s|$)/;var ab=/\r\n?|\n/;var ac=V.ownerDocument;var S;if(V.currentStyle){S=V.currentStyle.whiteSpace}else{if(window.getComputedStyle){S=ac.defaultView.getComputedStyle(V,null).getPropertyValue("white-space")}}var Z=S&&"pre"===S.substring(0,3);var af=ac.createElement("LI");while(V.firstChild){af.appendChild(V.firstChild)}var W=[af];function ae(al){switch(al.nodeType){case 1:if(U.test(al.className)){break}if("BR"===al.nodeName){ad(al);if(al.parentNode){al.parentNode.removeChild(al)}}else{for(var an=al.firstChild;an;an=an.nextSibling){ae(an)}}break;case 3:case 4:if(Z){var am=al.nodeValue;var aj=am.match(ab);if(aj){var ai=am.substring(0,aj.index);al.nodeValue=ai;var ah=am.substring(aj.index+aj[0].length);if(ah){var ak=al.parentNode;ak.insertBefore(ac.createTextNode(ah),al.nextSibling)}ad(al);if(!ai){al.parentNode.removeChild(al)}}}break}}function ad(ak){while(!ak.nextSibling){ak=ak.parentNode;if(!ak){return}}function ai(al,ar){var aq=ar?al.cloneNode(false):al;var ao=al.parentNode;if(ao){var ap=ai(ao,1);var an=al.nextSibling;ap.appendChild(aq);for(var am=an;am;am=an){an=am.nextSibling;ap.appendChild(am)}}return aq}var ah=ai(ak.nextSibling,0);for(var aj;(aj=ah.parentNode)&&aj.nodeType===1;){ah=aj}W.push(ah)}for(var Y=0;Y=S){ah+=2}if(V>=ap){Z+=2}}}var t={};function c(U,V){for(var S=V.length;--S>=0;){var T=V[S];if(!t.hasOwnProperty(T)){t[T]=U}else{if(window.console){console.warn("cannot override language handler %s",T)}}}}function q(T,S){if(!(T&&t.hasOwnProperty(T))){T=/^\s*]*(?:>|$)/],[j,/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],[L,/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);c(g([[F,/^[\s]+/,null," \t\r\n"],[n,/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,null,"\"'"]],[[m,/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],[P,/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],[L,/^[=<>\/]+/],["lang-js",/^on\w+\s*=\s*\"([^\"]+)\"/i],["lang-js",/^on\w+\s*=\s*\'([^\']+)\'/i],["lang-js",/^on\w+\s*=\s*([^\"\'>\s]+)/i],["lang-css",/^style\s*=\s*\"([^\"]+)\"/i],["lang-css",/^style\s*=\s*\'([^\']+)\'/i],["lang-css",/^style\s*=\s*([^\"\'>\s]+)/i]]),["in.tag"]);c(g([],[[n,/^[\s\S]+/]]),["uq.val"]);c(i({keywords:l,hashComments:true,cStyleComments:true,types:e}),["c","cc","cpp","cxx","cyc","m"]);c(i({keywords:"null,true,false"}),["json"]);c(i({keywords:R,hashComments:true,cStyleComments:true,verbatimStrings:true,types:e}),["cs"]);c(i({keywords:x,cStyleComments:true}),["java"]);c(i({keywords:H,hashComments:true,multiLineStrings:true}),["bsh","csh","sh"]);c(i({keywords:I,hashComments:true,multiLineStrings:true,tripleQuotedStrings:true}),["cv","py"]);c(i({keywords:s,hashComments:true,multiLineStrings:true,regexLiterals:true}),["perl","pl","pm"]);c(i({keywords:f,hashComments:true,multiLineStrings:true,regexLiterals:true}),["rb"]);c(i({keywords:w,cStyleComments:true,regexLiterals:true}),["js"]);c(i({keywords:r,hashComments:3,cStyleComments:true,multilineStrings:true,tripleQuotedStrings:true,regexLiterals:true}),["coffee"]);c(g([],[[C,/^[\s\S]+/]]),["regex"]);function d(V){var U=V.langExtension;try{var S=a(V.sourceNode);var T=S.sourceCode;V.sourceCode=T;V.spans=S.spans;V.basePos=0;q(U,T)(V);D(V)}catch(W){if("console" in window){console.log(W&&W.stack?W.stack:W)}}}function y(W,V,U){var S=document.createElement("PRE");S.innerHTML=W;if(U){Q(S,U)}var T={langExtension:V,numberLines:U,sourceNode:S};d(T);return S.innerHTML}function b(ad){function Y(af){return document.getElementsByTagName(af)}var ac=[Y("pre"),Y("code"),Y("xmp")];var T=[];for(var aa=0;aa=0){var ah=ai.match(ab);var am;if(!ah&&(am=o(aj))&&"CODE"===am.tagName){ah=am.className.match(ab)}if(ah){ah=ah[1]}var al=false;for(var ak=aj.parentNode;ak;ak=ak.parentNode){if((ak.tagName==="pre"||ak.tagName==="code"||ak.tagName==="xmp")&&ak.className&&ak.className.indexOf("prettyprint")>=0){al=true;break}}if(!al){var af=aj.className.match(/\blinenums\b(?::(\d+))?/);af=af?af[1]&&af[1].length?+af[1]:true:false;if(af){Q(aj,af)}S={langExtension:ah,sourceNode:aj,numberLines:af};d(S)}}}if(X]*(?:>|$)/],[PR.PR_COMMENT,/^<\!--[\s\S]*?(?:-\->|$)/],[PR.PR_PUNCTUATION,/^(?:<[%?]|[%?]>)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-handlebars",/^]*type\s*=\s*['"]?text\/x-handlebars-template['"]?\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i],[PR.PR_DECLARATION,/^{{[#^>/]?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{&?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{{>?\s*[\w.][^}]*}}}/],[PR.PR_COMMENT,/^{{![^}]*}}/]]),["handlebars","hbs"]);PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[ \t\r\n\f]+/,null," \t\r\n\f"]],[[PR.PR_STRING,/^\"(?:[^\n\r\f\\\"]|\\(?:\r\n?|\n|\f)|\\[\s\S])*\"/,null],[PR.PR_STRING,/^\'(?:[^\n\r\f\\\']|\\(?:\r\n?|\n|\f)|\\[\s\S])*\'/,null],["lang-css-str",/^url\(([^\)\"\']*)\)/i],[PR.PR_KEYWORD,/^(?:url|rgb|\!important|@import|@page|@media|@charset|inherit)(?=[^\-\w]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|(?:\\[0-9a-f]+ ?))(?:[_a-z0-9\-]|\\(?:\\[0-9a-f]+ ?))*)\s*:/i],[PR.PR_COMMENT,/^\/\*[^*]*\*+(?:[^\/*][^*]*\*+)*\//],[PR.PR_COMMENT,/^(?:)/],[PR.PR_LITERAL,/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],[PR.PR_LITERAL,/^#(?:[0-9a-f]{3}){1,2}/i],[PR.PR_PLAIN,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i],[PR.PR_PUNCTUATION,/^[^\s\w\'\"]+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_KEYWORD,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_STRING,/^[^\)\"\']+/]]),["css-str"]); diff --git a/sdk/lib/coverage/lcov-report/sort-arrow-sprite.png b/sdk/lib/coverage/lcov-report/sort-arrow-sprite.png new file mode 100644 index 000000000..6ed68316e Binary files /dev/null and b/sdk/lib/coverage/lcov-report/sort-arrow-sprite.png differ diff --git a/sdk/lib/coverage/lcov-report/sorter.js b/sdk/lib/coverage/lcov-report/sorter.js new file mode 100644 index 000000000..2bb296a8c --- /dev/null +++ b/sdk/lib/coverage/lcov-report/sorter.js @@ -0,0 +1,196 @@ +/* eslint-disable */ +var addSorting = (function() { + 'use strict'; + var cols, + currentSort = { + index: 0, + desc: false + }; + + // returns the summary table element + function getTable() { + return document.querySelector('.coverage-summary'); + } + // returns the thead element of the summary table + function getTableHeader() { + return getTable().querySelector('thead tr'); + } + // returns the tbody element of the summary table + function getTableBody() { + return getTable().querySelector('tbody'); + } + // returns the th element for nth column + function getNthColumn(n) { + return getTableHeader().querySelectorAll('th')[n]; + } + + function onFilterInput() { + const searchValue = document.getElementById('fileSearch').value; + const rows = document.getElementsByTagName('tbody')[0].children; + for (let i = 0; i < rows.length; i++) { + const row = rows[i]; + if ( + row.textContent + .toLowerCase() + .includes(searchValue.toLowerCase()) + ) { + row.style.display = ''; + } else { + row.style.display = 'none'; + } + } + } + + // loads the search box + function addSearchBox() { + var template = document.getElementById('filterTemplate'); + var templateClone = template.content.cloneNode(true); + templateClone.getElementById('fileSearch').oninput = onFilterInput; + template.parentElement.appendChild(templateClone); + } + + // loads all columns + function loadColumns() { + var colNodes = getTableHeader().querySelectorAll('th'), + colNode, + cols = [], + col, + i; + + for (i = 0; i < colNodes.length; i += 1) { + colNode = colNodes[i]; + col = { + key: colNode.getAttribute('data-col'), + sortable: !colNode.getAttribute('data-nosort'), + type: colNode.getAttribute('data-type') || 'string' + }; + cols.push(col); + if (col.sortable) { + col.defaultDescSort = col.type === 'number'; + colNode.innerHTML = + colNode.innerHTML + ''; + } + } + return cols; + } + // attaches a data attribute to every tr element with an object + // of data values keyed by column name + function loadRowData(tableRow) { + var tableCols = tableRow.querySelectorAll('td'), + colNode, + col, + data = {}, + i, + val; + for (i = 0; i < tableCols.length; i += 1) { + colNode = tableCols[i]; + col = cols[i]; + val = colNode.getAttribute('data-value'); + if (col.type === 'number') { + val = Number(val); + } + data[col.key] = val; + } + return data; + } + // loads all row data + function loadData() { + var rows = getTableBody().querySelectorAll('tr'), + i; + + for (i = 0; i < rows.length; i += 1) { + rows[i].data = loadRowData(rows[i]); + } + } + // sorts the table using the data for the ith column + function sortByIndex(index, desc) { + var key = cols[index].key, + sorter = function(a, b) { + a = a.data[key]; + b = b.data[key]; + return a < b ? -1 : a > b ? 1 : 0; + }, + finalSorter = sorter, + tableBody = document.querySelector('.coverage-summary tbody'), + rowNodes = tableBody.querySelectorAll('tr'), + rows = [], + i; + + if (desc) { + finalSorter = function(a, b) { + return -1 * sorter(a, b); + }; + } + + for (i = 0; i < rowNodes.length; i += 1) { + rows.push(rowNodes[i]); + tableBody.removeChild(rowNodes[i]); + } + + rows.sort(finalSorter); + + for (i = 0; i < rows.length; i += 1) { + tableBody.appendChild(rows[i]); + } + } + // removes sort indicators for current column being sorted + function removeSortIndicators() { + var col = getNthColumn(currentSort.index), + cls = col.className; + + cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, ''); + col.className = cls; + } + // adds sort indicators for current column being sorted + function addSortIndicators() { + getNthColumn(currentSort.index).className += currentSort.desc + ? ' sorted-desc' + : ' sorted'; + } + // adds event listeners for all sorter widgets + function enableUI() { + var i, + el, + ithSorter = function ithSorter(i) { + var col = cols[i]; + + return function() { + var desc = col.defaultDescSort; + + if (currentSort.index === i) { + desc = !currentSort.desc; + } + sortByIndex(i, desc); + removeSortIndicators(); + currentSort.index = i; + currentSort.desc = desc; + addSortIndicators(); + }; + }; + for (i = 0; i < cols.length; i += 1) { + if (cols[i].sortable) { + // add the click event handler on the th so users + // dont have to click on those tiny arrows + el = getNthColumn(i).querySelector('.sorter').parentElement; + if (el.addEventListener) { + el.addEventListener('click', ithSorter(i)); + } else { + el.attachEvent('onclick', ithSorter(i)); + } + } + } + } + // adds sorting functionality to the UI + return function() { + if (!getTable()) { + return; + } + cols = loadColumns(); + loadData(); + addSearchBox(); + addSortIndicators(); + enableUI(); + }; +})(); + +window.addEventListener('load', addSorting); diff --git a/sdk/lib/coverage/lcov-report/util/deepEqual.ts.html b/sdk/lib/coverage/lcov-report/util/deepEqual.ts.html new file mode 100644 index 000000000..0ebb3ad61 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/util/deepEqual.ts.html @@ -0,0 +1,142 @@ + + + + + + Code coverage report for util/deepEqual.ts + + + + + + + + + +
+
+

All files / util deepEqual.ts

+
+ +
+ 66.66% + Statements + 14/21 +
+ + +
+ 16.66% + Branches + 1/6 +
+ + +
+ 100% + Functions + 2/2 +
+ + +
+ 85.71% + Lines + 12/14 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +201x +  +1x +11x +3x +3x +  +  +  +3x +6x +3x +5x +10x +10x +  +  +3x +  + 
import { object } from "ts-matches"
+ 
+export function deepEqual(...args: unknown[]) {
+  if (!object.test(args[args.length - 1])) return args[args.length - 1]
+  const objects = args.filter(object.test)
+  Iif (objects.length === 0) {
+    for (const x of args) Iif (x !== args[0]) return false
+    return true
+  }
+  Iif (objects.length !== args.length) return false
+  const allKeys = new Set(objects.flatMap((x) => Object.keys(x)))
+  for (const key of allKeys) {
+    for (const x of objects) {
+      Iif (!(key in x)) return false
+      Iif (!deepEqual((objects[0] as any)[key], (x as any)[key])) return false
+    }
+  }
+  return true
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/util/deepMerge.ts.html b/sdk/lib/coverage/lcov-report/util/deepMerge.ts.html new file mode 100644 index 000000000..51da4e156 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/util/deepMerge.ts.html @@ -0,0 +1,136 @@ + + + + + + Code coverage report for util/deepMerge.ts + + + + + + + + + +
+
+

All files / util deepMerge.ts

+
+ +
+ 94.44% + Statements + 17/18 +
+ + +
+ 80% + Branches + 4/5 +
+ + +
+ 100% + Functions + 4/4 +
+ + +
+ 100% + Lines + 13/13 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +181x +  +1x +13x +13x +14x +7x +5x +11x +5x +8x +18x +  +8x +  +5x +  + 
import { object } from "ts-matches"
+ 
+export function deepMerge(...args: unknown[]): unknown {
+  const lastItem = (args as any)[args.length - 1]
+  if (!object.test(lastItem)) return lastItem
+  const objects = args.filter(object.test).filter((x) => !Array.isArray(x))
+  if (objects.length === 0) return lastItem as any
+  Iif (objects.length === 1) objects.unshift({})
+  const allKeys = new Set(objects.flatMap((x) => Object.keys(x)))
+  for (const key of allKeys) {
+    const filteredValues = objects.flatMap((x) =>
+      key in x ? [(x as any)[key]] : [],
+    )
+    ;(objects as any)[0][key] = deepMerge(...filteredValues)
+  }
+  return objects[0] as any
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/util/getServiceInterface.ts.html b/sdk/lib/coverage/lcov-report/util/getServiceInterface.ts.html new file mode 100644 index 000000000..2ca2587ff --- /dev/null +++ b/sdk/lib/coverage/lcov-report/util/getServiceInterface.ts.html @@ -0,0 +1,934 @@ + + + + + + Code coverage report for util/getServiceInterface.ts + + + + + + + + + +
+
+

All files / util getServiceInterface.ts

+
+ +
+ 20.87% + Statements + 19/91 +
+ + +
+ 0% + Branches + 0/32 +
+ + +
+ 2.5% + Functions + 1/40 +
+ + +
+ 19.27% + Lines + 16/83 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +1x +8x +8x +8x +8x +8x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +1x +  +  +1x +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  + 
import { ServiceInterfaceType } from "../StartSdk"
+import { knownProtocols } from "../interfaces/Host"
+import {
+  AddressInfo,
+  Effects,
+  Host,
+  HostAddress,
+  Hostname,
+  HostnameInfo,
+  HostnameInfoIp,
+  HostnameInfoOnion,
+  IpInfo,
+} from "../types"
+ 
+export type UrlString = string
+export type HostId = string
+ 
+const getHostnameRegex = /^(\w+:\/\/)?([^\/\:]+)(:\d{1,3})?(\/)?/
+export const getHostname = (url: string): Hostname | null => {
+  const founds = url.match(getHostnameRegex)?.[2]
+  Iif (!founds) return null
+  const parts = founds.split("@")
+  const last = parts[parts.length - 1] as Hostname | null
+  return last
+}
+ 
+export type Filled = {
+  hostnames: HostnameInfo[]
+  onionHostnames: HostnameInfo[]
+  localHostnames: HostnameInfo[]
+  ipHostnames: HostnameInfo[]
+  ipv4Hostnames: HostnameInfo[]
+  ipv6Hostnames: HostnameInfo[]
+  nonIpHostnames: HostnameInfo[]
+ 
+  urls: UrlString[]
+  onionUrls: UrlString[]
+  localUrls: UrlString[]
+  ipUrls: UrlString[]
+  ipv4Urls: UrlString[]
+  ipv6Urls: UrlString[]
+  nonIpUrls: UrlString[]
+}
+export type FilledAddressInfo = AddressInfo & Filled
+export type ServiceInterfaceFilled = {
+  id: string
+  /** The title of this field to be displayed */
+  name: string
+  /** Human readable description, used as tooltip usually */
+  description: string
+  /** Whether or not the interface has a primary URL */
+  hasPrimary: boolean
+  /** Whether or not the interface disabled */
+  disabled: boolean
+  /** Whether or not to mask the URIs for this interface. Useful if the URIs contain sensitive information, such as a password, macaroon, or API key */
+  masked: boolean
+  /** Information about the host for this binding */
+  host: Host
+  /** URI information */
+  addressInfo: FilledAddressInfo
+  /** Indicates if we are a ui/p2p/api for the kind of interface that this is representing */
+  type: ServiceInterfaceType
+  /** The primary hostname for the service, as chosen by the user */
+  primaryHostname: Hostname | null
+  /** The primary URL for the service, as chosen by the user */
+  primaryUrl: UrlString | null
+}
+const either =
+  <A>(...args: ((a: A) => boolean)[]) =>
+  (a: A) =>
+    args.some((x) => x(a))
+const negate =
+  <A>(fn: (a: A) => boolean) =>
+  (a: A) =>
+    !fn(a)
+const unique = <A>(values: A[]) => Array.from(new Set(values))
+export const addressHostToUrl = (
+  { scheme, sslScheme, username, suffix }: AddressInfo,
+  host: HostnameInfo,
+): UrlString[] => {
+  const res = []
+  const fmt = (scheme: string | null, host: HostnameInfo, port: number) => {
+    const excludePort =
+      scheme &&
+      scheme in knownProtocols &&
+      port === knownProtocols[scheme as keyof typeof knownProtocols].defaultPort
+    let hostname
+    if (host.kind === "onion") {
+      hostname = host.hostname.value
+    } else Iif (host.kind === "ip") {
+      if (host.hostname.kind === "domain") {
+        hostname = `${host.hostname.subdomain ? `${host.hostname.subdomain}.` : ""}${host.hostname.domain}`
+      } else {
+        hostname = host.hostname.value
+      }
+    }
+    return `${scheme ? `${scheme}://` : ""}${
+      username ? `${username}@` : ""
+    }${hostname}${excludePort ? "" : `:${port}`}${suffix}`
+  }
+  Iif (host.hostname.sslPort !== null) {
+    res.push(fmt(sslScheme, host, host.hostname.sslPort))
+  }
+  Iif (host.hostname.port !== null) {
+    res.push(fmt(scheme, host, host.hostname.port))
+  }
+ 
+  return res
+}
+ 
+export const filledAddress = (
+  host: Host,
+  addressInfo: AddressInfo,
+): FilledAddressInfo => {
+  const toUrl = addressHostToUrl.bind(null, addressInfo)
+  const hostnames = host.hostnameInfo[addressInfo.internalPort]
+ 
+  return {
+    ...addressInfo,
+    hostnames,
+    get onionHostnames() {
+      return hostnames.filter((h) => h.kind === "onion")
+    },
+    get localHostnames() {
+      return hostnames.filter(
+        (h) => h.kind === "ip" && h.hostname.kind === "local",
+      )
+    },
+    get ipHostnames() {
+      return hostnames.filter(
+        (h) =>
+          h.kind === "ip" &&
+          (h.hostname.kind === "ipv4" || h.hostname.kind === "ipv6"),
+      )
+    },
+    get ipv4Hostnames() {
+      return hostnames.filter(
+        (h) => h.kind === "ip" && h.hostname.kind === "ipv4",
+      )
+    },
+    get ipv6Hostnames() {
+      return hostnames.filter(
+        (h) => h.kind === "ip" && h.hostname.kind === "ipv6",
+      )
+    },
+    get nonIpHostnames() {
+      return hostnames.filter(
+        (h) =>
+          h.kind === "ip" &&
+          h.hostname.kind !== "ipv4" &&
+          h.hostname.kind !== "ipv6",
+      )
+    },
+    get urls() {
+      return this.hostnames.flatMap(toUrl)
+    },
+    get onionUrls() {
+      return this.onionHostnames.flatMap(toUrl)
+    },
+    get localUrls() {
+      return this.localHostnames.flatMap(toUrl)
+    },
+    get ipUrls() {
+      return this.ipHostnames.flatMap(toUrl)
+    },
+    get ipv4Urls() {
+      return this.ipv4Hostnames.flatMap(toUrl)
+    },
+    get ipv6Urls() {
+      return this.ipv6Hostnames.flatMap(toUrl)
+    },
+    get nonIpUrls() {
+      return this.nonIpHostnames.flatMap(toUrl)
+    },
+  }
+}
+ 
+const makeInterfaceFilled = async ({
+  effects,
+  id,
+  packageId,
+  callback,
+}: {
+  effects: Effects
+  id: string
+  packageId: string | null
+  callback: () => void
+}) => {
+  const serviceInterfaceValue = await effects.getServiceInterface({
+    serviceInterfaceId: id,
+    packageId,
+    callback,
+  })
+  const hostId = serviceInterfaceValue.addressInfo.hostId
+  const host = await effects.getHostInfo({
+    packageId,
+    hostId,
+    callback,
+  })
+  const primaryUrl = await effects
+    .getPrimaryUrl({
+      serviceInterfaceId: id,
+      packageId,
+      callback,
+    })
+    .catch((e) => null)
+ 
+  const interfaceFilled: ServiceInterfaceFilled = {
+    ...serviceInterfaceValue,
+    primaryUrl: primaryUrl,
+    host,
+    addressInfo: filledAddress(host, serviceInterfaceValue.addressInfo),
+    get primaryHostname() {
+      Iif (primaryUrl == null) return null
+      return getHostname(primaryUrl)
+    },
+  }
+  return interfaceFilled
+}
+ 
+export class GetServiceInterface {
+  constructor(
+    readonly effects: Effects,
+    readonly opts: { id: string; packageId: string | null },
+  ) {}
+ 
+  /**
+   * Returns the value of Store at the provided path. Restart the service if the value changes
+   */
+  async const() {
+    const { id, packageId } = this.opts
+    const callback = this.effects.restart
+    const interfaceFilled: ServiceInterfaceFilled = await makeInterfaceFilled({
+      effects: this.effects,
+      id,
+      packageId,
+      callback,
+    })
+ 
+    return interfaceFilled
+  }
+  /**
+   * Returns the value of ServiceInterfacesFilled at the provided path. Does nothing if the value changes
+   */
+  async once() {
+    const { id, packageId } = this.opts
+    const callback = () => {}
+    const interfaceFilled: ServiceInterfaceFilled = await makeInterfaceFilled({
+      effects: this.effects,
+      id,
+      packageId,
+      callback,
+    })
+ 
+    return interfaceFilled
+  }
+ 
+  /**
+   * Watches the value of ServiceInterfacesFilled at the provided path. Takes a custom callback function to run whenever the value changes
+   */
+  async *watch() {
+    const { id, packageId } = this.opts
+    while (true) {
+      let callback: () => void = () => {}
+      const waitForNext = new Promise<void>((resolve) => {
+        callback = resolve
+      })
+      yield await makeInterfaceFilled({
+        effects: this.effects,
+        id,
+        packageId,
+        callback,
+      })
+      await waitForNext
+    }
+  }
+}
+export function getServiceInterface(
+  effects: Effects,
+  opts: { id: string; packageId: string | null },
+) {
+  return new GetServiceInterface(effects, opts)
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/util/index.html b/sdk/lib/coverage/lcov-report/util/index.html new file mode 100644 index 000000000..9ed2146a9 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/util/index.html @@ -0,0 +1,191 @@ + + + + + + Code coverage report for util + + + + + + + + + +
+
+

All files util

+
+ +
+ 42.85% + Statements + 63/147 +
+ + +
+ 19.6% + Branches + 10/51 +
+ + +
+ 22.64% + Functions + 12/53 +
+ + +
+ 41.6% + Lines + 52/125 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
deepEqual.ts +
+
66.66%14/2116.66%1/6100%2/285.71%12/14
deepMerge.ts +
+
94.44%17/1880%4/5100%4/4100%13/13
getServiceInterface.ts +
+
20.87%19/910%0/322.5%1/4019.27%16/83
once.ts +
+
50%3/60%0/150%1/250%3/6
splitCommand.ts +
+
100%9/9100%5/5100%4/4100%7/7
stringFromStdErrOut.ts +
+
50%1/20%0/20%0/150%1/2
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/util/once.ts.html b/sdk/lib/coverage/lcov-report/util/once.ts.html new file mode 100644 index 000000000..09ed7e7a9 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/util/once.ts.html @@ -0,0 +1,112 @@ + + + + + + Code coverage report for util/once.ts + + + + + + + + + +
+
+

All files / util once.ts

+
+ +
+ 50% + Statements + 3/6 +
+ + +
+ 0% + Branches + 0/1 +
+ + +
+ 50% + Functions + 1/2 +
+ + +
+ 50% + Lines + 3/6 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +101x +1x +1x +  +  +  +  +  +  + 
export function once<B>(fn: () => B): () => B {
+  let result: [B] | [] = []
+  return () => {
+    Iif (!result.length) {
+      result = [fn()]
+    }
+    return result[0]
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/util/splitCommand.ts.html b/sdk/lib/coverage/lcov-report/util/splitCommand.ts.html new file mode 100644 index 000000000..e2e114382 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/util/splitCommand.ts.html @@ -0,0 +1,136 @@ + + + + + + Code coverage report for util/splitCommand.ts + + + + + + + + + +
+
+

All files / util splitCommand.ts

+
+ +
+ 100% + Statements + 9/9 +
+ + +
+ 100% + Branches + 5/5 +
+ + +
+ 100% + Functions + 4/4 +
+ + +
+ 100% + Lines + 7/7 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +181x +  +  +1x +  +  +13x +9x +  +  +15x +  +16x +  +92x +  +  + 
import { arrayOf, string } from "ts-matches"
+import { ValidIfNoStupidEscape } from "../types"
+ 
+export const splitCommand = (
+  command: string | [string, ...string[]],
+): string[] => {
+  if (arrayOf(string).test(command)) return command
+  return String(command)
+    .split('"')
+    .flatMap((x, i) =>
+      i % 2 !== 0
+        ? [x]
+        : x.split("'").flatMap((x, i) => (i % 2 !== 0 ? [x] : x.split(" "))),
+    )
+    .map((x) => x.trim())
+    .filter(Boolean)
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov-report/util/stringFromStdErrOut.ts.html b/sdk/lib/coverage/lcov-report/util/stringFromStdErrOut.ts.html new file mode 100644 index 000000000..617069cb8 --- /dev/null +++ b/sdk/lib/coverage/lcov-report/util/stringFromStdErrOut.ts.html @@ -0,0 +1,103 @@ + + + + + + Code coverage report for util/stringFromStdErrOut.ts + + + + + + + + + +
+
+

All files / util stringFromStdErrOut.ts

+
+ +
+ 50% + Statements + 1/2 +
+ + +
+ 0% + Branches + 0/2 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 50% + Lines + 1/2 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +71x +  +  +  +  +  + 
export async function stringFromStdErrOut(x: {
+  stdout: string
+  stderr: string
+}) {
+  return x?.stderr ? Promise.reject(x.stderr) : x.stdout
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/sdk/lib/coverage/lcov.info b/sdk/lib/coverage/lcov.info new file mode 100644 index 000000000..bb8f64179 --- /dev/null +++ b/sdk/lib/coverage/lcov.info @@ -0,0 +1,5539 @@ +TN: +SF:lib/Dependency.ts +FN:4,(anonymous_0) +FNF:1 +FNH:0 +FNDA:0,(anonymous_0) +DA:3,5 +DA:5,0 +LF:2 +LH:1 +BRF:0 +BRH:0 +end_of_record +TN: +SF:lib/StartSdk.ts +FN:99,removeCallbackTypes +FN:100,(anonymous_8) +FN:116,(anonymous_9) +FN:117,(anonymous_10) +FN:120,(anonymous_11) +FN:123,(anonymous_12) +FN:127,(anonymous_13) +FN:159,(anonymous_14) +FN:160,(anonymous_15) +FN:161,(anonymous_16) +FN:162,(anonymous_17) +FN:163,(anonymous_18) +FN:164,(anonymous_19) +FN:165,(anonymous_20) +FN:166,(anonymous_21) +FN:168,(anonymous_22) +FN:169,(anonymous_23) +FN:171,(anonymous_24) +FN:173,(anonymous_25) +FN:175,(anonymous_26) +FN:176,(anonymous_27) +FN:177,(anonymous_28) +FN:178,(anonymous_29) +FN:179,(anonymous_30) +FN:180,(anonymous_31) +FN:181,(anonymous_32) +FN:195,(anonymous_33) +FN:201,(anonymous_34) +FN:206,(anonymous_35) +FN:208,(anonymous_36) +FN:216,(anonymous_37) +FN:226,(anonymous_38) +FN:233,(anonymous_39) +FN:249,(anonymous_40) +FN:252,(anonymous_41) +FN:266,(anonymous_42) +FN:291,(anonymous_43) +FN:306,(anonymous_44) +FN:309,(anonymous_45) +FN:318,(anonymous_46) +FN:343,(anonymous_47) +FN:348,(anonymous_48) +FN:358,(anonymous_49) +FN:360,(anonymous_50) +FN:362,(anonymous_51) +FN:370,(anonymous_52) +FN:378,(anonymous_53) +FN:386,(anonymous_54) +FN:397,(anonymous_55) +FN:403,(anonymous_56) +FN:407,(anonymous_57) +FN:429,(anonymous_58) +FN:448,(anonymous_59) +FN:449,(anonymous_60) +FN:456,(anonymous_61) +FN:463,(anonymous_62) +FN:466,(anonymous_63) +FN:468,(anonymous_64) +FN:477,(anonymous_65) +FN:482,(anonymous_66) +FN:485,(anonymous_67) +FN:488,(anonymous_68) +FN:492,(anonymous_69) +FN:499,(anonymous_70) +FN:508,(anonymous_71) +FN:539,(anonymous_72) +FN:555,(anonymous_73) +FN:595,(anonymous_74) +FN:607,(anonymous_75) +FN:628,(anonymous_76) +FN:644,(anonymous_77) +FN:663,(anonymous_78) +FN:676,(anonymous_79) +FN:692,(anonymous_80) +FN:705,(anonymous_81) +FN:720,(anonymous_82) +FN:739,(anonymous_83) +FN:757,(anonymous_84) +FN:772,runCommand +FN:785,(anonymous_86) +FN:788,nullifyProperties +FN:790,(anonymous_88) +FN:793,nullifyProperties_ +FN:801,(anonymous_90) +FNF:84 +FNH:10 +FNDA:0,removeCallbackTypes +FNDA:0,(anonymous_8) +FNDA:18,(anonymous_9) +FNDA:6,(anonymous_10) +FNDA:6,(anonymous_11) +FNDA:6,(anonymous_12) +FNDA:6,(anonymous_13) +FNDA:0,(anonymous_14) +FNDA:0,(anonymous_15) +FNDA:0,(anonymous_16) +FNDA:0,(anonymous_17) +FNDA:0,(anonymous_18) +FNDA:0,(anonymous_19) +FNDA:0,(anonymous_20) +FNDA:0,(anonymous_21) +FNDA:0,(anonymous_22) +FNDA:0,(anonymous_23) +FNDA:0,(anonymous_24) +FNDA:0,(anonymous_25) +FNDA:0,(anonymous_26) +FNDA:0,(anonymous_27) +FNDA:0,(anonymous_28) +FNDA:0,(anonymous_29) +FNDA:0,(anonymous_30) +FNDA:0,(anonymous_31) +FNDA:0,(anonymous_32) +FNDA:0,(anonymous_33) +FNDA:0,(anonymous_34) +FNDA:0,(anonymous_35) +FNDA:0,(anonymous_36) +FNDA:0,(anonymous_37) +FNDA:0,(anonymous_38) +FNDA:0,(anonymous_39) +FNDA:0,(anonymous_40) +FNDA:0,(anonymous_41) +FNDA:0,(anonymous_42) +FNDA:0,(anonymous_43) +FNDA:0,(anonymous_44) +FNDA:0,(anonymous_45) +FNDA:0,(anonymous_46) +FNDA:0,(anonymous_47) +FNDA:0,(anonymous_48) +FNDA:0,(anonymous_49) +FNDA:0,(anonymous_50) +FNDA:0,(anonymous_51) +FNDA:0,(anonymous_52) +FNDA:0,(anonymous_53) +FNDA:1,(anonymous_54) +FNDA:0,(anonymous_55) +FNDA:0,(anonymous_56) +FNDA:0,(anonymous_57) +FNDA:0,(anonymous_58) +FNDA:0,(anonymous_59) +FNDA:0,(anonymous_60) +FNDA:0,(anonymous_61) +FNDA:0,(anonymous_62) +FNDA:0,(anonymous_63) +FNDA:0,(anonymous_64) +FNDA:0,(anonymous_65) +FNDA:0,(anonymous_66) +FNDA:0,(anonymous_67) +FNDA:0,(anonymous_68) +FNDA:32,(anonymous_69) +FNDA:0,(anonymous_70) +FNDA:1,(anonymous_71) +FNDA:4,(anonymous_72) +FNDA:0,(anonymous_73) +FNDA:0,(anonymous_74) +FNDA:0,(anonymous_75) +FNDA:0,(anonymous_76) +FNDA:0,(anonymous_77) +FNDA:0,(anonymous_78) +FNDA:0,(anonymous_79) +FNDA:0,(anonymous_80) +FNDA:0,(anonymous_81) +FNDA:0,(anonymous_82) +FNDA:0,(anonymous_83) +FNDA:4,(anonymous_84) +FNDA:0,runCommand +FNDA:0,(anonymous_86) +FNDA:0,nullifyProperties +FNDA:0,(anonymous_88) +FNDA:0,nullifyProperties_ +FNDA:0,(anonymous_90) +DA:1,5 +DA:2,5 +DA:12,5 +DA:13,5 +DA:24,5 +DA:25,5 +DA:26,5 +DA:27,5 +DA:28,5 +DA:29,5 +DA:30,5 +DA:31,5 +DA:32,5 +DA:33,5 +DA:34,5 +DA:35,5 +DA:36,5 +DA:37,5 +DA:38,5 +DA:39,5 +DA:40,5 +DA:41,5 +DA:42,5 +DA:47,5 +DA:52,5 +DA:54,5 +DA:55,5 +DA:56,5 +DA:57,5 +DA:58,5 +DA:62,5 +DA:63,5 +DA:64,5 +DA:65,5 +DA:66,5 +DA:67,5 +DA:69,5 +DA:71,5 +DA:72,5 +DA:77,5 +DA:80,5 +DA:95,5 +DA:96,5 +DA:97,5 +DA:100,0 +DA:101,0 +DA:102,0 +DA:104,0 +DA:105,0 +DA:107,0 +DA:108,0 +DA:110,0 +DA:115,5 +DA:116,18 +DA:118,6 +DA:121,6 +DA:124,6 +DA:158,6 +DA:159,0 +DA:160,0 +DA:161,0 +DA:162,0 +DA:163,0 +DA:164,0 +DA:165,0 +DA:167,0 +DA:168,0 +DA:170,0 +DA:172,0 +DA:174,0 +DA:175,0 +DA:176,0 +DA:177,0 +DA:178,0 +DA:179,0 +DA:180,0 +DA:181,0 +DA:184,6 +DA:196,0 +DA:205,0 +DA:207,0 +DA:212,0 +DA:221,0 +DA:230,0 +DA:238,0 +DA:249,0 +DA:263,0 +DA:282,0 +DA:283,0 +DA:305,0 +DA:307,0 +DA:314,0 +DA:335,0 +DA:344,0 +DA:349,0 +DA:359,0 +DA:361,0 +DA:369,0 +DA:377,0 +DA:385,0 +DA:396,1 +DA:403,0 +DA:404,0 +DA:405,0 +DA:412,0 +DA:440,0 +DA:448,0 +DA:455,0 +DA:461,0 +DA:466,0 +DA:467,0 +DA:469,0 +DA:478,0 +DA:484,0 +DA:487,0 +DA:489,0 +DA:496,32 +DA:504,0 +DA:529,1 +DA:554,4 +DA:580,0 +DA:606,0 +DA:627,0 +DA:643,0 +DA:662,0 +DA:675,0 +DA:691,0 +DA:704,0 +DA:719,0 +DA:733,0 +DA:754,0 +DA:766,4 +DA:772,5 +DA:780,0 +DA:781,0 +DA:785,0 +DA:789,0 +DA:790,0 +DA:794,0 +DA:795,0 +DA:797,0 +DA:801,0 +LF:142 +LH:57 +BRDA:101,0,0,0 +BRDA:101,0,1,0 +BRDA:101,1,0,0 +BRDA:101,1,1,0 +BRDA:104,2,0,0 +BRDA:107,3,0,0 +BRDA:415,4,0,0 +BRDA:415,4,1,0 +BRDA:784,5,0,0 +BRDA:784,5,1,0 +BRDA:794,6,0,0 +BRF:11 +BRH:0 +end_of_record +TN: +SF:lib/actions/createAction.ts +FN:18,(anonymous_0) +FN:33,(anonymous_1) +FN:55,(anonymous_2) +FN:62,(anonymous_3) +FN:69,(anonymous_4) +FN:75,(anonymous_5) +FN:82,(anonymous_6) +FNF:7 +FNH:0 +FNDA:0,(anonymous_0) +FNDA:0,(anonymous_1) +FNDA:0,(anonymous_2) +FNDA:0,(anonymous_3) +FNDA:0,(anonymous_4) +FNDA:0,(anonymous_5) +FNDA:0,(anonymous_6) +DA:9,5 +DA:19,0 +DA:20,0 +DA:25,0 +DA:29,0 +DA:30,0 +DA:47,0 +DA:55,0 +DA:56,0 +DA:62,0 +DA:63,0 +DA:70,0 +DA:71,0 +DA:72,0 +DA:76,0 +DA:83,0 +DA:89,5 +LF:17 +LH:2 +BRDA:30,0,0,0 +BRDA:70,1,0,0 +BRF:2 +BRH:0 +end_of_record +TN: +SF:lib/actions/setupActions.ts +FN:5,setupActions +FN:8,(anonymous_1) +FN:19,(anonymous_2) +FN:22,(anonymous_3) +FN:24,(anonymous_4) +FNF:5 +FNH:0 +FNDA:0,setupActions +FNDA:0,(anonymous_1) +FNDA:0,(anonymous_2) +FNDA:0,(anonymous_3) +FNDA:0,(anonymous_4) +DA:5,5 +DA:8,0 +DA:9,0 +DA:10,0 +DA:11,0 +DA:13,0 +DA:18,0 +DA:20,0 +DA:23,0 +DA:24,0 +DA:28,0 +LF:11 +LH:1 +BRF:0 +BRH:0 +end_of_record +TN: +SF:lib/backup/Backups.ts +FN:46,(anonymous_6) +FN:50,(anonymous_7) +FN:54,(anonymous_8) +FN:62,(anonymous_9) +FN:67,(anonymous_10) +FN:74,(anonymous_11) +FN:81,(anonymous_12) +FN:83,(anonymous_13) +FN:91,(anonymous_14) +FN:92,(anonymous_15) +FN:97,(anonymous_16) +FN:98,(anonymous_17) +FN:116,(anonymous_18) +FN:137,notEmptyPath +FN:140,runRsync +FN:177,(anonymous_21) +FN:186,(anonymous_22) +FN:190,(anonymous_23) +FN:197,(anonymous_24) +FN:198,(anonymous_25) +FN:206,(anonymous_26) +FN:207,(anonymous_27) +FNF:22 +FNH:0 +FNDA:0,(anonymous_6) +FNDA:0,(anonymous_7) +FNDA:0,(anonymous_8) +FNDA:0,(anonymous_9) +FNDA:0,(anonymous_10) +FNDA:0,(anonymous_11) +FNDA:0,(anonymous_12) +FNDA:0,(anonymous_13) +FNDA:0,(anonymous_14) +FNDA:0,(anonymous_15) +FNDA:0,(anonymous_16) +FNDA:0,(anonymous_17) +FNDA:0,(anonymous_18) +FNDA:0,notEmptyPath +FNDA:0,runRsync +FNDA:0,(anonymous_21) +FNDA:0,(anonymous_22) +FNDA:0,(anonymous_23) +FNDA:0,(anonymous_24) +FNDA:0,(anonymous_25) +FNDA:0,(anonymous_26) +FNDA:0,(anonymous_27) +DA:3,5 +DA:5,5 +DA:8,5 +DA:43,5 +DA:44,5 +DA:47,0 +DA:48,0 +DA:53,0 +DA:54,0 +DA:65,0 +DA:70,0 +DA:73,5 +DA:75,0 +DA:79,0 +DA:82,0 +DA:83,0 +DA:92,0 +DA:93,0 +DA:95,0 +DA:98,0 +DA:101,0 +DA:102,0 +DA:112,0 +DA:114,0 +DA:116,0 +DA:119,0 +DA:120,0 +DA:130,0 +DA:132,0 +DA:134,0 +DA:138,0 +DA:154,0 +DA:156,0 +DA:157,0 +DA:158,0 +DA:159,0 +DA:161,0 +DA:162,0 +DA:164,0 +DA:165,0 +DA:167,0 +DA:168,0 +DA:170,0 +DA:171,0 +DA:172,0 +DA:173,0 +DA:174,0 +DA:175,0 +DA:176,0 +DA:177,0 +DA:178,0 +DA:179,0 +DA:180,0 +DA:181,0 +DA:182,0 +DA:186,0 +DA:187,0 +DA:190,0 +DA:191,0 +DA:192,0 +DA:193,0 +DA:195,0 +DA:197,0 +DA:198,0 +DA:199,0 +DA:200,0 +DA:202,0 +DA:206,0 +DA:207,0 +DA:208,0 +LF:70 +LH:6 +BRDA:47,0,0,0 +BRDA:48,1,0,0 +BRDA:158,2,0,0 +BRDA:161,3,0,0 +BRDA:164,4,0,0 +BRDA:181,5,0,0 +BRDA:192,6,0,0 +BRDA:199,7,0,0 +BRDA:199,7,1,0 +BRF:9 +BRH:0 +end_of_record +TN: +SF:lib/backup/setupBackups.ts +FN:10,setupBackups +FN:28,(anonymous_1) +FN:29,(anonymous_2) +FN:35,(anonymous_3) +FN:36,(anonymous_4) +FNF:5 +FNH:0 +FNDA:0,setupBackups +FNDA:0,(anonymous_1) +FNDA:0,(anonymous_2) +FNDA:0,(anonymous_3) +FNDA:0,(anonymous_4) +DA:1,5 +DA:10,5 +DA:14,0 +DA:15,0 +DA:16,0 +DA:17,0 +DA:18,0 +DA:20,0 +DA:23,0 +DA:27,0 +DA:29,0 +DA:30,0 +DA:31,0 +DA:36,0 +DA:37,0 +DA:38,0 +DA:40,0 +DA:44,0 +LF:18 +LH:2 +BRDA:17,0,0,0 +BRDA:17,0,1,0 +BRF:2 +BRH:0 +end_of_record +TN: +SF:lib/config/configConstants.ts +FN:51,(anonymous_0) +FNF:1 +FNH:0 +FNDA:0,(anonymous_0) +DA:2,5 +DA:3,5 +DA:4,5 +DA:5,5 +DA:6,5 +DA:11,5 +DA:50,5 +DA:52,0 +DA:53,0 +LF:9 +LH:7 +BRDA:53,0,0,0 +BRDA:53,0,1,0 +BRF:2 +BRH:0 +end_of_record +TN: +SF:lib/config/configTypes.ts +FN:267,isValueSpecListOf +FNF:1 +FNH:1 +FNDA:3,isValueSpecListOf +DA:267,1 +DA:271,3 +LF:2 +LH:2 +BRDA:271,0,0,3 +BRDA:271,0,1,3 +BRF:2 +BRH:2 +end_of_record +TN: +SF:lib/config/setupConfig.ts +FN:43,setupConfig +FN:58,(anonymous_2) +FN:75,(anonymous_3) +FNF:3 +FNH:0 +FNDA:0,setupConfig +FNDA:0,(anonymous_2) +FNDA:0,(anonymous_3) +DA:5,5 +DA:43,5 +DA:56,0 +DA:57,0 +DA:59,0 +DA:60,0 +DA:63,0 +DA:65,0 +DA:66,0 +DA:67,0 +DA:71,0 +DA:72,0 +DA:76,0 +DA:77,0 +DA:87,5 +LF:15 +LH:3 +BRDA:59,0,0,0 +BRDA:71,1,0,0 +BRDA:76,2,0,0 +BRDA:76,2,1,0 +BRF:4 +BRH:0 +end_of_record +TN: +SF:lib/config/builder/config.ts +FN:81,(anonymous_0) +FN:87,(anonymous_1) +FN:97,(anonymous_2) +FN:134,(anonymous_3) +FNF:4 +FNH:3 +FNDA:62,(anonymous_0) +FNDA:6,(anonymous_1) +FNDA:62,(anonymous_2) +FNDA:0,(anonymous_3) +DA:5,6 +DA:80,6 +DA:82,62 +DA:85,62 +DA:88,6 +DA:91,6 +DA:92,5 +DA:94,6 +DA:101,62 +DA:104,62 +DA:105,131 +DA:107,62 +DA:108,62 +DA:135,0 +LF:14 +LH:13 +BRF:0 +BRH:0 +end_of_record +TN: +SF:lib/config/builder/list.ts +FN:25,(anonymous_0) +FN:29,(anonymous_1) +FN:51,(anonymous_2) +FN:76,(anonymous_3) +FN:102,(anonymous_4) +FN:128,(anonymous_5) +FN:144,(anonymous_6) +FN:185,(anonymous_7) +FNF:8 +FNH:7 +FNDA:11,(anonymous_0) +FNDA:4,(anonymous_1) +FNDA:1,(anonymous_2) +FNDA:1,(anonymous_3) +FNDA:1,(anonymous_4) +FNDA:6,(anonymous_5) +FNDA:1,(anonymous_6) +FNDA:0,(anonymous_7) +DA:10,6 +DA:24,6 +DA:26,11 +DA:27,11 +DA:51,4 +DA:52,1 +DA:62,1 +DA:73,1 +DA:102,1 +DA:103,1 +DA:104,1 +DA:114,1 +DA:125,1 +DA:144,6 +DA:145,1 +DA:146,1 +DA:147,1 +DA:154,1 +DA:159,1 +DA:186,0 +LF:20 +LH:19 +BRF:0 +BRH:0 +end_of_record +TN: +SF:lib/config/builder/value.ts +FN:35,requiredLikeToAbove +FN:63,(anonymous_1) +FN:65,asRequiredParser +FN:99,(anonymous_3) +FN:103,(anonymous_4) +FN:113,(anonymous_5) +FN:124,(anonymous_6) +FN:137,(anonymous_7) +FN:148,(anonymous_8) +FN:169,(anonymous_9) +FN:188,(anonymous_10) +FN:213,(anonymous_11) +FN:233,(anonymous_12) +FN:245,(anonymous_13) +FN:260,(anonymous_14) +FN:275,(anonymous_15) +FN:290,(anonymous_16) +FN:307,(anonymous_17) +FN:324,(anonymous_18) +FN:343,(anonymous_19) +FN:361,(anonymous_20) +FN:371,(anonymous_21) +FN:385,(anonymous_22) +FN:397,(anonymous_23) +FN:410,(anonymous_24) +FN:424,(anonymous_25) +FN:440,(anonymous_26) +FN:456,(anonymous_27) +FN:472,(anonymous_28) +FN:492,(anonymous_29) +FN:503,(anonymous_30) +FN:509,(anonymous_31) +FN:527,(anonymous_32) +FN:540,(anonymous_33) +FN:559,(anonymous_34) +FN:574,(anonymous_35) +FN:594,(anonymous_36) +FN:608,(anonymous_37) +FN:616,(anonymous_38) +FN:627,(anonymous_39) +FN:641,(anonymous_40) +FN:649,(anonymous_41) +FN:662,(anonymous_42) +FN:671,(anonymous_43) +FN:690,(anonymous_44) +FN:703,(anonymous_45) +FN:718,(anonymous_46) +FN:731,(anonymous_47) +FN:748,(anonymous_48) +FN:762,(anonymous_49) +FN:763,(anonymous_50) +FN:780,(anonymous_51) +FNF:52 +FNH:40 +FNDA:16,requiredLikeToAbove +FNDA:5,(anonymous_1) +FNDA:89,asRequiredParser +FNDA:169,(anonymous_3) +FNDA:34,(anonymous_4) +FNDA:4,(anonymous_5) +FNDA:1,(anonymous_6) +FNDA:1,(anonymous_7) +FNDA:40,(anonymous_8) +FNDA:4,(anonymous_9) +FNDA:3,(anonymous_10) +FNDA:5,(anonymous_11) +FNDA:3,(anonymous_12) +FNDA:0,(anonymous_13) +FNDA:1,(anonymous_14) +FNDA:1,(anonymous_15) +FNDA:28,(anonymous_16) +FNDA:0,(anonymous_17) +FNDA:1,(anonymous_18) +FNDA:1,(anonymous_19) +FNDA:2,(anonymous_20) +FNDA:0,(anonymous_21) +FNDA:1,(anonymous_22) +FNDA:1,(anonymous_23) +FNDA:2,(anonymous_24) +FNDA:0,(anonymous_25) +FNDA:1,(anonymous_26) +FNDA:1,(anonymous_27) +FNDA:6,(anonymous_28) +FNDA:1,(anonymous_29) +FNDA:10,(anonymous_30) +FNDA:1,(anonymous_31) +FNDA:1,(anonymous_32) +FNDA:4,(anonymous_33) +FNDA:0,(anonymous_34) +FNDA:1,(anonymous_35) +FNDA:1,(anonymous_36) +FNDA:17,(anonymous_37) +FNDA:0,(anonymous_38) +FNDA:0,(anonymous_39) +FNDA:0,(anonymous_40) +FNDA:0,(anonymous_41) +FNDA:0,(anonymous_42) +FNDA:5,(anonymous_43) +FNDA:0,(anonymous_44) +FNDA:6,(anonymous_45) +FNDA:1,(anonymous_46) +FNDA:1,(anonymous_47) +FNDA:1,(anonymous_48) +FNDA:11,(anonymous_49) +FNDA:3,(anonymous_50) +FNDA:0,(anonymous_51) +DA:15,6 +DA:27,6 +DA:39,16 +DA:62,6 +DA:63,5 +DA:72,89 +DA:73,28 +DA:98,6 +DA:100,169 +DA:101,169 +DA:112,34 +DA:113,4 +DA:136,1 +DA:137,1 +DA:168,40 +DA:169,4 +DA:213,3 +DA:214,5 +DA:215,5 +DA:245,3 +DA:246,0 +DA:257,0 +DA:275,1 +DA:276,1 +DA:277,1 +DA:306,28 +DA:307,0 +DA:343,1 +DA:344,1 +DA:345,1 +DA:370,2 +DA:371,0 +DA:397,1 +DA:398,1 +DA:399,1 +DA:423,2 +DA:424,0 +DA:456,1 +DA:457,1 +DA:458,1 +DA:491,6 +DA:492,1 +DA:503,10 +DA:527,1 +DA:528,1 +DA:529,1 +DA:558,4 +DA:559,0 +DA:594,1 +DA:595,1 +DA:596,1 +DA:616,17 +DA:617,0 +DA:618,0 +DA:634,0 +DA:640,0 +DA:641,0 +DA:661,0 +DA:662,0 +DA:689,5 +DA:690,0 +DA:717,6 +DA:718,1 +DA:748,1 +DA:749,1 +DA:750,1 +DA:763,11 +DA:781,0 +LF:68 +LH:53 +BRDA:40,0,0,11 +BRDA:40,0,1,5 +BRDA:45,1,0,11 +BRDA:45,1,1,5 +BRDA:72,2,0,61 +BRDA:118,3,0,4 +BRDA:118,3,1,4 +BRDA:180,4,0,4 +BRDA:180,4,1,4 +BRDA:181,5,0,4 +BRDA:181,5,1,4 +BRDA:227,6,0,5 +BRDA:227,6,1,5 +BRDA:254,7,0,0 +BRDA:254,7,1,0 +BRDA:317,8,0,0 +BRDA:317,8,1,0 +BRDA:376,9,0,0 +BRDA:376,9,1,0 +BRDA:433,10,0,0 +BRDA:433,10,1,0 +BRDA:497,11,0,1 +BRDA:497,11,1,1 +BRDA:566,12,0,0 +BRDA:566,12,1,0 +BRDA:698,13,0,0 +BRDA:698,13,1,0 +BRDA:725,14,0,1 +BRDA:725,14,1,0 +BRF:29 +BRH:16 +end_of_record +TN: +SF:lib/config/builder/variants.ts +FN:56,(anonymous_0) +FN:60,(anonymous_1) +FN:70,(anonymous_2) +FN:89,(anonymous_3) +FN:117,(anonymous_4) +FNF:5 +FNH:4 +FNDA:12,(anonymous_0) +FNDA:12,(anonymous_1) +FNDA:28,(anonymous_2) +FNDA:2,(anonymous_3) +FNDA:0,(anonymous_4) +DA:3,5 +DA:54,5 +DA:57,12 +DA:58,12 +DA:69,12 +DA:71,28 +DA:78,12 +DA:90,2 +DA:93,2 +DA:94,4 +DA:95,4 +DA:100,2 +DA:118,0 +LF:13 +LH:12 +BRF:0 +BRH:0 +end_of_record +TN: +SF:lib/dependencies/DependencyConfig.ts +FN:16,(anonymous_0) +FN:22,(anonymous_1) +FN:33,(anonymous_2) +FNF:3 +FNH:1 +FNDA:0,(anonymous_0) +FNDA:1,(anonymous_1) +FNDA:0,(anonymous_2) +DA:3,5 +DA:10,5 +DA:16,5 +DA:20,0 +DA:23,1 +DA:27,1 +DA:34,0 +LF:7 +LH:5 +BRDA:20,0,0,0 +BRDA:20,0,1,0 +BRDA:27,1,0,1 +BRF:3 +BRH:1 +end_of_record +TN: +SF:lib/dependencies/dependencies.ts +FN:32,checkDependencies +FN:45,(anonymous_1) +FN:50,(anonymous_2) +FN:51,(anonymous_3) +FN:52,(anonymous_4) +FN:59,(anonymous_5) +FN:61,(anonymous_6) +FN:70,(anonymous_7) +FN:74,(anonymous_8) +FN:76,(anonymous_9) +FN:89,(anonymous_10) +FN:90,(anonymous_11) +FN:93,(anonymous_12) +FN:99,(anonymous_13) +FN:102,(anonymous_14) +FN:104,(anonymous_15) +FN:110,(anonymous_16) +FN:116,(anonymous_17) +FN:127,(anonymous_18) +FN:133,(anonymous_19) +FN:141,(anonymous_20) +FN:154,(anonymous_21) +FN:155,(anonymous_22) +FN:160,(anonymous_23) +FN:167,(anonymous_24) +FN:174,(anonymous_25) +FN:177,(anonymous_26) +FN:178,(anonymous_27) +FNF:28 +FNH:0 +FNDA:0,checkDependencies +FNDA:0,(anonymous_1) +FNDA:0,(anonymous_2) +FNDA:0,(anonymous_3) +FNDA:0,(anonymous_4) +FNDA:0,(anonymous_5) +FNDA:0,(anonymous_6) +FNDA:0,(anonymous_7) +FNDA:0,(anonymous_8) +FNDA:0,(anonymous_9) +FNDA:0,(anonymous_10) +FNDA:0,(anonymous_11) +FNDA:0,(anonymous_12) +FNDA:0,(anonymous_13) +FNDA:0,(anonymous_14) +FNDA:0,(anonymous_15) +FNDA:0,(anonymous_16) +FNDA:0,(anonymous_17) +FNDA:0,(anonymous_18) +FNDA:0,(anonymous_19) +FNDA:0,(anonymous_20) +FNDA:0,(anonymous_21) +FNDA:0,(anonymous_22) +FNDA:0,(anonymous_23) +FNDA:0,(anonymous_24) +FNDA:0,(anonymous_25) +FNDA:0,(anonymous_26) +FNDA:0,(anonymous_27) +DA:1,5 +DA:32,5 +DA:38,0 +DA:44,0 +DA:45,0 +DA:46,0 +DA:50,0 +DA:51,0 +DA:52,0 +DA:53,0 +DA:54,0 +DA:56,0 +DA:59,0 +DA:60,0 +DA:61,0 +DA:62,0 +DA:63,0 +DA:70,0 +DA:71,0 +DA:72,0 +DA:74,0 +DA:75,0 +DA:76,0 +DA:80,0 +DA:81,0 +DA:86,0 +DA:88,0 +DA:89,0 +DA:90,0 +DA:91,0 +DA:93,0 +DA:94,0 +DA:99,0 +DA:100,0 +DA:102,0 +DA:104,0 +DA:105,0 +DA:106,0 +DA:107,0 +DA:110,0 +DA:111,0 +DA:112,0 +DA:113,0 +DA:115,0 +DA:117,0 +DA:122,0 +DA:127,0 +DA:128,0 +DA:129,0 +DA:130,0 +DA:133,0 +DA:134,0 +DA:135,0 +DA:136,0 +DA:141,0 +DA:145,0 +DA:146,0 +DA:151,0 +DA:153,0 +DA:154,0 +DA:155,0 +DA:156,0 +DA:157,0 +DA:161,0 +DA:167,0 +DA:168,0 +DA:169,0 +DA:170,0 +DA:171,0 +DA:172,0 +DA:174,0 +DA:175,0 +DA:178,0 +DA:179,0 +DA:180,0 +DA:182,0 +DA:183,0 +DA:185,0 +DA:187,0 +DA:188,0 +DA:192,0 +LF:81 +LH:2 +BRDA:44,0,0,0 +BRDA:53,1,0,0 +BRDA:53,2,0,0 +BRDA:53,2,1,0 +BRDA:64,3,0,0 +BRDA:64,3,1,0 +BRDA:72,4,0,0 +BRDA:72,4,1,0 +BRDA:81,5,0,0 +BRDA:82,6,0,0 +BRDA:82,6,1,0 +BRDA:82,6,2,0 +BRDA:89,7,0,0 +BRDA:89,7,1,0 +BRDA:94,8,0,0 +BRDA:94,8,1,0 +BRDA:94,8,2,0 +BRDA:94,8,3,0 +BRDA:94,8,4,0 +BRDA:100,9,0,0 +BRDA:100,9,1,0 +BRDA:106,10,0,0 +BRDA:107,11,0,0 +BRDA:107,11,1,0 +BRDA:112,12,0,0 +BRDA:113,13,0,0 +BRDA:113,13,1,0 +BRDA:115,14,0,0 +BRDA:123,15,0,0 +BRDA:123,15,1,0 +BRDA:129,16,0,0 +BRDA:129,17,0,0 +BRDA:129,17,1,0 +BRDA:130,18,0,0 +BRDA:130,18,1,0 +BRDA:135,19,0,0 +BRDA:137,20,0,0 +BRDA:137,20,1,0 +BRDA:146,21,0,0 +BRDA:147,22,0,0 +BRDA:147,22,1,0 +BRDA:147,22,2,0 +BRDA:154,23,0,0 +BRDA:154,23,1,0 +BRDA:156,24,0,0 +BRDA:161,25,0,0 +BRDA:161,25,1,0 +BRDA:161,26,0,0 +BRDA:161,26,1,0 +BRDA:175,27,0,0 +BRDA:175,27,1,0 +BRDA:182,28,0,0 +BRDA:187,29,0,0 +BRF:53 +BRH:0 +end_of_record +TN: +SF:lib/dependencies/setupDependencyConfig.ts +FN:6,setupDependencyConfig +FNF:1 +FNH:1 +FNDA:1,setupDependencyConfig +DA:6,5 +DA:21,1 +LF:2 +LH:2 +BRF:0 +BRH:0 +end_of_record +TN: +SF:lib/exver/exver.ts +FN:9,(anonymous_0) +FN:14,peg$subclass +FN:16,C +FN:24,peg$SyntaxError +FN:49,peg$padEnd +FN:63,(anonymous_5) +FN:125,(anonymous_6) +FN:129,(anonymous_7) +FN:135,(anonymous_8) +FN:137,(anonymous_9) +FN:151,(anonymous_10) +FN:157,(anonymous_11) +FN:163,(anonymous_12) +FN:170,hex +FN:176,literalEscape +FN:192,(anonymous_15) +FN:194,(anonymous_16) +FN:198,classEscape +FN:218,(anonymous_18) +FN:220,(anonymous_19) +FN:224,describeExpectation +FN:230,describeExpected +FN:279,describeFound +FN:289,peg$parse +FN:353,(anonymous_24) +FN:356,(anonymous_25) +FN:359,(anonymous_26) +FN:362,(anonymous_27) +FN:365,(anonymous_28) +FN:368,(anonymous_29) +FN:371,(anonymous_30) +FN:374,(anonymous_31) +FN:377,(anonymous_32) +FN:380,(anonymous_33) +FN:383,(anonymous_34) +FN:386,(anonymous_35) +FN:389,(anonymous_36) +FN:392,(anonymous_37) +FN:395,(anonymous_38) +FN:400,(anonymous_39) +FN:422,(anonymous_40) +FN:425,(anonymous_41) +FN:428,(anonymous_42) +FN:431,(anonymous_43) +FN:441,(anonymous_44) +FN:443,(anonymous_45) +FN:446,(anonymous_46) +FN:451,(anonymous_47) +FN:453,(anonymous_48) +FN:456,(anonymous_49) +FN:487,text +FN:493,offset +FN:499,range +FN:512,location +FN:518,expected +FN:538,error +FN:551,peg$literalExpectation +FN:557,peg$classExpectation +FN:563,peg$anyExpectation +FN:569,peg$endExpectation +FN:575,peg$otherExpectation +FN:581,peg$computePosDetails +FN:638,peg$computeLocation +FN:679,peg$fail +FN:696,peg$buildSimpleError +FN:702,peg$buildStructuredError +FN:718,peg$parseVersionRange +FN:849,peg$parseOr +FN:873,peg$parseAnd +FN:897,peg$parseVersionRangeAtom +FN:930,peg$parseParens +FN:1006,peg$parseAnchor +FN:1043,peg$parseVersionSpec +FN:1122,peg$parseNot +FN:1174,peg$parseAny +FN:1209,peg$parseNone +FN:1244,peg$parseCmpOp +FN:1468,peg$parseExtendedVersion +FN:1536,peg$parseEmVer +FN:1674,peg$parseFlavor +FN:1746,peg$parseLowercase +FN:1808,peg$parseString +FN:1870,peg$parseVersion +FN:1905,peg$parsePreRelease +FN:2040,peg$parsePreReleaseSegment +FN:2091,peg$parseVersionNumber +FN:2204,peg$parseDigit +FN:2266,peg$parse_ +FNF:88 +FNH:61 +FNDA:6,(anonymous_0) +FNDA:6,peg$subclass +FNDA:6,C +FNDA:3,peg$SyntaxError +FNDA:0,peg$padEnd +FNDA:0,(anonymous_5) +FNDA:3,(anonymous_6) +FNDA:2,(anonymous_7) +FNDA:3,(anonymous_8) +FNDA:3,(anonymous_9) +FNDA:0,(anonymous_10) +FNDA:0,(anonymous_11) +FNDA:0,(anonymous_12) +FNDA:0,hex +FNDA:4,literalEscape +FNDA:0,(anonymous_15) +FNDA:0,(anonymous_16) +FNDA:6,classEscape +FNDA:0,(anonymous_18) +FNDA:0,(anonymous_19) +FNDA:5,describeExpectation +FNDA:3,describeExpected +FNDA:3,describeFound +FNDA:127,peg$parse +FNDA:0,(anonymous_24) +FNDA:24,(anonymous_25) +FNDA:24,(anonymous_26) +FNDA:2,(anonymous_27) +FNDA:1,(anonymous_28) +FNDA:0,(anonymous_29) +FNDA:1,(anonymous_30) +FNDA:2,(anonymous_31) +FNDA:7,(anonymous_32) +FNDA:4,(anonymous_33) +FNDA:7,(anonymous_34) +FNDA:0,(anonymous_35) +FNDA:0,(anonymous_36) +FNDA:3,(anonymous_37) +FNDA:106,(anonymous_38) +FNDA:0,(anonymous_39) +FNDA:0,(anonymous_40) +FNDA:0,(anonymous_41) +FNDA:1,(anonymous_42) +FNDA:242,(anonymous_43) +FNDA:1,(anonymous_44) +FNDA:1,(anonymous_45) +FNDA:2,(anonymous_46) +FNDA:242,(anonymous_47) +FNDA:150,(anonymous_48) +FNDA:393,(anonymous_49) +FNDA:394,text +FNDA:0,offset +FNDA:0,range +FNDA:0,location +FNDA:0,expected +FNDA:0,error +FNDA:2286,peg$literalExpectation +FNDA:508,peg$classExpectation +FNDA:0,peg$anyExpectation +FNDA:0,peg$endExpectation +FNDA:127,peg$otherExpectation +FNDA:6,peg$computePosDetails +FNDA:3,peg$computeLocation +FNDA:1542,peg$fail +FNDA:0,peg$buildSimpleError +FNDA:3,peg$buildStructuredError +FNDA:18,peg$parseVersionRange +FNDA:25,peg$parseOr +FNDA:22,peg$parseAnd +FNDA:45,peg$parseVersionRangeAtom +FNDA:45,peg$parseParens +FNDA:45,peg$parseAnchor +FNDA:45,peg$parseVersionSpec +FNDA:21,peg$parseNot +FNDA:19,peg$parseAny +FNDA:18,peg$parseNone +FNDA:45,peg$parseCmpOp +FNDA:109,peg$parseExtendedVersion +FNDA:0,peg$parseEmVer +FNDA:154,peg$parseFlavor +FNDA:0,peg$parseLowercase +FNDA:1,peg$parseString +FNDA:265,peg$parseVersion +FNDA:242,peg$parsePreRelease +FNDA:2,peg$parsePreReleaseSegment +FNDA:265,peg$parseVersionNumber +FNDA:418,peg$parseDigit +FNDA:79,peg$parse_ +DA:9,6 +DA:16,6 +DA:18,6 +DA:20,6 +DA:26,3 +DA:34,3 +DA:36,3 +DA:38,3 +DA:40,3 +DA:42,3 +DA:46,6 +DA:51,0 +DA:53,0 +DA:55,0 +DA:57,0 +DA:59,0 +DA:63,6 +DA:65,0 +DA:67,0 +DA:69,0 +DA:73,0 +DA:75,0 +DA:77,0 +DA:79,0 +DA:83,0 +DA:85,0 +DA:91,0 +DA:93,0 +DA:95,0 +DA:97,0 +DA:99,0 +DA:101,0 +DA:103,0 +DA:105,0 +DA:117,0 +DA:121,0 +DA:125,6 +DA:127,3 +DA:131,2 +DA:137,3 +DA:139,3 +DA:147,3 +DA:153,0 +DA:159,0 +DA:165,0 +DA:172,0 +DA:178,4 +DA:192,0 +DA:194,0 +DA:200,6 +DA:218,0 +DA:220,0 +DA:226,5 +DA:232,3 +DA:237,3 +DA:240,3 +DA:242,3 +DA:244,2 +DA:246,2 +DA:248,2 +DA:252,3 +DA:256,3 +DA:260,1 +DA:265,2 +DA:270,0 +DA:281,3 +DA:285,3 +DA:291,127 +DA:294,127 +DA:296,127 +DA:299,127 +DA:301,127 +DA:304,127 +DA:305,127 +DA:306,127 +DA:307,127 +DA:308,127 +DA:309,127 +DA:310,127 +DA:311,127 +DA:312,127 +DA:313,127 +DA:314,127 +DA:315,127 +DA:316,127 +DA:317,127 +DA:318,127 +DA:319,127 +DA:320,127 +DA:321,127 +DA:323,127 +DA:324,127 +DA:325,127 +DA:326,127 +DA:328,127 +DA:329,127 +DA:330,127 +DA:331,127 +DA:332,127 +DA:333,127 +DA:334,127 +DA:335,127 +DA:336,127 +DA:337,127 +DA:338,127 +DA:339,127 +DA:340,127 +DA:341,127 +DA:342,127 +DA:343,127 +DA:344,127 +DA:345,127 +DA:346,127 +DA:347,127 +DA:348,127 +DA:349,127 +DA:350,127 +DA:353,127 +DA:354,0 +DA:356,127 +DA:357,24 +DA:359,127 +DA:360,24 +DA:362,127 +DA:363,2 +DA:365,127 +DA:366,1 +DA:368,127 +DA:369,0 +DA:371,127 +DA:372,1 +DA:374,127 +DA:375,2 +DA:377,127 +DA:378,7 +DA:380,127 +DA:381,4 +DA:383,127 +DA:384,7 +DA:386,127 +DA:387,0 +DA:389,127 +DA:390,0 +DA:392,127 +DA:393,3 +DA:395,127 +DA:397,106 +DA:400,127 +DA:402,0 +DA:422,127 +DA:423,0 +DA:425,127 +DA:426,0 +DA:428,127 +DA:429,1 +DA:431,127 +DA:433,242 +DA:441,127 +DA:443,1 +DA:446,127 +DA:448,2 +DA:451,127 +DA:453,242 +DA:456,127 +DA:457,393 +DA:459,127 +DA:461,127 +DA:463,127 +DA:465,127 +DA:467,127 +DA:469,127 +DA:475,127 +DA:477,127 +DA:479,0 +DA:483,127 +DA:489,394 +DA:495,0 +DA:501,0 +DA:514,0 +DA:520,0 +DA:527,0 +DA:540,0 +DA:547,0 +DA:553,2286 +DA:559,508 +DA:565,0 +DA:571,0 +DA:577,127 +DA:583,6 +DA:588,6 +DA:590,3 +DA:594,3 +DA:596,3 +DA:598,1 +DA:602,3 +DA:604,3 +DA:612,3 +DA:614,4 +DA:616,0 +DA:618,0 +DA:622,4 +DA:626,4 +DA:630,3 +DA:633,3 +DA:640,3 +DA:642,3 +DA:645,3 +DA:668,3 +DA:670,0 +DA:672,0 +DA:675,3 +DA:681,1542 +DA:684,1540 +DA:686,438 +DA:688,438 +DA:692,1540 +DA:698,0 +DA:704,3 +DA:723,18 +DA:725,18 +DA:727,18 +DA:729,18 +DA:731,18 +DA:733,18 +DA:735,18 +DA:737,18 +DA:739,18 +DA:741,17 +DA:744,18 +DA:746,4 +DA:748,4 +DA:750,4 +DA:754,14 +DA:756,14 +DA:759,18 +DA:761,14 +DA:764,18 +DA:766,18 +DA:768,4 +DA:770,4 +DA:774,14 +DA:776,14 +DA:779,18 +DA:781,7 +DA:783,7 +DA:785,7 +DA:787,7 +DA:789,7 +DA:791,7 +DA:793,5 +DA:796,7 +DA:798,3 +DA:800,3 +DA:802,3 +DA:806,4 +DA:808,4 +DA:811,7 +DA:813,4 +DA:816,7 +DA:818,7 +DA:820,3 +DA:822,3 +DA:826,4 +DA:828,4 +DA:832,18 +DA:834,18 +DA:838,0 +DA:840,0 +DA:844,18 +DA:854,25 +DA:856,3 +DA:858,3 +DA:862,22 +DA:864,22 +DA:868,25 +DA:878,22 +DA:880,4 +DA:882,4 +DA:886,18 +DA:888,18 +DA:892,22 +DA:902,45 +DA:904,45 +DA:906,45 +DA:908,45 +DA:910,21 +DA:912,21 +DA:914,19 +DA:916,19 +DA:918,18 +DA:925,45 +DA:935,45 +DA:937,45 +DA:939,0 +DA:941,0 +DA:945,45 +DA:947,45 +DA:950,45 +DA:952,0 +DA:954,0 +DA:956,0 +DA:958,0 +DA:960,0 +DA:962,0 +DA:964,0 +DA:968,0 +DA:970,0 +DA:973,0 +DA:975,0 +DA:977,0 +DA:981,0 +DA:983,0 +DA:988,0 +DA:990,0 +DA:995,45 +DA:997,45 +DA:1001,45 +DA:1011,45 +DA:1013,45 +DA:1015,45 +DA:1017,21 +DA:1020,45 +DA:1022,45 +DA:1024,45 +DA:1026,24 +DA:1028,24 +DA:1032,21 +DA:1034,21 +DA:1038,45 +DA:1048,45 +DA:1050,45 +DA:1052,45 +DA:1054,45 +DA:1057,45 +DA:1059,45 +DA:1061,24 +DA:1063,24 +DA:1065,5 +DA:1067,5 +DA:1071,19 +DA:1073,19 +DA:1076,24 +DA:1078,5 +DA:1080,5 +DA:1082,5 +DA:1084,5 +DA:1088,0 +DA:1090,0 +DA:1095,19 +DA:1097,19 +DA:1100,24 +DA:1102,19 +DA:1105,24 +DA:1107,24 +DA:1111,21 +DA:1113,21 +DA:1117,45 +DA:1127,21 +DA:1129,21 +DA:1131,2 +DA:1133,2 +DA:1137,19 +DA:1139,19 +DA:1142,21 +DA:1144,2 +DA:1146,2 +DA:1148,2 +DA:1150,2 +DA:1152,2 +DA:1156,0 +DA:1158,0 +DA:1163,19 +DA:1165,19 +DA:1169,21 +DA:1179,19 +DA:1181,19 +DA:1183,1 +DA:1185,1 +DA:1189,18 +DA:1191,18 +DA:1194,19 +DA:1196,1 +DA:1198,1 +DA:1201,19 +DA:1204,19 +DA:1214,18 +DA:1216,18 +DA:1218,0 +DA:1220,0 +DA:1224,18 +DA:1226,18 +DA:1229,18 +DA:1231,0 +DA:1233,0 +DA:1236,18 +DA:1239,18 +DA:1249,45 +DA:1251,45 +DA:1253,1 +DA:1255,1 +DA:1259,44 +DA:1261,44 +DA:1264,45 +DA:1266,1 +DA:1268,1 +DA:1271,45 +DA:1273,45 +DA:1275,44 +DA:1277,44 +DA:1279,2 +DA:1281,2 +DA:1285,42 +DA:1287,42 +DA:1290,44 +DA:1292,2 +DA:1294,2 +DA:1297,44 +DA:1299,44 +DA:1301,42 +DA:1303,42 +DA:1305,7 +DA:1307,7 +DA:1311,35 +DA:1313,35 +DA:1316,42 +DA:1318,7 +DA:1320,7 +DA:1323,42 +DA:1325,42 +DA:1327,35 +DA:1329,35 +DA:1331,4 +DA:1333,4 +DA:1337,31 +DA:1339,31 +DA:1342,35 +DA:1344,4 +DA:1346,4 +DA:1349,35 +DA:1351,35 +DA:1353,31 +DA:1355,31 +DA:1357,7 +DA:1359,7 +DA:1363,24 +DA:1365,24 +DA:1368,31 +DA:1370,7 +DA:1372,7 +DA:1375,31 +DA:1377,31 +DA:1379,24 +DA:1381,24 +DA:1383,0 +DA:1385,0 +DA:1389,24 +DA:1391,24 +DA:1394,24 +DA:1396,0 +DA:1398,0 +DA:1401,24 +DA:1403,24 +DA:1405,24 +DA:1407,24 +DA:1409,0 +DA:1411,0 +DA:1415,24 +DA:1417,24 +DA:1420,24 +DA:1422,0 +DA:1424,0 +DA:1427,24 +DA:1429,24 +DA:1431,24 +DA:1433,24 +DA:1435,3 +DA:1437,3 +DA:1441,21 +DA:1443,21 +DA:1446,24 +DA:1448,3 +DA:1450,3 +DA:1453,24 +DA:1463,45 +DA:1473,109 +DA:1475,109 +DA:1477,109 +DA:1479,109 +DA:1482,109 +DA:1484,109 +DA:1486,107 +DA:1488,106 +DA:1490,106 +DA:1494,1 +DA:1496,1 +DA:1499,107 +DA:1501,106 +DA:1503,106 +DA:1505,106 +DA:1507,106 +DA:1511,0 +DA:1513,0 +DA:1518,1 +DA:1520,1 +DA:1525,2 +DA:1527,2 +DA:1531,109 +DA:1541,0 +DA:1543,0 +DA:1545,0 +DA:1547,0 +DA:1549,0 +DA:1551,0 +DA:1555,0 +DA:1557,0 +DA:1560,0 +DA:1562,0 +DA:1564,0 +DA:1566,0 +DA:1568,0 +DA:1570,0 +DA:1574,0 +DA:1576,0 +DA:1579,0 +DA:1581,0 +DA:1583,0 +DA:1585,0 +DA:1587,0 +DA:1589,0 +DA:1591,0 +DA:1595,0 +DA:1597,0 +DA:1600,0 +DA:1602,0 +DA:1604,0 +DA:1606,0 +DA:1608,0 +DA:1612,0 +DA:1614,0 +DA:1619,0 +DA:1621,0 +DA:1624,0 +DA:1626,0 +DA:1629,0 +DA:1631,0 +DA:1635,0 +DA:1637,0 +DA:1642,0 +DA:1644,0 +DA:1649,0 +DA:1651,0 +DA:1656,0 +DA:1658,0 +DA:1663,0 +DA:1665,0 +DA:1669,0 +DA:1679,154 +DA:1681,154 +DA:1683,0 +DA:1685,0 +DA:1689,154 +DA:1691,154 +DA:1694,154 +DA:1696,0 +DA:1698,0 +DA:1700,0 +DA:1702,0 +DA:1704,0 +DA:1708,0 +DA:1710,0 +DA:1713,0 +DA:1715,0 +DA:1717,0 +DA:1721,0 +DA:1723,0 +DA:1728,0 +DA:1730,0 +DA:1735,154 +DA:1737,154 +DA:1741,154 +DA:1751,0 +DA:1753,0 +DA:1755,0 +DA:1757,0 +DA:1759,0 +DA:1763,0 +DA:1765,0 +DA:1768,0 +DA:1770,0 +DA:1772,0 +DA:1774,0 +DA:1776,0 +DA:1778,0 +DA:1782,0 +DA:1784,0 +DA:1790,0 +DA:1793,0 +DA:1795,0 +DA:1797,0 +DA:1800,0 +DA:1803,0 +DA:1813,1 +DA:1815,1 +DA:1817,1 +DA:1819,1 +DA:1821,1 +DA:1825,0 +DA:1827,0 +DA:1830,1 +DA:1832,1 +DA:1834,4 +DA:1836,4 +DA:1838,3 +DA:1840,3 +DA:1844,1 +DA:1846,1 +DA:1852,0 +DA:1855,1 +DA:1857,1 +DA:1859,1 +DA:1862,1 +DA:1865,1 +DA:1875,265 +DA:1877,265 +DA:1879,265 +DA:1881,242 +DA:1883,242 +DA:1885,241 +DA:1888,242 +DA:1890,242 +DA:1894,23 +DA:1896,23 +DA:1900,265 +DA:1910,242 +DA:1912,242 +DA:1914,1 +DA:1916,1 +DA:1920,241 +DA:1922,241 +DA:1925,242 +DA:1927,1 +DA:1929,1 +DA:1931,1 +DA:1933,1 +DA:1935,1 +DA:1937,1 +DA:1939,1 +DA:1943,0 +DA:1945,0 +DA:1948,1 +DA:1950,1 +DA:1952,1 +DA:1954,1 +DA:1956,1 +DA:1960,0 +DA:1962,0 +DA:1967,0 +DA:1969,0 +DA:1972,1 +DA:1974,1 +DA:1976,1 +DA:1978,1 +DA:1980,0 +DA:1982,0 +DA:1986,1 +DA:1988,1 +DA:1991,1 +DA:1993,0 +DA:1995,0 +DA:1997,0 +DA:1999,0 +DA:2003,0 +DA:2005,0 +DA:2010,1 +DA:2012,1 +DA:2016,1 +DA:2018,1 +DA:2022,0 +DA:2024,0 +DA:2029,241 +DA:2031,241 +DA:2035,242 +DA:2045,2 +DA:2047,2 +DA:2049,0 +DA:2051,0 +DA:2055,2 +DA:2057,2 +DA:2060,2 +DA:2062,2 +DA:2065,2 +DA:2067,2 +DA:2069,1 +DA:2072,2 +DA:2074,2 +DA:2076,2 +DA:2080,0 +DA:2082,0 +DA:2086,2 +DA:2096,265 +DA:2098,265 +DA:2100,265 +DA:2102,242 +DA:2104,242 +DA:2106,242 +DA:2108,93 +DA:2110,93 +DA:2114,149 +DA:2116,149 +DA:2119,242 +DA:2121,93 +DA:2123,93 +DA:2125,92 +DA:2127,92 +DA:2131,1 +DA:2133,1 +DA:2138,149 +DA:2140,149 +DA:2143,242 +DA:2145,150 +DA:2147,150 +DA:2149,150 +DA:2151,58 +DA:2153,58 +DA:2157,92 +DA:2159,92 +DA:2162,150 +DA:2164,58 +DA:2166,58 +DA:2168,58 +DA:2170,58 +DA:2174,0 +DA:2176,0 +DA:2181,92 +DA:2183,92 +DA:2187,242 +DA:2189,242 +DA:2193,23 +DA:2195,23 +DA:2199,265 +DA:2209,418 +DA:2211,418 +DA:2213,418 +DA:2215,393 +DA:2217,393 +DA:2221,25 +DA:2223,25 +DA:2226,418 +DA:2228,393 +DA:2230,395 +DA:2232,395 +DA:2234,2 +DA:2236,2 +DA:2240,393 +DA:2242,393 +DA:2248,25 +DA:2251,418 +DA:2253,393 +DA:2255,393 +DA:2258,418 +DA:2261,418 +DA:2271,79 +DA:2273,79 +DA:2275,79 +DA:2277,14 +DA:2279,14 +DA:2283,65 +DA:2285,65 +DA:2288,79 +DA:2290,14 +DA:2292,14 +DA:2294,0 +DA:2296,0 +DA:2300,14 +DA:2302,14 +DA:2306,79 +DA:2308,79 +DA:2310,79 +DA:2313,79 +DA:2317,127 +DA:2320,127 +DA:2322,124 +DA:2326,3 +DA:2328,0 +DA:2332,3 +DA:2348,6 +DA:2422,6 +DA:2457,6 +DA:2459,6 +LF:789 +LH:582 +BRDA:51,0,0,0 +BRDA:51,0,1,0 +BRDA:53,1,0,0 +BRDA:67,2,0,0 +BRDA:75,3,0,0 +BRDA:85,4,0,0 +BRDA:85,4,1,0 +BRDA:85,5,0,0 +BRDA:85,5,1,0 +BRDA:93,6,0,0 +BRDA:93,6,1,0 +BRDA:101,7,0,0 +BRDA:101,7,1,0 +BRDA:103,8,0,0 +BRDA:103,8,1,0 +BRDA:139,9,0,3 +BRDA:139,9,1,0 +BRDA:147,10,0,0 +BRDA:147,10,1,3 +BRDA:240,11,0,3 +BRDA:244,12,0,2 +BRDA:256,13,0,1 +BRDA:256,13,1,2 +BRDA:256,13,2,0 +BRDA:281,14,0,2 +BRDA:281,14,1,1 +BRDA:291,15,0,127 +BRDA:291,15,1,0 +BRDA:360,16,0,24 +BRDA:360,16,1,24 +BRDA:360,17,0,5 +BRDA:360,17,1,19 +BRDA:397,18,0,106 +BRDA:397,18,1,106 +BRDA:415,19,0,0 +BRDA:415,19,1,0 +BRDA:437,20,0,242 +BRDA:437,20,1,241 +BRDA:475,21,0,127 +BRDA:477,22,0,0 +BRDA:520,23,0,0 +BRDA:520,23,1,0 +BRDA:540,24,0,0 +BRDA:540,24,1,0 +BRDA:588,25,0,3 +BRDA:588,25,1,3 +BRDA:614,26,0,0 +BRDA:614,26,1,4 +BRDA:668,27,0,0 +BRDA:668,28,0,3 +BRDA:668,28,1,0 +BRDA:668,28,2,0 +BRDA:681,29,0,2 +BRDA:684,30,0,438 +BRDA:727,31,0,18 +BRDA:727,31,1,0 +BRDA:739,32,0,17 +BRDA:744,33,0,4 +BRDA:744,33,1,14 +BRDA:759,34,0,14 +BRDA:766,35,0,4 +BRDA:766,35,1,14 +BRDA:791,36,0,5 +BRDA:796,37,0,3 +BRDA:796,37,1,4 +BRDA:811,38,0,4 +BRDA:818,39,0,3 +BRDA:818,39,1,4 +BRDA:854,40,0,3 +BRDA:854,40,1,22 +BRDA:864,41,0,22 +BRDA:878,42,0,4 +BRDA:878,42,1,18 +BRDA:888,43,0,18 +BRDA:904,44,0,45 +BRDA:908,45,0,21 +BRDA:912,46,0,19 +BRDA:916,47,0,18 +BRDA:937,48,0,0 +BRDA:937,48,1,45 +BRDA:947,49,0,45 +BRDA:950,50,0,0 +BRDA:950,50,1,45 +BRDA:956,51,0,0 +BRDA:956,51,1,0 +BRDA:960,52,0,0 +BRDA:960,52,1,0 +BRDA:970,53,0,0 +BRDA:973,54,0,0 +BRDA:973,54,1,0 +BRDA:1015,55,0,21 +BRDA:1024,56,0,24 +BRDA:1024,56,1,21 +BRDA:1052,57,0,45 +BRDA:1059,58,0,24 +BRDA:1059,58,1,21 +BRDA:1063,59,0,5 +BRDA:1063,59,1,19 +BRDA:1073,60,0,19 +BRDA:1076,61,0,5 +BRDA:1076,61,1,19 +BRDA:1080,62,0,5 +BRDA:1080,62,1,0 +BRDA:1100,63,0,19 +BRDA:1129,64,0,2 +BRDA:1129,64,1,19 +BRDA:1139,65,0,19 +BRDA:1142,66,0,2 +BRDA:1142,66,1,19 +BRDA:1148,67,0,2 +BRDA:1148,67,1,0 +BRDA:1181,68,0,1 +BRDA:1181,68,1,18 +BRDA:1191,69,0,18 +BRDA:1194,70,0,1 +BRDA:1216,71,0,0 +BRDA:1216,71,1,18 +BRDA:1226,72,0,18 +BRDA:1229,73,0,0 +BRDA:1251,74,0,1 +BRDA:1251,74,1,44 +BRDA:1261,75,0,44 +BRDA:1264,76,0,1 +BRDA:1273,77,0,44 +BRDA:1277,78,0,2 +BRDA:1277,78,1,42 +BRDA:1287,79,0,42 +BRDA:1290,80,0,2 +BRDA:1299,81,0,42 +BRDA:1303,82,0,7 +BRDA:1303,82,1,35 +BRDA:1313,83,0,35 +BRDA:1316,84,0,7 +BRDA:1325,85,0,35 +BRDA:1329,86,0,4 +BRDA:1329,86,1,31 +BRDA:1339,87,0,31 +BRDA:1342,88,0,4 +BRDA:1351,89,0,31 +BRDA:1355,90,0,7 +BRDA:1355,90,1,24 +BRDA:1365,91,0,24 +BRDA:1368,92,0,7 +BRDA:1377,93,0,24 +BRDA:1381,94,0,0 +BRDA:1381,94,1,24 +BRDA:1391,95,0,24 +BRDA:1394,96,0,0 +BRDA:1403,97,0,24 +BRDA:1407,98,0,0 +BRDA:1407,98,1,24 +BRDA:1417,99,0,24 +BRDA:1420,100,0,0 +BRDA:1429,101,0,24 +BRDA:1433,102,0,3 +BRDA:1433,102,1,21 +BRDA:1443,103,0,21 +BRDA:1446,104,0,3 +BRDA:1477,105,0,109 +BRDA:1484,106,0,107 +BRDA:1484,106,1,2 +BRDA:1486,107,0,106 +BRDA:1486,107,1,1 +BRDA:1496,108,0,1 +BRDA:1499,109,0,106 +BRDA:1499,109,1,1 +BRDA:1503,110,0,106 +BRDA:1503,110,1,0 +BRDA:1545,111,0,0 +BRDA:1545,111,1,0 +BRDA:1547,112,0,0 +BRDA:1547,112,1,0 +BRDA:1557,113,0,0 +BRDA:1560,114,0,0 +BRDA:1560,114,1,0 +BRDA:1564,115,0,0 +BRDA:1564,115,1,0 +BRDA:1566,116,0,0 +BRDA:1566,116,1,0 +BRDA:1576,117,0,0 +BRDA:1579,118,0,0 +BRDA:1579,118,1,0 +BRDA:1583,119,0,0 +BRDA:1583,119,1,0 +BRDA:1587,120,0,0 +BRDA:1587,120,1,0 +BRDA:1597,121,0,0 +BRDA:1600,122,0,0 +BRDA:1600,122,1,0 +BRDA:1604,123,0,0 +BRDA:1604,123,1,0 +BRDA:1624,124,0,0 +BRDA:1681,125,0,0 +BRDA:1681,125,1,154 +BRDA:1691,126,0,154 +BRDA:1694,127,0,0 +BRDA:1694,127,1,154 +BRDA:1698,128,0,0 +BRDA:1698,128,1,0 +BRDA:1700,129,0,0 +BRDA:1700,129,1,0 +BRDA:1710,130,0,0 +BRDA:1713,131,0,0 +BRDA:1713,131,1,0 +BRDA:1755,132,0,0 +BRDA:1755,132,1,0 +BRDA:1765,133,0,0 +BRDA:1768,134,0,0 +BRDA:1768,134,1,0 +BRDA:1774,135,0,0 +BRDA:1774,135,1,0 +BRDA:1784,136,0,0 +BRDA:1793,137,0,0 +BRDA:1817,138,0,1 +BRDA:1817,138,1,0 +BRDA:1827,139,0,0 +BRDA:1830,140,0,1 +BRDA:1830,140,1,0 +BRDA:1836,141,0,3 +BRDA:1836,141,1,1 +BRDA:1846,142,0,1 +BRDA:1855,143,0,1 +BRDA:1879,144,0,242 +BRDA:1879,144,1,23 +BRDA:1883,145,0,241 +BRDA:1912,146,0,1 +BRDA:1912,146,1,241 +BRDA:1922,147,0,241 +BRDA:1925,148,0,1 +BRDA:1925,148,1,241 +BRDA:1929,149,0,1 +BRDA:1929,149,1,0 +BRDA:1935,150,0,1 +BRDA:1935,150,1,0 +BRDA:1945,151,0,0 +BRDA:1948,152,0,1 +BRDA:1948,152,1,0 +BRDA:1952,153,0,1 +BRDA:1952,153,1,0 +BRDA:1978,154,0,0 +BRDA:1978,154,1,1 +BRDA:1988,155,0,1 +BRDA:1991,156,0,0 +BRDA:1991,156,1,1 +BRDA:1995,157,0,0 +BRDA:1995,157,1,0 +BRDA:2047,158,0,0 +BRDA:2047,158,1,2 +BRDA:2057,159,0,2 +BRDA:2060,160,0,2 +BRDA:2067,161,0,1 +BRDA:2072,162,0,2 +BRDA:2072,162,1,0 +BRDA:2100,163,0,242 +BRDA:2100,163,1,23 +BRDA:2106,164,0,93 +BRDA:2106,164,1,149 +BRDA:2116,165,0,149 +BRDA:2119,166,0,93 +BRDA:2119,166,1,149 +BRDA:2123,167,0,92 +BRDA:2123,167,1,1 +BRDA:2149,168,0,58 +BRDA:2149,168,1,92 +BRDA:2159,169,0,92 +BRDA:2162,170,0,58 +BRDA:2162,170,1,92 +BRDA:2166,171,0,58 +BRDA:2166,171,1,0 +BRDA:2213,172,0,393 +BRDA:2213,172,1,25 +BRDA:2223,173,0,25 +BRDA:2226,174,0,393 +BRDA:2226,174,1,25 +BRDA:2232,175,0,2 +BRDA:2232,175,1,393 +BRDA:2242,176,0,393 +BRDA:2251,177,0,393 +BRDA:2275,178,0,14 +BRDA:2275,178,1,65 +BRDA:2285,179,0,0 +BRDA:2292,180,0,0 +BRDA:2292,180,1,14 +BRDA:2302,181,0,0 +BRDA:2310,182,0,79 +BRDA:2320,183,0,124 +BRDA:2320,183,1,3 +BRDA:2320,184,0,127 +BRDA:2320,184,1,124 +BRDA:2326,185,0,0 +BRDA:2326,186,0,3 +BRDA:2326,186,1,0 +BRDA:2336,187,0,2 +BRDA:2336,187,1,1 +BRDA:2338,188,0,2 +BRDA:2338,188,1,1 +BRF:296 +BRH:185 +end_of_record +TN: +SF:lib/exver/index.ts +FN:47,(anonymous_6) +FN:49,(anonymous_7) +FN:66,(anonymous_8) +FN:96,(anonymous_9) +FN:120,(anonymous_10) +FN:126,(anonymous_11) +FN:130,(anonymous_12) +FN:134,(anonymous_13) +FN:138,(anonymous_14) +FN:142,(anonymous_15) +FN:146,(anonymous_16) +FN:150,(anonymous_17) +FN:156,(anonymous_18) +FN:161,(anonymous_19) +FN:165,(anonymous_20) +FN:208,(anonymous_21) +FN:213,(anonymous_22) +FN:222,(anonymous_23) +FN:228,(anonymous_24) +FN:232,(anonymous_25) +FN:243,(anonymous_26) +FN:253,(anonymous_27) +FN:264,(anonymous_28) +FN:268,(anonymous_29) +FN:272,(anonymous_30) +FN:276,(anonymous_31) +FN:280,(anonymous_32) +FN:284,(anonymous_33) +FN:293,(anonymous_34) +FN:307,(anonymous_35) +FN:308,(anonymous_36) +FN:310,(anonymous_37) +FN:334,(anonymous_38) +FN:335,(anonymous_39) +FN:338,(anonymous_40) +FN:361,(anonymous_41) +FN:419,(anonymous_42) +FN:421,(anonymous_43) +FN:423,tests +FNF:39 +FNH:30 +FNDA:87,(anonymous_6) +FNDA:50,(anonymous_7) +FNDA:27,(anonymous_8) +FNDA:18,(anonymous_9) +FNDA:18,(anonymous_10) +FNDA:1,(anonymous_11) +FNDA:21,(anonymous_12) +FNDA:1,(anonymous_13) +FNDA:20,(anonymous_14) +FNDA:0,(anonymous_15) +FNDA:10,(anonymous_16) +FNDA:112,(anonymous_17) +FNDA:308,(anonymous_18) +FNDA:40,(anonymous_19) +FNDA:235,(anonymous_20) +FNDA:0,(anonymous_21) +FNDA:0,(anonymous_22) +FNDA:154,(anonymous_23) +FNDA:20,(anonymous_24) +FNDA:160,(anonymous_25) +FNDA:3,(anonymous_26) +FNDA:3,(anonymous_27) +FNDA:30,(anonymous_28) +FNDA:30,(anonymous_29) +FNDA:31,(anonymous_30) +FNDA:54,(anonymous_31) +FNDA:9,(anonymous_32) +FNDA:109,(anonymous_33) +FNDA:0,(anonymous_34) +FNDA:0,(anonymous_35) +FNDA:0,(anonymous_36) +FNDA:0,(anonymous_37) +FNDA:24,(anonymous_38) +FNDA:24,(anonymous_39) +FNDA:48,(anonymous_40) +FNDA:198,(anonymous_41) +FNDA:0,(anonymous_42) +FNDA:5,(anonymous_43) +FNDA:0,tests +DA:1,6 +DA:46,6 +DA:47,87 +DA:50,50 +DA:52,20 +DA:54,0 +DA:56,20 +DA:58,0 +DA:60,0 +DA:62,10 +DA:67,27 +DA:69,2 +DA:74,0 +DA:76,24 +DA:92,1 +DA:97,18 +DA:98,18 +DA:99,7 +DA:101,3 +DA:106,3 +DA:109,4 +DA:114,4 +DA:117,18 +DA:121,18 +DA:127,1 +DA:131,21 +DA:135,1 +DA:139,20 +DA:143,0 +DA:147,10 +DA:151,112 +DA:155,6 +DA:157,308 +DA:158,308 +DA:162,40 +DA:166,235 +DA:167,235 +DA:168,419 +DA:169,63 +DA:170,356 +DA:171,38 +DA:175,134 +DA:176,0 +DA:177,134 +DA:178,0 +DA:181,134 +DA:182,134 +DA:183,252 +DA:184,252 +DA:185,0 +DA:186,252 +DA:187,0 +DA:190,0 +DA:192,0 +DA:194,0 +DA:197,0 +DA:200,0 +DA:205,134 +DA:209,0 +DA:210,0 +DA:214,0 +DA:221,6 +DA:223,154 +DA:224,154 +DA:225,154 +DA:229,20 +DA:233,160 +DA:234,0 +DA:236,160 +DA:237,160 +DA:238,85 +DA:240,75 +DA:244,3 +DA:245,0 +DA:246,3 +DA:247,0 +DA:249,3 +DA:254,3 +DA:256,1 +DA:258,1 +DA:260,1 +DA:265,30 +DA:269,30 +DA:273,31 +DA:277,54 +DA:281,9 +DA:285,109 +DA:286,106 +DA:294,0 +DA:295,0 +DA:308,0 +DA:310,0 +DA:311,0 +DA:312,0 +DA:313,0 +DA:314,0 +DA:316,0 +DA:319,0 +DA:320,0 +DA:322,0 +DA:335,24 +DA:336,24 +DA:338,24 +DA:339,48 +DA:340,0 +DA:341,48 +DA:342,24 +DA:344,24 +DA:347,24 +DA:348,24 +DA:350,24 +DA:362,198 +DA:364,129 +DA:365,129 +DA:367,21 +DA:369,30 +DA:371,39 +DA:373,6 +DA:375,9 +DA:377,0 +DA:379,0 +DA:380,0 +DA:384,0 +DA:386,0 +DA:389,24 +DA:390,24 +DA:394,6 +DA:396,18 +DA:400,21 +DA:405,17 +DA:410,22 +DA:412,9 +DA:414,0 +DA:419,6 +DA:421,6 +DA:422,5 +DA:424,0 +DA:425,0 +DA:426,0 +DA:427,0 +DA:428,0 +DA:429,0 +DA:431,0 +DA:433,0 +DA:435,0 +DA:437,0 +DA:438,0 +DA:439,0 +DA:440,0 +DA:441,0 +DA:442,0 +DA:443,0 +DA:445,0 +DA:447,0 +DA:449,0 +DA:451,0 +DA:453,0 +LF:157 +LH:97 +BRDA:50,0,0,20 +BRDA:50,0,1,0 +BRDA:50,0,2,20 +BRDA:50,0,3,0 +BRDA:50,0,4,0 +BRDA:50,0,5,10 +BRDA:67,1,0,2 +BRDA:67,1,1,0 +BRDA:67,1,2,24 +BRDA:67,1,3,1 +BRDA:78,2,0,24 +BRDA:78,2,1,0 +BRDA:99,3,0,3 +BRDA:99,3,1,4 +BRDA:99,3,2,4 +BRDA:162,4,0,0 +BRDA:162,4,1,40 +BRDA:168,5,0,63 +BRDA:168,5,1,356 +BRDA:168,6,0,419 +BRDA:168,6,1,131 +BRDA:168,7,0,419 +BRDA:168,7,1,135 +BRDA:170,8,0,38 +BRDA:170,9,0,356 +BRDA:170,9,1,131 +BRDA:170,10,0,356 +BRDA:170,10,1,114 +BRDA:175,11,0,0 +BRDA:175,11,1,134 +BRDA:175,12,0,134 +BRDA:175,12,1,134 +BRDA:177,13,0,0 +BRDA:177,14,0,134 +BRDA:177,14,1,0 +BRDA:183,15,0,252 +BRDA:183,15,1,0 +BRDA:184,16,0,0 +BRDA:184,16,1,252 +BRDA:186,17,0,0 +BRDA:190,18,0,0 +BRDA:190,18,1,0 +BRDA:190,18,2,0 +BRDA:190,18,3,0 +BRDA:190,18,4,0 +BRDA:190,18,5,0 +BRDA:229,19,0,0 +BRDA:229,19,1,20 +BRDA:233,20,0,0 +BRDA:237,21,0,85 +BRDA:244,22,0,0 +BRDA:244,22,1,3 +BRDA:244,23,0,3 +BRDA:244,23,1,3 +BRDA:244,24,0,3 +BRDA:244,24,1,3 +BRDA:246,25,0,0 +BRDA:246,25,1,3 +BRDA:246,26,0,3 +BRDA:246,26,1,3 +BRDA:246,27,0,3 +BRDA:246,27,1,3 +BRDA:254,28,0,1 +BRDA:254,28,1,1 +BRDA:254,28,2,1 +BRDA:311,29,0,0 +BRDA:311,29,1,0 +BRDA:313,30,0,0 +BRDA:336,31,0,0 +BRDA:336,31,1,24 +BRDA:339,32,0,0 +BRDA:339,32,1,48 +BRDA:341,33,0,24 +BRDA:362,34,0,129 +BRDA:362,34,1,21 +BRDA:362,34,2,17 +BRDA:362,34,3,22 +BRDA:362,34,4,9 +BRDA:362,34,5,0 +BRDA:365,35,0,21 +BRDA:365,35,1,30 +BRDA:365,35,2,39 +BRDA:365,35,3,6 +BRDA:365,35,4,9 +BRDA:365,35,5,0 +BRDA:365,35,6,0 +BRDA:365,35,7,24 +BRDA:380,36,0,0 +BRDA:380,36,1,0 +BRDA:381,37,0,0 +BRDA:381,37,1,0 +BRDA:390,38,0,6 +BRDA:390,38,1,18 +BRDA:391,39,0,24 +BRDA:391,39,1,15 +BRDA:401,40,0,21 +BRDA:401,40,1,13 +BRDA:406,41,0,17 +BRDA:406,41,1,13 +BRF:99 +BRH:65 +end_of_record +TN: +SF:lib/health/HealthCheck.ts +FN:21,healthCheck +FN:22,(anonymous_1) +FN:24,(anonymous_2) +FN:26,(anonymous_3) +FN:47,(anonymous_4) +FN:63,asMessage +FNF:6 +FNH:0 +FNDA:0,healthCheck +FNDA:0,(anonymous_1) +FNDA:0,(anonymous_2) +FNDA:0,(anonymous_3) +FNDA:0,(anonymous_4) +FNDA:0,asMessage +DA:6,5 +DA:7,5 +DA:9,5 +DA:11,5 +DA:21,5 +DA:22,0 +DA:23,0 +DA:24,0 +DA:25,0 +DA:26,0 +DA:27,0 +DA:33,0 +DA:34,0 +DA:38,0 +DA:39,0 +DA:40,0 +DA:46,0 +DA:47,0 +DA:48,0 +DA:51,0 +DA:57,0 +DA:61,0 +DA:64,0 +DA:65,0 +DA:66,0 +DA:67,0 +LF:26 +LH:5 +BRDA:25,0,0,0 +BRDA:25,0,1,0 +BRDA:28,1,0,0 +BRDA:28,1,1,0 +BRDA:28,2,0,0 +BRDA:28,2,1,0 +BRDA:44,3,0,0 +BRDA:44,3,1,0 +BRDA:55,4,0,0 +BRDA:55,4,1,0 +BRDA:64,5,0,0 +BRDA:66,6,0,0 +BRF:12 +BRH:0 +end_of_record +TN: +SF:lib/health/checkFns/checkPortListening.ts +FN:10,containsAddress +FN:15,(anonymous_7) +FN:17,(anonymous_8) +FN:26,checkPortListening +FN:37,(anonymous_10) +FN:55,(anonymous_11) +FN:57,(anonymous_12) +FNF:7 +FNH:3 +FNDA:2,containsAddress +FNDA:12,(anonymous_7) +FNDA:8,(anonymous_8) +FNDA:0,checkPortListening +FNDA:0,(anonymous_10) +FNDA:0,(anonymous_11) +FNDA:0,(anonymous_12) +DA:2,6 +DA:5,6 +DA:6,6 +DA:8,6 +DA:9,6 +DA:10,6 +DA:11,2 +DA:15,12 +DA:17,8 +DA:19,2 +DA:26,6 +DA:36,0 +DA:39,0 +DA:47,0 +DA:48,0 +DA:50,0 +DA:56,0 +DA:58,0 +LF:18 +LH:11 +BRDA:39,0,0,0 +BRDA:39,0,1,0 +BRDA:47,1,0,0 +BRDA:61,2,0,0 +BRDA:61,2,1,0 +BRDA:63,3,0,0 +BRDA:63,3,1,0 +BRF:7 +BRH:0 +end_of_record +TN: +SF:lib/health/checkFns/checkWebUrl.ts +FN:13,(anonymous_0) +FN:24,(anonymous_1) +FN:30,(anonymous_2) +FNF:3 +FNH:0 +FNDA:0,(anonymous_0) +FNDA:0,(anonymous_1) +FNDA:0,(anonymous_2) +DA:2,5 +DA:4,5 +DA:5,5 +DA:13,5 +DA:22,0 +DA:25,0 +DA:31,0 +DA:32,0 +DA:33,0 +DA:34,0 +LF:10 +LH:4 +BRDA:16,0,0,0 +BRDA:17,1,0,0 +BRDA:18,2,0,0 +BRDA:19,3,0,0 +BRF:4 +BRH:0 +end_of_record +TN: +SF:lib/health/checkFns/index.ts +FN:11,(anonymous_0) +FN:2,(anonymous_1) +FN:4,(anonymous_2) +FN:6,timeoutPromise +FN:7,(anonymous_4) +FN:8,(anonymous_5) +FNF:6 +FNH:2 +FNDA:6,(anonymous_0) +FNDA:0,(anonymous_1) +FNDA:6,(anonymous_2) +FNDA:0,timeoutPromise +FNDA:0,(anonymous_4) +FNDA:0,(anonymous_5) +DA:1,5 +DA:2,5 +DA:4,11 +DA:6,5 +DA:7,0 +DA:8,0 +DA:11,11 +LF:7 +LH:5 +BRDA:6,0,0,0 +BRDA:6,1,0,0 +BRF:2 +BRH:0 +end_of_record +TN: +SF:lib/health/checkFns/runHealthScript.ts +FN:14,(anonymous_0) +FN:20,(anonymous_1) +FN:27,(anonymous_2) +FNF:3 +FNH:0 +FNDA:0,(anonymous_0) +FNDA:0,(anonymous_1) +FNDA:0,(anonymous_2) +DA:5,5 +DA:14,5 +DA:21,0 +DA:24,0 +DA:28,0 +DA:29,0 +DA:30,0 +DA:31,0 +DA:33,0 +LF:9 +LH:2 +BRDA:17,0,0,0 +BRDA:18,1,0,0 +BRDA:19,2,0,0 +BRDA:20,3,0,0 +BRF:4 +BRH:0 +end_of_record +TN: +SF:lib/inits/setupInit.ts +FN:11,setupInit +FN:26,(anonymous_1) +FN:47,(anonymous_2) +FNF:3 +FNH:0 +FNDA:0,setupInit +FNDA:0,(anonymous_1) +FNDA:0,(anonymous_2) +DA:2,5 +DA:11,5 +DA:25,0 +DA:27,0 +DA:28,0 +DA:29,0 +DA:35,0 +DA:36,0 +DA:40,0 +DA:44,0 +DA:45,0 +DA:48,0 +DA:49,0 +DA:50,0 +DA:51,0 +DA:58,0 +LF:16 +LH:2 +BRDA:28,0,0,0 +BRDA:28,0,1,0 +BRDA:48,1,0,0 +BRDA:48,1,1,0 +BRDA:50,2,0,0 +BRF:5 +BRH:0 +end_of_record +TN: +SF:lib/inits/setupInstall.ts +FN:7,(anonymous_0) +FN:8,(anonymous_1) +FN:14,(anonymous_2) +FN:21,setupInstall +FNF:4 +FNH:0 +FNDA:0,(anonymous_0) +FNDA:0,(anonymous_1) +FNDA:0,(anonymous_2) +FNDA:0,setupInstall +DA:6,5 +DA:7,0 +DA:11,0 +DA:15,0 +DA:21,5 +DA:24,0 +LF:6 +LH:2 +BRF:0 +BRH:0 +end_of_record +TN: +SF:lib/inits/setupUninstall.ts +FN:7,(anonymous_0) +FN:8,(anonymous_1) +FN:14,(anonymous_2) +FN:25,setupUninstall +FNF:4 +FNH:0 +FNDA:0,(anonymous_0) +FNDA:0,(anonymous_1) +FNDA:0,(anonymous_2) +FNDA:0,setupUninstall +DA:6,5 +DA:7,0 +DA:11,0 +DA:18,0 +DA:19,0 +DA:25,5 +DA:28,0 +LF:7 +LH:2 +BRDA:18,0,0,0 +BRF:1 +BRH:0 +end_of_record +TN: +SF:lib/interfaces/Host.ts +FN:89,(anonymous_0) +FN:97,(anonymous_1) +FN:108,(anonymous_2) +FN:127,(anonymous_3) +FN:161,(anonymous_4) +FN:171,inObject +FN:191,(anonymous_6) +FNF:7 +FNH:0 +FNDA:0,(anonymous_0) +FNDA:0,(anonymous_1) +FNDA:0,(anonymous_2) +FNDA:0,(anonymous_3) +FNDA:0,(anonymous_4) +FNDA:0,inObject +FNDA:0,(anonymous_6) +DA:1,6 +DA:3,6 +DA:11,6 +DA:84,6 +DA:88,6 +DA:90,0 +DA:101,0 +DA:102,0 +DA:104,0 +DA:116,0 +DA:122,0 +DA:124,0 +DA:131,0 +DA:133,0 +DA:135,0 +DA:137,0 +DA:147,0 +DA:149,0 +DA:158,0 +DA:165,0 +DA:166,0 +DA:167,0 +DA:175,0 +DA:190,6 +DA:192,0 +LF:25 +LH:6 +BRDA:101,0,0,0 +BRDA:101,0,1,0 +BRDA:133,1,0,0 +BRDA:133,1,1,0 +BRDA:137,2,0,0 +BRDA:137,2,1,0 +BRDA:137,3,0,0 +BRDA:137,3,1,0 +BRDA:143,4,0,0 +BRDA:143,4,1,0 +BRDA:147,5,0,0 +BRDA:147,5,1,0 +BRDA:165,6,0,0 +BRDA:165,7,0,0 +BRDA:165,7,1,0 +BRDA:166,8,0,0 +BRDA:166,9,0,0 +BRDA:166,9,1,0 +BRF:18 +BRH:0 +end_of_record +TN: +SF:lib/interfaces/Origin.ts +FN:7,(anonymous_0) +FN:14,(anonymous_1) +FN:17,(anonymous_2) +FN:41,(anonymous_3) +FNF:4 +FNH:0 +FNDA:0,(anonymous_0) +FNDA:0,(anonymous_1) +FNDA:0,(anonymous_2) +FNDA:0,(anonymous_3) +DA:6,6 +DA:8,0 +DA:9,0 +DA:10,0 +DA:11,0 +DA:15,0 +DA:17,0 +DA:21,0 +DA:23,0 +DA:44,0 +DA:45,0 +DA:57,0 +DA:59,0 +DA:66,0 +DA:76,0 +DA:79,0 +LF:16 +LH:1 +BRDA:21,0,0,0 +BRDA:21,0,1,0 +BRDA:26,1,0,0 +BRDA:26,1,1,0 +BRDA:27,2,0,0 +BRDA:27,2,1,0 +BRF:6 +BRH:0 +end_of_record +TN: +SF:lib/interfaces/ServiceInterfaceBuilder.ts +FN:17,(anonymous_0) +FNF:1 +FNH:0 +FNDA:0,(anonymous_0) +DA:16,5 +DA:18,0 +LF:2 +LH:1 +BRF:0 +BRH:0 +end_of_record +TN: +SF:lib/interfaces/setupInterfaces.ts +FN:23,(anonymous_0) +FNF:1 +FNH:0 +FNDA:0,(anonymous_0) +DA:22,5 +DA:23,5 +LF:2 +LH:2 +BRF:0 +BRH:0 +end_of_record +TN: +SF:lib/mainFn/CommandController.ts +FN:16,(anonymous_0) +FN:23,(anonymous_1) +FN:24,(anonymous_2) +FN:53,(anonymous_3) +FN:71,(anonymous_4) +FN:72,(anonymous_5) +FN:102,(anonymous_6) +FN:105,(anonymous_7) +FN:107,(anonymous_8) +FN:116,(anonymous_9) +FN:119,(anonymous_10) +FN:130,(anonymous_11) +FNF:12 +FNH:0 +FNDA:0,(anonymous_0) +FNDA:0,(anonymous_1) +FNDA:0,(anonymous_2) +FNDA:0,(anonymous_3) +FNDA:0,(anonymous_4) +FNDA:0,(anonymous_5) +FNDA:0,(anonymous_6) +FNDA:0,(anonymous_7) +FNDA:0,(anonymous_8) +FNDA:0,(anonymous_9) +FNDA:0,(anonymous_10) +FNDA:0,(anonymous_11) +DA:1,5 +DA:2,5 +DA:6,5 +DA:12,5 +DA:15,5 +DA:17,0 +DA:18,0 +DA:19,0 +DA:20,0 +DA:21,0 +DA:24,0 +DA:49,0 +DA:51,0 +DA:54,0 +DA:55,0 +DA:56,0 +DA:58,0 +DA:61,0 +DA:62,0 +DA:66,0 +DA:70,0 +DA:71,0 +DA:72,0 +DA:73,0 +DA:74,0 +DA:79,0 +DA:81,0 +DA:82,0 +DA:84,0 +DA:93,0 +DA:103,0 +DA:106,0 +DA:107,0 +DA:108,0 +DA:110,0 +DA:111,0 +DA:113,0 +DA:114,0 +DA:116,0 +DA:120,0 +DA:121,0 +DA:122,0 +DA:123,0 +DA:129,0 +DA:130,0 +DA:131,0 +DA:134,0 +DA:136,0 +LF:48 +LH:5 +BRDA:21,0,0,0 +BRDA:51,1,0,0 +BRDA:51,1,1,0 +BRDA:55,2,0,0 +BRDA:55,2,1,0 +BRDA:61,3,0,0 +BRDA:61,3,1,0 +BRDA:74,4,0,0 +BRDA:75,5,0,0 +BRDA:75,5,1,0 +BRDA:75,5,2,0 +BRDA:75,5,3,0 +BRDA:81,6,0,0 +BRDA:81,6,1,0 +BRDA:105,7,0,0 +BRDA:105,8,0,0 +BRDA:106,9,0,0 +BRDA:113,10,0,0 +BRDA:119,11,0,0 +BRDA:119,12,0,0 +BRDA:119,13,0,0 +BRDA:121,14,0,0 +BRDA:122,15,0,0 +BRDA:129,16,0,0 +BRF:24 +BRH:0 +end_of_record +TN: +SF:lib/mainFn/Daemon.ts +FN:16,(anonymous_0) +FN:17,(anonymous_1) +FN:20,(anonymous_2) +FN:21,(anonymous_3) +FN:44,(anonymous_4) +FN:54,(anonymous_5) +FN:60,(anonymous_6) +FN:63,(anonymous_7) +FN:64,(anonymous_8) +FN:68,(anonymous_9) +FN:72,(anonymous_10) +FN:78,(anonymous_11) +FN:85,(anonymous_12) +FNF:13 +FNH:0 +FNDA:0,(anonymous_0) +FNDA:0,(anonymous_1) +FNDA:0,(anonymous_2) +FNDA:0,(anonymous_3) +FNDA:0,(anonymous_4) +FNDA:0,(anonymous_5) +FNDA:0,(anonymous_6) +FNDA:0,(anonymous_7) +FNDA:0,(anonymous_8) +FNDA:0,(anonymous_9) +FNDA:0,(anonymous_10) +FNDA:0,(anonymous_11) +FNDA:0,(anonymous_12) +DA:2,5 +DA:4,5 +DA:6,5 +DA:7,5 +DA:13,5 +DA:14,0 +DA:15,0 +DA:16,0 +DA:18,0 +DA:21,0 +DA:44,0 +DA:45,0 +DA:51,0 +DA:55,0 +DA:56,0 +DA:58,0 +DA:59,0 +DA:60,0 +DA:61,0 +DA:62,0 +DA:63,0 +DA:64,0 +DA:65,0 +DA:66,0 +DA:69,0 +DA:76,0 +DA:82,0 +DA:83,0 +DA:85,0 +DA:86,0 +LF:30 +LH:5 +BRDA:55,0,0,0 +BRF:1 +BRH:0 +end_of_record +TN: +SF:lib/mainFn/Daemons.ts +FN:21,(anonymous_6) +FN:22,(anonymous_7) +FN:54,(anonymous_8) +FN:81,(anonymous_9) +FN:98,(anonymous_10) +FN:117,(anonymous_11) +FN:135,(anonymous_12) +FN:136,(anonymous_13) +FN:137,(anonymous_14) +FN:156,(anonymous_15) +FN:158,(anonymous_16) +FN:159,(anonymous_17) +FN:162,(anonymous_18) +FN:164,(anonymous_19) +FN:170,(anonymous_20) +FN:174,(anonymous_21) +FNF:16 +FNH:0 +FNDA:0,(anonymous_6) +FNDA:0,(anonymous_7) +FNDA:0,(anonymous_8) +FNDA:0,(anonymous_9) +FNDA:0,(anonymous_10) +FNDA:0,(anonymous_11) +FNDA:0,(anonymous_12) +FNDA:0,(anonymous_13) +FNDA:0,(anonymous_14) +FNDA:0,(anonymous_15) +FNDA:0,(anonymous_16) +FNDA:0,(anonymous_17) +FNDA:0,(anonymous_18) +FNDA:0,(anonymous_19) +FNDA:0,(anonymous_20) +FNDA:0,(anonymous_21) +DA:18,5 +DA:19,5 +DA:21,5 +DA:22,5 +DA:23,5 +DA:24,5 +DA:25,5 +DA:27,5 +DA:28,5 +DA:54,5 +DA:55,0 +DA:80,5 +DA:82,0 +DA:83,0 +DA:84,0 +DA:85,0 +DA:86,0 +DA:103,0 +DA:126,0 +DA:127,0 +DA:131,0 +DA:135,0 +DA:136,0 +DA:137,0 +DA:144,0 +DA:145,0 +DA:146,0 +DA:147,0 +DA:157,0 +DA:158,0 +DA:159,0 +DA:161,0 +DA:163,0 +DA:164,0 +DA:166,0 +DA:170,0 +DA:171,0 +DA:175,0 +LF:38 +LH:11 +BRF:0 +BRH:0 +end_of_record +TN: +SF:lib/mainFn/HealthDaemon.ts +FN:9,(anonymous_0) +FN:11,(anonymous_1) +FN:28,(anonymous_2) +FN:39,(anonymous_3) +FN:39,(anonymous_4) +FN:43,(anonymous_5) +FN:51,(anonymous_6) +FN:60,(anonymous_7) +FN:64,(anonymous_8) +FN:68,(anonymous_9) +FN:85,(anonymous_10) +FN:88,(anonymous_11) +FN:90,(anonymous_12) +FN:97,(anonymous_13) +FN:108,(anonymous_14) +FN:123,(anonymous_15) +FN:125,(anonymous_16) +FN:131,(anonymous_17) +FN:133,(anonymous_18) +FN:146,(anonymous_19) +FN:147,(anonymous_20) +FN:148,(anonymous_21) +FNF:22 +FNH:0 +FNDA:0,(anonymous_0) +FNDA:0,(anonymous_1) +FNDA:0,(anonymous_2) +FNDA:0,(anonymous_3) +FNDA:0,(anonymous_4) +FNDA:0,(anonymous_5) +FNDA:0,(anonymous_6) +FNDA:0,(anonymous_7) +FNDA:0,(anonymous_8) +FNDA:0,(anonymous_9) +FNDA:0,(anonymous_10) +FNDA:0,(anonymous_11) +FNDA:0,(anonymous_12) +FNDA:0,(anonymous_13) +FNDA:0,(anonymous_14) +FNDA:0,(anonymous_15) +FNDA:0,(anonymous_16) +FNDA:0,(anonymous_17) +FNDA:0,(anonymous_18) +FNDA:0,(anonymous_19) +FNDA:0,(anonymous_20) +FNDA:0,(anonymous_21) +DA:2,5 +DA:6,5 +DA:7,5 +DA:9,5 +DA:11,0 +DA:12,0 +DA:14,0 +DA:24,5 +DA:25,0 +DA:26,0 +DA:27,0 +DA:29,0 +DA:30,0 +DA:31,0 +DA:32,0 +DA:33,0 +DA:34,0 +DA:35,0 +DA:36,0 +DA:38,0 +DA:39,0 +DA:47,0 +DA:48,0 +DA:49,0 +DA:51,0 +DA:52,0 +DA:61,0 +DA:65,0 +DA:69,0 +DA:71,0 +DA:73,0 +DA:74,0 +DA:75,0 +DA:77,0 +DA:78,0 +DA:80,0 +DA:84,0 +DA:86,0 +DA:89,0 +DA:90,0 +DA:94,0 +DA:97,0 +DA:98,0 +DA:99,0 +DA:103,0 +DA:105,0 +DA:106,0 +DA:109,0 +DA:110,0 +DA:115,0 +DA:117,0 +DA:123,0 +DA:125,0 +DA:126,0 +DA:127,0 +DA:132,0 +DA:133,0 +DA:134,0 +DA:135,0 +DA:136,0 +DA:137,0 +DA:139,0 +DA:147,0 +DA:148,0 +LF:64 +LH:5 +BRDA:36,0,0,0 +BRDA:69,1,0,0 +BRDA:73,2,0,0 +BRDA:73,2,1,0 +BRDA:89,3,0,0 +BRDA:90,4,0,0 +BRDA:90,4,1,0 +BRDA:105,5,0,0 +BRDA:105,5,1,0 +BRDA:112,6,0,0 +BRDA:112,6,1,0 +BRDA:136,7,0,0 +BRF:12 +BRH:0 +end_of_record +TN: +SF:lib/mainFn/Mounts.ts +FN:7,(anonymous_0) +FN:28,(anonymous_1) +FN:32,(anonymous_2) +FN:47,(anonymous_3) +FN:60,(anonymous_4) +FN:77,(anonymous_5) +FN:80,(anonymous_6) +FN:81,(anonymous_7) +FN:82,(anonymous_8) +FN:92,(anonymous_9) +FN:103,(anonymous_10) +FN:113,(anonymous_11) +FNF:12 +FNH:0 +FNDA:0,(anonymous_0) +FNDA:0,(anonymous_1) +FNDA:0,(anonymous_2) +FNDA:0,(anonymous_3) +FNDA:0,(anonymous_4) +FNDA:0,(anonymous_5) +FNDA:0,(anonymous_6) +FNDA:0,(anonymous_7) +FNDA:0,(anonymous_8) +FNDA:0,(anonymous_9) +FNDA:0,(anonymous_10) +FNDA:0,(anonymous_11) +DA:6,5 +DA:8,0 +DA:14,0 +DA:19,0 +DA:29,0 +DA:38,0 +DA:44,0 +DA:52,0 +DA:57,0 +DA:67,0 +DA:74,0 +DA:78,0 +DA:79,0 +DA:80,0 +DA:81,0 +DA:82,0 +DA:83,0 +DA:84,0 +DA:88,0 +DA:90,0 +DA:92,0 +DA:103,0 +DA:113,0 +LF:23 +LH:1 +BRDA:83,0,0,0 +BRF:1 +BRH:0 +end_of_record +TN: +SF:lib/mainFn/index.ts +FN:21,(anonymous_0) +FN:27,(anonymous_1) +FNF:2 +FNH:0 +FNDA:0,(anonymous_0) +FNDA:0,(anonymous_1) +DA:3,5 +DA:4,5 +DA:6,5 +DA:10,5 +DA:21,5 +DA:27,0 +DA:28,0 +DA:29,0 +LF:8 +LH:5 +BRF:0 +BRH:0 +end_of_record +TN: +SF:lib/manifest/setupManifest.ts +FN:12,setupManifest +FN:32,(anonymous_1) +FN:63,(anonymous_2) +FN:70,(anonymous_3) +FN:77,(anonymous_4) +FNF:5 +FNH:1 +FNDA:5,setupManifest +FNDA:0,(anonymous_1) +FNDA:0,(anonymous_2) +FNDA:0,(anonymous_3) +FNDA:0,(anonymous_4) +DA:4,4 +DA:12,4 +DA:31,5 +DA:33,0 +DA:34,0 +DA:35,0 +DA:36,0 +DA:37,0 +DA:41,5 +DA:63,0 +DA:71,0 +DA:72,0 +DA:74,0 +DA:75,0 +DA:77,0 +LF:15 +LH:4 +BRDA:33,0,0,0 +BRDA:33,0,1,0 +BRDA:34,1,0,0 +BRDA:35,2,0,0 +BRDA:35,2,1,0 +BRDA:47,3,0,5 +BRDA:47,3,1,0 +BRDA:52,4,0,5 +BRDA:52,4,1,5 +BRDA:53,5,0,5 +BRDA:53,5,1,5 +BRDA:54,6,0,5 +BRDA:54,6,1,5 +BRDA:55,7,0,5 +BRDA:55,7,1,5 +BRDA:56,8,0,5 +BRDA:56,8,1,5 +BRDA:57,9,0,5 +BRDA:57,9,1,5 +BRDA:59,10,0,5 +BRDA:59,10,1,0 +BRDA:62,11,0,5 +BRDA:62,11,1,5 +BRDA:66,12,0,5 +BRDA:66,12,1,5 +BRDA:68,13,0,5 +BRDA:68,13,1,0 +BRDA:71,14,0,0 +BRDA:74,15,0,0 +BRF:29 +BRH:19 +end_of_record +TN: +SF:lib/store/PathBuilder.ts +FN:22,(anonymous_0) +FN:26,(anonymous_1) +FN:30,(anonymous_2) +FNF:3 +FNH:1 +FNDA:0,(anonymous_0) +FNDA:6,(anonymous_1) +FNDA:0,(anonymous_2) +DA:3,5 +DA:21,5 +DA:22,5 +DA:23,0 +DA:26,5 +DA:29,6 +DA:31,0 +DA:32,0 +DA:33,0 +DA:35,0 +LF:10 +LH:5 +BRDA:27,0,0,6 +BRDA:31,1,0,0 +BRDA:32,2,0,0 +BRF:3 +BRH:1 +end_of_record +TN: +SF:lib/store/getStore.ts +FN:5,(anonymous_0) +FN:17,(anonymous_1) +FN:27,(anonymous_2) +FN:37,(anonymous_3) +FN:40,(anonymous_4) +FN:46,(anonymous_5) +FN:52,getStore +FNF:7 +FNH:0 +FNDA:0,(anonymous_0) +FNDA:0,(anonymous_1) +FNDA:0,(anonymous_2) +FNDA:0,(anonymous_3) +FNDA:0,(anonymous_4) +FNDA:0,(anonymous_5) +FNDA:0,getStore +DA:2,5 +DA:4,5 +DA:6,0 +DA:7,0 +DA:8,0 +DA:18,0 +DA:28,0 +DA:38,0 +DA:40,0 +DA:41,0 +DA:43,0 +DA:46,0 +DA:48,0 +DA:52,5 +DA:60,0 +LF:15 +LH:3 +BRDA:8,0,0,0 +BRDA:55,1,0,0 +BRF:2 +BRH:0 +end_of_record +TN: +SF:lib/test/output.sdk.ts +FNF:0 +FNH:0 +DA:1,4 +DA:2,4 +DA:3,4 +DA:4,4 +DA:7,4 +LF:5 +LH:5 +BRF:0 +BRH:0 +end_of_record +TN: +SF:lib/test/output.ts +FNF:0 +FNH:0 +DA:2,2 +DA:3,2 +DA:5,2 +DA:376,2 +LF:4 +LH:4 +BRF:0 +BRH:0 +end_of_record +TN: +SF:lib/trigger/changeOnFirstSuccess.ts +FN:3,changeOnFirstSuccess +FN:7,(anonymous_1) +FNF:2 +FNH:1 +FNDA:5,changeOnFirstSuccess +FNDA:0,(anonymous_1) +DA:3,5 +DA:7,5 +DA:8,0 +DA:9,0 +DA:10,0 +DA:11,0 +DA:13,0 +DA:14,0 +DA:15,0 +DA:19,0 +DA:20,0 +DA:22,0 +DA:23,0 +DA:24,0 +DA:28,0 +DA:29,0 +LF:16 +LH:2 +BRDA:16,0,0,0 +BRDA:16,0,1,0 +BRF:2 +BRH:0 +end_of_record +TN: +SF:lib/trigger/cooldownTrigger.ts +FN:1,cooldownTrigger +FN:2,(anonymous_1) +FN:4,(anonymous_2) +FNF:3 +FNH:1 +FNDA:10,cooldownTrigger +FNDA:0,(anonymous_1) +FNDA:0,(anonymous_2) +DA:1,5 +DA:2,10 +DA:3,0 +DA:4,0 +DA:5,0 +LF:5 +LH:2 +BRF:0 +BRH:0 +end_of_record +TN: +SF:lib/trigger/defaultTrigger.ts +FNF:0 +FNH:0 +DA:1,5 +DA:2,5 +DA:5,5 +LF:3 +LH:3 +BRF:0 +BRH:0 +end_of_record +TN: +SF:lib/trigger/index.ts +FN:3,(anonymous_0) +FN:4,(anonymous_1) +FNF:2 +FNH:2 +FNDA:6,(anonymous_0) +FNDA:6,(anonymous_1) +DA:3,11 +DA:4,11 +LF:2 +LH:2 +BRF:0 +BRH:0 +end_of_record +TN: +SF:lib/trigger/lastStatus.ts +FN:8,lastStatus +FN:9,(anonymous_1) +FNF:2 +FNH:0 +FNDA:0,lastStatus +FNDA:0,(anonymous_1) +DA:8,5 +DA:9,0 +DA:10,0 +DA:13,0 +DA:16,0 +DA:17,0 +DA:18,0 +DA:19,0 +DA:20,0 +DA:21,0 +DA:23,0 +DA:24,0 +DA:26,0 +DA:27,0 +DA:29,0 +DA:30,0 +LF:16 +LH:1 +BRDA:19,0,0,0 +BRDA:23,1,0,0 +BRDA:26,2,0,0 +BRF:3 +BRH:0 +end_of_record +TN: +SF:lib/trigger/successFailure.ts +FN:4,(anonymous_0) +FNF:1 +FNH:0 +FNDA:0,(anonymous_0) +DA:2,5 +DA:4,5 +DA:7,0 +LF:3 +LH:2 +BRF:0 +BRH:0 +end_of_record +TN: +SF:lib/util/GetSslCertificate.ts +FN:5,(anonymous_0) +FN:14,(anonymous_1) +FN:24,(anonymous_2) +FN:33,(anonymous_3) +FN:36,(anonymous_4) +FN:42,(anonymous_5) +FNF:6 +FNH:0 +FNDA:0,(anonymous_0) +FNDA:0,(anonymous_1) +FNDA:0,(anonymous_2) +FNDA:0,(anonymous_3) +FNDA:0,(anonymous_4) +FNDA:0,(anonymous_5) +DA:4,5 +DA:6,0 +DA:7,0 +DA:8,0 +DA:15,0 +DA:25,0 +DA:34,0 +DA:36,0 +DA:37,0 +DA:39,0 +DA:42,0 +DA:44,0 +LF:12 +LH:1 +BRF:0 +BRH:0 +end_of_record +TN: +SF:lib/util/GetSystemSmtp.ts +FN:4,(anonymous_0) +FN:9,(anonymous_1) +FN:17,(anonymous_2) +FN:23,(anonymous_3) +FN:26,(anonymous_4) +FN:30,(anonymous_5) +FNF:6 +FNH:0 +FNDA:0,(anonymous_0) +FNDA:0,(anonymous_1) +FNDA:0,(anonymous_2) +FNDA:0,(anonymous_3) +FNDA:0,(anonymous_4) +FNDA:0,(anonymous_5) +DA:3,5 +DA:4,0 +DA:10,0 +DA:18,0 +DA:24,0 +DA:26,0 +DA:27,0 +DA:29,0 +DA:30,0 +DA:32,0 +LF:10 +LH:1 +BRF:0 +BRH:0 +end_of_record +TN: +SF:lib/util/Hostname.ts +FN:3,hostnameInfoToAddress +FNF:1 +FNH:0 +FNDA:0,hostnameInfoToAddress +DA:3,5 +DA:4,0 +DA:5,0 +DA:7,0 +DA:8,0 +DA:10,0 +DA:11,0 +DA:12,0 +DA:14,0 +DA:15,0 +DA:16,0 +DA:17,0 +DA:19,0 +DA:20,0 +DA:22,0 +LF:15 +LH:1 +BRDA:4,0,0,0 +BRDA:7,1,0,0 +BRDA:11,2,0,0 +BRDA:12,3,0,0 +BRDA:12,3,1,0 +BRDA:14,4,0,0 +BRDA:14,4,1,0 +BRDA:15,5,0,0 +BRDA:15,5,1,0 +BRDA:16,6,0,0 +BRDA:16,7,0,0 +BRDA:16,7,1,0 +BRDA:19,8,0,0 +BRF:13 +BRH:0 +end_of_record +TN: +SF:lib/util/SubContainer.ts +FN:8,(anonymous_6) +FN:9,(anonymous_7) +FN:51,(anonymous_8) +FN:62,(anonymous_9) +FN:66,(anonymous_10) +FN:67,(anonymous_11) +FN:70,(anonymous_12) +FN:86,(anonymous_13) +FN:113,(anonymous_14) +FN:130,(anonymous_15) +FN:175,(anonymous_16) +FN:179,(anonymous_17) +FN:181,(anonymous_18) +FN:193,(anonymous_19) +FN:194,(anonymous_20) +FN:201,(anonymous_21) +FN:216,(anonymous_22) +FN:242,(anonymous_23) +FN:243,(anonymous_24) +FN:251,(anonymous_25) +FN:257,(anonymous_26) +FN:258,(anonymous_27) +FN:270,(anonymous_28) +FN:274,(anonymous_29) +FN:278,(anonymous_30) +FN:290,(anonymous_31) +FN:299,(anonymous_32) +FN:326,(anonymous_33) +FN:332,(anonymous_34) +FN:341,(anonymous_35) +FN:375,(anonymous_36) +FN:376,(anonymous_37) +FN:380,(anonymous_38) +FN:387,(anonymous_39) +FN:432,wait +FN:433,(anonymous_41) +FNF:36 +FNH:0 +FNDA:0,(anonymous_6) +FNDA:0,(anonymous_7) +FNDA:0,(anonymous_8) +FNDA:0,(anonymous_9) +FNDA:0,(anonymous_10) +FNDA:0,(anonymous_11) +FNDA:0,(anonymous_12) +FNDA:0,(anonymous_13) +FNDA:0,(anonymous_14) +FNDA:0,(anonymous_15) +FNDA:0,(anonymous_16) +FNDA:0,(anonymous_17) +FNDA:0,(anonymous_18) +FNDA:0,(anonymous_19) +FNDA:0,(anonymous_20) +FNDA:0,(anonymous_21) +FNDA:0,(anonymous_22) +FNDA:0,(anonymous_23) +FNDA:0,(anonymous_24) +FNDA:0,(anonymous_25) +FNDA:0,(anonymous_26) +FNDA:0,(anonymous_27) +FNDA:0,(anonymous_28) +FNDA:0,(anonymous_29) +FNDA:0,(anonymous_30) +FNDA:0,(anonymous_31) +FNDA:0,(anonymous_32) +FNDA:0,(anonymous_33) +FNDA:0,(anonymous_34) +FNDA:0,(anonymous_35) +FNDA:0,(anonymous_36) +FNDA:0,(anonymous_37) +FNDA:0,(anonymous_38) +FNDA:0,(anonymous_39) +FNDA:0,wait +FNDA:0,(anonymous_41) +DA:1,5 +DA:3,5 +DA:4,5 +DA:5,5 +DA:6,5 +DA:7,5 +DA:8,5 +DA:9,5 +DA:21,5 +DA:47,5 +DA:49,0 +DA:52,0 +DA:53,0 +DA:54,0 +DA:55,0 +DA:57,0 +DA:58,0 +DA:62,0 +DA:63,0 +DA:65,0 +DA:67,0 +DA:68,0 +DA:69,0 +DA:70,0 +DA:72,0 +DA:73,0 +DA:78,0 +DA:80,0 +DA:82,0 +DA:90,0 +DA:91,0 +DA:95,0 +DA:96,0 +DA:97,0 +DA:100,0 +DA:102,0 +DA:103,0 +DA:104,0 +DA:105,0 +DA:106,0 +DA:107,0 +DA:110,0 +DA:119,0 +DA:120,0 +DA:121,0 +DA:122,0 +DA:124,0 +DA:126,0 +DA:131,0 +DA:134,0 +DA:135,0 +DA:140,0 +DA:142,0 +DA:143,0 +DA:144,0 +DA:145,0 +DA:146,0 +DA:151,0 +DA:153,0 +DA:154,0 +DA:155,0 +DA:156,0 +DA:157,0 +DA:158,0 +DA:159,0 +DA:164,0 +DA:166,0 +DA:167,0 +DA:168,0 +DA:170,0 +DA:172,0 +DA:176,0 +DA:177,0 +DA:179,0 +DA:180,0 +DA:181,0 +DA:182,0 +DA:184,0 +DA:185,0 +DA:188,0 +DA:194,0 +DA:195,0 +DA:196,0 +DA:197,0 +DA:211,0 +DA:212,0 +DA:216,0 +DA:218,0 +DA:219,0 +DA:220,0 +DA:221,0 +DA:223,0 +DA:224,0 +DA:225,0 +DA:226,0 +DA:228,0 +DA:241,0 +DA:242,0 +DA:243,0 +DA:244,0 +DA:245,0 +DA:247,0 +DA:251,0 +DA:253,0 +DA:254,0 +DA:255,0 +DA:257,0 +DA:258,0 +DA:259,0 +DA:260,0 +DA:261,0 +DA:262,0 +DA:267,0 +DA:270,0 +DA:271,0 +DA:273,0 +DA:274,0 +DA:276,0 +DA:277,0 +DA:278,0 +DA:279,0 +DA:280,0 +DA:294,0 +DA:295,0 +DA:299,0 +DA:301,0 +DA:302,0 +DA:303,0 +DA:304,0 +DA:306,0 +DA:307,0 +DA:308,0 +DA:309,0 +DA:311,0 +DA:312,0 +DA:313,0 +DA:326,0 +DA:327,0 +DA:329,0 +DA:336,0 +DA:337,0 +DA:341,0 +DA:343,0 +DA:344,0 +DA:345,0 +DA:346,0 +DA:348,0 +DA:349,0 +DA:350,0 +DA:351,0 +DA:353,0 +DA:374,5 +DA:375,0 +DA:377,0 +DA:385,0 +DA:391,0 +DA:433,0 +LF:157 +LH:11 +BRDA:72,0,0,0 +BRDA:96,1,0,0 +BRDA:131,2,0,0 +BRDA:131,2,1,0 +BRDA:134,3,0,0 +BRDA:134,3,1,0 +BRDA:135,4,0,0 +BRDA:135,4,1,0 +BRDA:136,5,0,0 +BRDA:136,5,1,0 +BRDA:145,6,0,0 +BRDA:145,6,1,0 +BRDA:146,7,0,0 +BRDA:146,7,1,0 +BRDA:147,8,0,0 +BRDA:147,8,1,0 +BRDA:156,9,0,0 +BRDA:156,9,1,0 +BRDA:158,10,0,0 +BRDA:158,10,1,0 +BRDA:159,11,0,0 +BRDA:159,11,1,0 +BRDA:160,12,0,0 +BRDA:160,12,1,0 +BRDA:176,13,0,0 +BRDA:184,14,0,0 +BRDA:204,15,0,0 +BRDA:219,16,0,0 +BRDA:223,17,0,0 +BRDA:223,17,1,0 +BRDA:224,18,0,0 +BRDA:239,19,0,0 +BRDA:239,19,1,0 +BRDA:241,20,0,0 +BRDA:244,21,0,0 +BRDA:244,21,1,0 +BRDA:259,22,0,0 +BRDA:259,22,1,0 +BRDA:259,23,0,0 +BRDA:259,23,1,0 +BRDA:261,24,0,0 +BRDA:261,24,1,0 +BRDA:261,25,0,0 +BRDA:261,25,1,0 +BRDA:273,26,0,0 +BRDA:273,27,0,0 +BRDA:273,27,1,0 +BRDA:302,28,0,0 +BRDA:306,29,0,0 +BRDA:306,29,1,0 +BRDA:307,30,0,0 +BRDA:344,31,0,0 +BRDA:348,32,0,0 +BRDA:348,32,1,0 +BRDA:349,33,0,0 +BRF:55 +BRH:0 +end_of_record +TN: +SF:lib/util/asError.ts +FN:1,(anonymous_0) +FNF:1 +FNH:0 +FNDA:0,(anonymous_0) +DA:1,5 +DA:2,0 +DA:3,0 +DA:5,0 +LF:4 +LH:1 +BRDA:2,0,0,0 +BRF:1 +BRH:0 +end_of_record +TN: +SF:lib/util/deepEqual.ts +FN:3,deepEqual +FN:11,(anonymous_1) +FNF:2 +FNH:2 +FNDA:11,deepEqual +FNDA:6,(anonymous_1) +DA:1,6 +DA:3,6 +DA:4,11 +DA:5,3 +DA:6,3 +DA:7,0 +DA:8,0 +DA:10,3 +DA:11,6 +DA:12,3 +DA:13,5 +DA:14,10 +DA:15,10 +DA:18,3 +LF:14 +LH:12 +BRDA:4,0,0,8 +BRDA:6,1,0,0 +BRDA:7,2,0,0 +BRDA:10,3,0,0 +BRDA:14,4,0,0 +BRDA:15,5,0,0 +BRF:6 +BRH:1 +end_of_record +TN: +SF:lib/util/deepMerge.ts +FN:3,deepMerge +FN:6,(anonymous_1) +FN:9,(anonymous_2) +FN:11,(anonymous_3) +FNF:4 +FNH:4 +FNDA:253,deepMerge +FNDA:126,(anonymous_1) +FNDA:149,(anonymous_2) +FNDA:528,(anonymous_3) +DA:1,6 +DA:3,6 +DA:4,253 +DA:5,253 +DA:6,126 +DA:7,97 +DA:8,71 +DA:9,149 +DA:10,71 +DA:11,242 +DA:12,528 +DA:14,242 +DA:16,71 +LF:13 +LH:13 +BRDA:5,0,0,156 +BRDA:7,1,0,26 +BRDA:8,2,0,50 +BRDA:12,3,0,262 +BRDA:12,3,1,266 +BRF:5 +BRH:5 +end_of_record +TN: +SF:lib/util/fileHelper.ts +FN:56,(anonymous_7) +FN:61,(anonymous_8) +FN:69,(anonymous_9) +FN:72,(anonymous_10) +FN:73,(anonymous_11) +FN:79,(anonymous_12) +FN:83,(anonymous_13) +FN:84,(anonymous_14) +FN:93,(anonymous_15) +FN:103,(anonymous_16) +FN:106,(anonymous_17) +FN:109,(anonymous_18) +FN:117,(anonymous_19) +FN:123,(anonymous_20) +FN:126,(anonymous_21) +FN:134,(anonymous_22) +FN:140,(anonymous_23) +FN:143,(anonymous_24) +FNF:18 +FNH:0 +FNDA:0,(anonymous_7) +FNDA:0,(anonymous_8) +FNDA:0,(anonymous_9) +FNDA:0,(anonymous_10) +FNDA:0,(anonymous_11) +FNDA:0,(anonymous_12) +FNDA:0,(anonymous_13) +FNDA:0,(anonymous_14) +FNDA:0,(anonymous_15) +FNDA:0,(anonymous_16) +FNDA:0,(anonymous_17) +FNDA:0,(anonymous_18) +FNDA:0,(anonymous_19) +FNDA:0,(anonymous_20) +FNDA:0,(anonymous_21) +FNDA:0,(anonymous_22) +FNDA:0,(anonymous_23) +FNDA:0,(anonymous_24) +DA:2,5 +DA:3,5 +DA:4,5 +DA:6,5 +DA:8,5 +DA:55,5 +DA:57,0 +DA:58,0 +DA:59,0 +DA:62,0 +DA:63,0 +DA:64,0 +DA:67,0 +DA:70,0 +DA:72,0 +DA:73,0 +DA:76,0 +DA:78,0 +DA:79,0 +DA:84,0 +DA:85,0 +DA:86,0 +DA:98,0 +DA:104,0 +DA:107,0 +DA:110,0 +DA:121,0 +DA:124,0 +DA:127,0 +DA:138,0 +DA:141,0 +DA:144,0 +DA:150,5 +LF:33 +LH:7 +BRDA:63,0,0,0 +BRDA:70,1,0,0 +BRDA:84,2,0,0 +BRDA:84,2,1,0 +BRF:4 +BRH:0 +end_of_record +TN: +SF:lib/util/getDefaultString.ts +FN:4,getDefaultString +FNF:1 +FNH:0 +FNDA:0,getDefaultString +DA:2,5 +DA:4,5 +DA:5,0 +DA:6,0 +DA:8,0 +LF:5 +LH:2 +BRDA:5,0,0,0 +BRDA:5,0,1,0 +BRF:2 +BRH:0 +end_of_record +TN: +SF:lib/util/getRandomCharInSet.ts +FN:3,getRandomCharInSet +FN:16,stringToCharSet +FNF:2 +FNH:0 +FNDA:0,getRandomCharInSet +FNDA:0,stringToCharSet +DA:3,5 +DA:4,0 +DA:5,0 +DA:8,0 +DA:9,0 +DA:10,0 +DA:12,0 +DA:14,0 +DA:17,0 +DA:18,0 +DA:19,0 +DA:20,0 +DA:21,0 +DA:22,0 +DA:24,0 +DA:25,0 +DA:26,0 +DA:28,0 +DA:29,0 +DA:34,0 +DA:35,0 +DA:36,0 +DA:37,0 +DA:38,0 +DA:39,0 +DA:40,0 +DA:41,0 +DA:42,0 +DA:43,0 +DA:44,0 +DA:45,0 +DA:47,0 +DA:49,0 +DA:51,0 +DA:52,0 +DA:53,0 +DA:54,0 +DA:55,0 +DA:56,0 +DA:58,0 +DA:60,0 +DA:62,0 +DA:63,0 +DA:64,0 +DA:65,0 +DA:67,0 +DA:71,0 +DA:72,0 +DA:73,0 +DA:75,0 +DA:76,0 +DA:81,0 +DA:82,0 +DA:83,0 +DA:84,0 +DA:90,0 +LF:56 +LH:1 +BRDA:9,0,0,0 +BRDA:22,1,0,0 +BRDA:22,1,1,0 +BRDA:22,1,2,0 +BRDA:24,2,0,0 +BRDA:24,2,1,0 +BRDA:24,3,0,0 +BRDA:24,3,1,0 +BRDA:25,4,0,0 +BRDA:38,5,0,0 +BRDA:38,5,1,0 +BRDA:38,6,0,0 +BRDA:38,6,1,0 +BRDA:42,7,0,0 +BRDA:42,7,1,0 +BRDA:42,8,0,0 +BRDA:42,8,1,0 +BRDA:44,9,0,0 +BRDA:44,9,1,0 +BRDA:44,10,0,0 +BRDA:44,10,1,0 +BRDA:44,10,2,0 +BRDA:51,11,0,0 +BRDA:51,11,1,0 +BRDA:53,12,0,0 +BRDA:53,12,1,0 +BRDA:55,13,0,0 +BRDA:55,13,1,0 +BRDA:55,14,0,0 +BRDA:55,14,1,0 +BRDA:62,15,0,0 +BRDA:62,15,1,0 +BRDA:64,16,0,0 +BRDA:64,16,1,0 +BRDA:64,17,0,0 +BRDA:64,17,1,0 +BRDA:71,18,0,0 +BRDA:71,18,1,0 +BRDA:71,19,0,0 +BRDA:71,19,1,0 +BRDA:72,20,0,0 +BRDA:82,21,0,0 +BRF:42 +BRH:0 +end_of_record +TN: +SF:lib/util/getRandomString.ts +FN:4,getRandomString +FNF:1 +FNH:0 +FNDA:0,getRandomString +DA:2,5 +DA:4,5 +DA:5,0 +DA:6,0 +DA:7,0 +DA:10,0 +LF:6 +LH:2 +BRF:0 +BRH:0 +end_of_record +TN: +SF:lib/util/getServiceInterface.ts +FN:19,(anonymous_0) +FN:67,(anonymous_1) +FN:68,(anonymous_2) +FN:69,(anonymous_3) +FN:71,(anonymous_4) +FN:72,(anonymous_5) +FN:74,(anonymous_6) +FN:75,(anonymous_7) +FN:80,(anonymous_8) +FN:111,(anonymous_9) +FN:121,(anonymous_10) +FN:122,(anonymous_11) +FN:124,(anonymous_12) +FN:126,(anonymous_13) +FN:129,(anonymous_14) +FN:131,(anonymous_15) +FN:136,(anonymous_16) +FN:138,(anonymous_17) +FN:141,(anonymous_18) +FN:143,(anonymous_19) +FN:146,(anonymous_20) +FN:148,(anonymous_21) +FN:154,(anonymous_22) +FN:157,(anonymous_23) +FN:160,(anonymous_24) +FN:163,(anonymous_25) +FN:166,(anonymous_26) +FN:169,(anonymous_27) +FN:172,(anonymous_28) +FN:178,(anonymous_29) +FN:216,(anonymous_30) +FN:225,(anonymous_31) +FN:233,(anonymous_32) +FN:248,(anonymous_33) +FN:262,(anonymous_34) +FN:265,(anonymous_35) +FN:266,(anonymous_36) +FN:279,getServiceInterface +FNF:38 +FNH:1 +FNDA:8,(anonymous_0) +FNDA:0,(anonymous_1) +FNDA:0,(anonymous_2) +FNDA:0,(anonymous_3) +FNDA:0,(anonymous_4) +FNDA:0,(anonymous_5) +FNDA:0,(anonymous_6) +FNDA:0,(anonymous_7) +FNDA:0,(anonymous_8) +FNDA:0,(anonymous_9) +FNDA:0,(anonymous_10) +FNDA:0,(anonymous_11) +FNDA:0,(anonymous_12) +FNDA:0,(anonymous_13) +FNDA:0,(anonymous_14) +FNDA:0,(anonymous_15) +FNDA:0,(anonymous_16) +FNDA:0,(anonymous_17) +FNDA:0,(anonymous_18) +FNDA:0,(anonymous_19) +FNDA:0,(anonymous_20) +FNDA:0,(anonymous_21) +FNDA:0,(anonymous_22) +FNDA:0,(anonymous_23) +FNDA:0,(anonymous_24) +FNDA:0,(anonymous_25) +FNDA:0,(anonymous_26) +FNDA:0,(anonymous_27) +FNDA:0,(anonymous_28) +FNDA:0,(anonymous_29) +FNDA:0,(anonymous_30) +FNDA:0,(anonymous_31) +FNDA:0,(anonymous_32) +FNDA:0,(anonymous_33) +FNDA:0,(anonymous_34) +FNDA:0,(anonymous_35) +FNDA:0,(anonymous_36) +FNDA:0,getServiceInterface +DA:2,6 +DA:18,6 +DA:19,6 +DA:20,8 +DA:21,8 +DA:22,8 +DA:23,8 +DA:24,8 +DA:67,6 +DA:68,0 +DA:69,0 +DA:71,6 +DA:72,0 +DA:73,0 +DA:74,6 +DA:75,6 +DA:79,0 +DA:80,0 +DA:82,0 +DA:86,0 +DA:87,0 +DA:88,0 +DA:89,0 +DA:90,0 +DA:91,0 +DA:92,0 +DA:94,0 +DA:97,0 +DA:101,0 +DA:102,0 +DA:104,0 +DA:105,0 +DA:108,0 +DA:111,6 +DA:115,0 +DA:116,0 +DA:118,0 +DA:122,0 +DA:125,0 +DA:126,0 +DA:130,0 +DA:132,0 +DA:137,0 +DA:138,0 +DA:142,0 +DA:143,0 +DA:147,0 +DA:149,0 +DA:155,0 +DA:158,0 +DA:161,0 +DA:164,0 +DA:167,0 +DA:170,0 +DA:173,0 +DA:178,6 +DA:189,0 +DA:194,0 +DA:195,0 +DA:197,0 +DA:198,0 +DA:203,0 +DA:209,0 +DA:217,0 +DA:218,0 +DA:221,0 +DA:224,6 +DA:226,0 +DA:227,0 +DA:234,0 +DA:235,0 +DA:236,0 +DA:243,0 +DA:249,0 +DA:250,0 +DA:256,0 +DA:263,0 +DA:264,0 +DA:265,0 +DA:266,0 +DA:267,0 +DA:269,0 +DA:275,0 +DA:279,6 +DA:283,0 +LF:85 +LH:16 +BRDA:21,0,0,0 +BRDA:82,1,0,0 +BRDA:82,1,1,0 +BRDA:82,1,2,0 +BRDA:86,2,0,0 +BRDA:86,2,1,0 +BRDA:88,3,0,0 +BRDA:89,4,0,0 +BRDA:89,4,1,0 +BRDA:90,5,0,0 +BRDA:90,5,1,0 +BRDA:91,6,0,0 +BRDA:91,6,1,0 +BRDA:97,7,0,0 +BRDA:97,7,1,0 +BRDA:98,8,0,0 +BRDA:98,8,1,0 +BRDA:99,9,0,0 +BRDA:99,9,1,0 +BRDA:101,10,0,0 +BRDA:104,11,0,0 +BRDA:126,12,0,0 +BRDA:126,12,1,0 +BRDA:132,13,0,0 +BRDA:132,13,1,0 +BRDA:132,13,2,0 +BRDA:138,14,0,0 +BRDA:138,14,1,0 +BRDA:143,15,0,0 +BRDA:143,15,1,0 +BRDA:149,16,0,0 +BRDA:149,16,1,0 +BRDA:149,16,2,0 +BRDA:194,17,0,0 +BRDA:213,18,0,0 +BRDA:213,18,1,0 +BRDA:217,19,0,0 +BRF:37 +BRH:0 +end_of_record +TN: +SF:lib/util/getServiceInterfaces.ts +FN:8,(anonymous_0) +FN:23,(anonymous_1) +FN:39,(anonymous_2) +FN:45,(anonymous_3) +FN:56,(anonymous_4) +FN:64,(anonymous_5) +FN:79,(anonymous_6) +FN:93,(anonymous_7) +FN:96,(anonymous_8) +FN:97,(anonymous_9) +FN:109,getServiceInterfaces +FNF:11 +FNH:0 +FNDA:0,(anonymous_0) +FNDA:0,(anonymous_1) +FNDA:0,(anonymous_2) +FNDA:0,(anonymous_3) +FNDA:0,(anonymous_4) +FNDA:0,(anonymous_5) +FNDA:0,(anonymous_6) +FNDA:0,(anonymous_7) +FNDA:0,(anonymous_8) +FNDA:0,(anonymous_9) +FNDA:0,getServiceInterfaces +DA:2,5 +DA:8,5 +DA:17,0 +DA:22,0 +DA:24,0 +DA:25,0 +DA:30,0 +DA:31,0 +DA:33,0 +DA:39,0 +DA:40,0 +DA:46,0 +DA:47,0 +DA:52,0 +DA:55,5 +DA:57,0 +DA:58,0 +DA:65,0 +DA:66,0 +DA:68,0 +DA:74,0 +DA:80,0 +DA:82,0 +DA:87,0 +DA:94,0 +DA:95,0 +DA:96,0 +DA:97,0 +DA:98,0 +DA:100,0 +DA:105,0 +DA:109,5 +DA:113,0 +LF:33 +LH:4 +BRDA:30,0,0,0 +BRDA:46,1,0,0 +BRF:2 +BRH:0 +end_of_record +TN: +SF:lib/util/graph.ts +FN:16,(anonymous_0) +FN:17,(anonymous_1) +FN:47,(anonymous_2) +FN:51,gen +FN:60,(anonymous_4) +FN:74,(anonymous_5) +FN:80,rec +FN:89,(anonymous_7) +FN:90,(anonymous_8) +FN:106,(anonymous_9) +FN:123,(anonymous_10) +FN:129,rec +FN:138,(anonymous_12) +FN:139,(anonymous_13) +FN:155,(anonymous_14) +FN:172,(anonymous_15) +FN:183,(anonymous_16) +FN:186,check +FN:199,(anonymous_18) +FN:200,(anonymous_19) +FN:219,(anonymous_20) +FNF:21 +FNH:20 +FNDA:11,(anonymous_0) +FNDA:39,(anonymous_1) +FNDA:1,(anonymous_2) +FNDA:1,gen +FNDA:12,(anonymous_4) +FNDA:6,(anonymous_5) +FNDA:15,rec +FNDA:23,(anonymous_7) +FNDA:9,(anonymous_8) +FNDA:5,(anonymous_9) +FNDA:6,(anonymous_10) +FNDA:15,rec +FNDA:23,(anonymous_12) +FNDA:9,(anonymous_13) +FNDA:5,(anonymous_14) +FNDA:3,(anonymous_15) +FNDA:11,(anonymous_16) +FNDA:11,check +FNDA:12,(anonymous_18) +FNDA:8,(anonymous_19) +FNDA:0,(anonymous_20) +DA:14,5 +DA:15,11 +DA:22,39 +DA:26,39 +DA:27,20 +DA:32,20 +DA:33,20 +DA:35,39 +DA:36,1 +DA:41,1 +DA:42,1 +DA:44,39 +DA:45,39 +DA:50,1 +DA:52,1 +DA:53,4 +DA:54,1 +DA:58,1 +DA:65,12 +DA:70,12 +DA:71,12 +DA:72,12 +DA:79,6 +DA:83,15 +DA:84,1 +DA:86,14 +DA:87,14 +DA:88,14 +DA:89,23 +DA:90,9 +DA:91,14 +DA:92,16 +DA:93,16 +DA:94,16 +DA:95,18 +DA:96,18 +DA:97,9 +DA:98,9 +DA:104,6 +DA:105,5 +DA:106,5 +DA:107,5 +DA:108,15 +DA:109,15 +DA:110,15 +DA:111,15 +DA:112,15 +DA:113,10 +DA:114,10 +DA:120,1 +DA:128,6 +DA:132,15 +DA:133,1 +DA:135,14 +DA:136,14 +DA:137,14 +DA:138,23 +DA:139,9 +DA:140,14 +DA:141,16 +DA:142,16 +DA:143,16 +DA:144,18 +DA:145,18 +DA:146,9 +DA:147,9 +DA:153,6 +DA:154,5 +DA:155,5 +DA:156,5 +DA:157,15 +DA:158,15 +DA:159,15 +DA:160,15 +DA:161,15 +DA:162,10 +DA:163,10 +DA:169,1 +DA:181,3 +DA:183,11 +DA:184,3 +DA:185,3 +DA:190,11 +DA:191,3 +DA:193,8 +DA:194,0 +DA:196,8 +DA:197,8 +DA:198,6 +DA:199,12 +DA:200,8 +DA:201,6 +DA:202,11 +DA:203,11 +DA:204,11 +DA:205,13 +DA:206,13 +DA:207,6 +DA:208,6 +DA:211,7 +DA:212,7 +DA:218,3 +DA:219,0 +DA:220,0 +DA:221,0 +DA:222,0 +DA:223,0 +DA:224,0 +DA:225,0 +DA:226,0 +DA:227,0 +DA:230,0 +DA:235,3 +DA:236,3 +DA:237,11 +DA:238,11 +DA:239,3 +LF:117 +LH:106 +BRDA:53,0,0,1 +BRDA:83,1,0,1 +BRDA:96,2,0,9 +BRDA:104,3,0,5 +BRDA:104,3,1,1 +BRDA:112,4,0,10 +BRDA:132,5,0,1 +BRDA:145,6,0,9 +BRDA:153,7,0,5 +BRDA:153,7,1,1 +BRDA:161,8,0,10 +BRDA:181,9,0,0 +BRDA:181,9,1,3 +BRDA:190,10,0,3 +BRDA:193,11,0,0 +BRDA:206,12,0,6 +BRDA:206,12,1,7 +BRDA:207,13,0,6 +BRDA:218,14,0,0 +BRDA:218,14,1,3 +BRDA:225,15,0,0 +BRDA:225,15,1,0 +BRDA:226,16,0,0 +BRDA:238,17,0,3 +BRF:24 +BRH:18 +end_of_record +TN: +SF:lib/util/inMs.ts +FN:5,(anonymous_0) +FN:14,(anonymous_1) +FN:20,(anonymous_2) +FNF:3 +FNH:1 +FNDA:0,(anonymous_0) +FNDA:0,(anonymous_1) +FNDA:1,(anonymous_2) +DA:3,6 +DA:5,6 +DA:6,0 +DA:7,0 +DA:8,0 +DA:9,0 +DA:10,0 +DA:11,0 +DA:12,0 +DA:14,6 +DA:15,0 +DA:16,0 +DA:17,0 +DA:18,0 +DA:20,6 +DA:21,1 +DA:22,1 +DA:23,0 +DA:24,0 +DA:25,0 +DA:26,0 +DA:27,0 +DA:28,0 +DA:30,0 +LF:24 +LH:6 +BRDA:6,0,0,0 +BRDA:7,1,0,0 +BRDA:8,2,0,0 +BRDA:9,3,0,0 +BRDA:10,4,0,0 +BRDA:11,5,0,0 +BRDA:15,6,0,0 +BRDA:21,7,0,0 +BRDA:22,8,0,1 +BRDA:24,9,0,0 +BRDA:27,10,0,0 +BRDA:27,10,1,0 +BRF:12 +BRH:1 +end_of_record +TN: +SF:lib/util/index.ts +FN:9,(anonymous_4) +FN:9,(anonymous_5) +FN:10,(anonymous_6) +FN:11,(anonymous_7) +FN:12,(anonymous_8) +FN:13,(anonymous_9) +FN:15,(anonymous_10) +FN:16,(anonymous_11) +FNF:8 +FNH:0 +FNDA:0,(anonymous_4) +FNDA:0,(anonymous_5) +FNDA:0,(anonymous_6) +FNDA:0,(anonymous_7) +FNDA:0,(anonymous_8) +FNDA:0,(anonymous_9) +FNDA:0,(anonymous_10) +FNDA:0,(anonymous_11) +DA:1,5 +DA:2,5 +DA:3,5 +DA:4,5 +DA:5,5 +DA:6,5 +DA:7,5 +DA:9,5 +DA:10,5 +DA:11,5 +DA:12,5 +DA:13,5 +DA:14,5 +DA:15,5 +DA:16,5 +LF:15 +LH:15 +BRF:0 +BRH:0 +end_of_record +TN: +SF:lib/util/nullIfEmpty.ts +FN:7,nullIfEmpty +FNF:1 +FNH:0 +FNDA:0,nullIfEmpty +DA:7,5 +DA:10,0 +DA:11,0 +LF:3 +LH:1 +BRDA:10,0,0,0 +BRDA:11,1,0,0 +BRDA:11,1,1,0 +BRF:3 +BRH:0 +end_of_record +TN: +SF:lib/util/once.ts +FN:1,once +FN:3,(anonymous_1) +FNF:2 +FNH:2 +FNDA:26,once +FNDA:139,(anonymous_1) +DA:1,6 +DA:2,26 +DA:3,26 +DA:4,139 +DA:5,25 +DA:7,139 +LF:6 +LH:6 +BRDA:4,0,0,25 +BRF:1 +BRH:1 +end_of_record +TN: +SF:lib/util/patterns.ts +FNF:0 +FNH:0 +DA:2,5 +DA:4,5 +DA:9,5 +DA:14,5 +DA:19,5 +DA:24,5 +DA:29,5 +DA:34,5 +DA:39,5 +DA:44,5 +DA:50,5 +DA:55,5 +LF:12 +LH:12 +BRF:0 +BRH:0 +end_of_record +TN: +SF:lib/util/regexes.ts +FNF:0 +FNH:0 +DA:2,5 +DA:6,5 +DA:9,5 +DA:12,5 +DA:14,5 +DA:17,5 +DA:20,5 +DA:23,5 +DA:27,5 +DA:30,5 +DA:33,5 +LF:11 +LH:11 +BRF:0 +BRH:0 +end_of_record +TN: +SF:lib/util/splitCommand.ts +FN:3,(anonymous_0) +FNF:1 +FNH:0 +FNDA:0,(anonymous_0) +DA:1,5 +DA:3,5 +DA:6,0 +DA:7,0 +LF:4 +LH:2 +BRDA:6,0,0,0 +BRF:1 +BRH:0 +end_of_record +TN: +SF:lib/util/stringFromStdErrOut.ts +FN:1,stringFromStdErrOut +FNF:1 +FNH:0 +FNDA:0,stringFromStdErrOut +DA:1,6 +DA:5,0 +LF:2 +LH:1 +BRDA:5,0,0,0 +BRDA:5,0,1,0 +BRF:2 +BRH:0 +end_of_record +TN: +SF:lib/util/typeHelpers.ts +FN:11,(anonymous_0) +FN:106,test +FN:108,(anonymous_2) +FNF:3 +FNH:0 +FNDA:0,(anonymous_0) +FNDA:0,test +FNDA:0,(anonymous_2) +DA:11,5 +DA:12,0 +DA:108,0 +DA:113,0 +DA:115,0 +LF:5 +LH:1 +BRDA:12,0,0,0 +BRDA:12,0,1,0 +BRDA:12,0,2,0 +BRF:3 +BRH:0 +end_of_record +TN: +SF:lib/version/VersionGraph.ts +FN:13,(anonymous_0) +FN:17,(anonymous_1) +FN:43,(anonymous_2) +FN:93,(anonymous_3) +FN:110,(anonymous_4) +FN:113,(anonymous_5) +FN:122,(anonymous_6) +FN:134,(anonymous_7) +FN:138,(anonymous_8) +FN:154,(anonymous_9) +FN:157,(anonymous_10) +FN:164,(anonymous_11) +FN:173,(anonymous_12) +FN:176,(anonymous_13) +FN:183,(anonymous_14) +FNF:15 +FNH:10 +FNDA:5,(anonymous_0) +FNDA:5,(anonymous_1) +FNDA:0,(anonymous_2) +FNDA:0,(anonymous_3) +FNDA:5,(anonymous_4) +FNDA:5,(anonymous_5) +FNDA:0,(anonymous_6) +FNDA:0,(anonymous_7) +FNDA:0,(anonymous_8) +FNDA:5,(anonymous_9) +FNDA:15,(anonymous_10) +FNDA:10,(anonymous_11) +FNDA:5,(anonymous_12) +FNDA:15,(anonymous_13) +FNDA:10,(anonymous_14) +DA:1,4 +DA:4,4 +DA:5,4 +DA:6,4 +DA:8,4 +DA:14,5 +DA:17,5 +DA:18,5 +DA:32,5 +DA:33,5 +DA:34,5 +DA:35,5 +DA:36,5 +DA:37,5 +DA:38,5 +DA:40,5 +DA:42,5 +DA:43,5 +DA:53,5 +DA:54,5 +DA:55,5 +DA:57,5 +DA:58,0 +DA:59,0 +DA:63,5 +DA:65,5 +DA:66,5 +DA:69,5 +DA:71,5 +DA:72,0 +DA:73,0 +DA:77,5 +DA:79,5 +DA:80,5 +DA:83,5 +DA:84,0 +DA:85,0 +DA:86,0 +DA:87,0 +DA:92,0 +DA:94,0 +DA:97,0 +DA:107,5 +DA:110,5 +DA:111,5 +DA:120,5 +DA:131,0 +DA:132,0 +DA:133,0 +DA:135,0 +DA:139,0 +DA:142,0 +DA:143,0 +DA:144,0 +DA:145,0 +DA:147,0 +DA:149,0 +DA:152,0 +DA:154,5 +DA:155,5 +DA:158,15 +DA:165,10 +DA:173,5 +DA:174,5 +DA:177,15 +DA:184,10 +LF:66 +LH:43 +BRDA:36,0,0,5 +BRDA:36,0,1,5 +BRDA:37,1,0,5 +BRDA:55,2,0,5 +BRDA:57,3,0,0 +BRDA:57,3,1,5 +BRDA:69,4,0,5 +BRDA:71,5,0,0 +BRDA:71,5,1,5 +BRDA:83,6,0,0 +BRDA:94,7,0,0 +BRDA:94,7,1,0 +BRDA:132,8,0,0 +BRDA:132,9,0,0 +BRDA:132,9,1,0 +BRDA:135,10,0,0 +BRDA:135,10,1,0 +BRDA:135,10,2,0 +BRDA:135,10,3,0 +BRDA:139,11,0,0 +BRDA:139,11,1,0 +BRDA:139,11,2,0 +BRDA:139,11,3,0 +BRDA:142,12,0,0 +BRDA:144,13,0,0 +BRDA:158,14,0,15 +BRDA:158,14,1,10 +BRDA:158,14,2,15 +BRDA:158,14,3,5 +BRDA:166,15,0,5 +BRDA:166,15,1,5 +BRDA:177,16,0,15 +BRDA:177,16,1,10 +BRDA:177,16,2,15 +BRDA:177,16,3,5 +BRDA:185,17,0,5 +BRDA:185,17,1,5 +BRF:37 +BRH:19 +end_of_record +TN: +SF:lib/version/VersionInfo.ts +FN:34,(anonymous_0) +FN:37,(anonymous_1) +FN:41,(anonymous_2) +FN:51,__type_tests +FNF:4 +FNH:3 +FNDA:13,(anonymous_0) +FNDA:5,(anonymous_1) +FNDA:8,(anonymous_2) +FNDA:0,__type_tests +DA:4,4 +DA:32,4 +DA:33,13 +DA:35,13 +DA:38,5 +DA:44,8 +DA:52,0 +DA:62,0 +DA:64,0 +DA:66,0 +DA:72,0 +LF:11 +LH:6 +BRF:0 +BRH:0 +end_of_record diff --git a/sdk/lib/dependencies/DependencyConfig.ts b/sdk/lib/dependencies/DependencyConfig.ts deleted file mode 100644 index b48bf56d3..000000000 --- a/sdk/lib/dependencies/DependencyConfig.ts +++ /dev/null @@ -1,39 +0,0 @@ -import * as T from "../types" -import { deepEqual } from "../util/deepEqual" -import { deepMerge } from "../util/deepMerge" - -export type Update = (options: { - remoteConfig: RemoteConfig - queryResults: QueryResults -}) => Promise - -export class DependencyConfig< - Manifest extends T.Manifest, - Store, - Input extends Record, - RemoteConfig extends Record, -> { - static defaultUpdate = async (options: { - queryResults: unknown - remoteConfig: unknown - }): Promise => { - return deepMerge({}, options.remoteConfig, options.queryResults || {}) - } - constructor( - readonly dependencyConfig: (options: { - effects: T.Effects - localConfig: Input - }) => Promise>, - readonly update: Update< - void | T.DeepPartial, - RemoteConfig - > = DependencyConfig.defaultUpdate as any, - ) {} - - async query(options: { effects: T.Effects; localConfig: unknown }) { - return this.dependencyConfig({ - localConfig: options.localConfig as Input, - effects: options.effects, - }) - } -} diff --git a/sdk/lib/dependencies/setupDependencyConfig.ts b/sdk/lib/dependencies/setupDependencyConfig.ts deleted file mode 100644 index 2fde4bce5..000000000 --- a/sdk/lib/dependencies/setupDependencyConfig.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Config } from "../config/builder/config" - -import * as T from "../types" -import { DependencyConfig } from "./DependencyConfig" - -export function setupDependencyConfig< - Store, - Input extends Record, - Manifest extends T.Manifest, ->( - _config: Config | Config, - autoConfigs: { - [key in keyof Manifest["dependencies"] & string]: DependencyConfig< - Manifest, - Store, - Input, - any - > | null - }, -): T.ExpectedExports.dependencyConfig { - return autoConfigs -} diff --git a/sdk/lib/health/HealthReceipt.ts b/sdk/lib/health/HealthReceipt.ts deleted file mode 100644 index a0995ba0a..000000000 --- a/sdk/lib/health/HealthReceipt.ts +++ /dev/null @@ -1,4 +0,0 @@ -declare const HealthProof: unique symbol -export type HealthReceipt = { - [HealthProof]: never -} diff --git a/sdk/lib/health/index.ts b/sdk/lib/health/index.ts deleted file mode 100644 index b6e1d26f5..000000000 --- a/sdk/lib/health/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import "./checkFns" - -import "./HealthReceipt" diff --git a/sdk/lib/inits/setupInstall.ts b/sdk/lib/inits/setupInstall.ts deleted file mode 100644 index ab21380a0..000000000 --- a/sdk/lib/inits/setupInstall.ts +++ /dev/null @@ -1,25 +0,0 @@ -import * as T from "../types" - -export type InstallFn = (opts: { - effects: T.Effects -}) => Promise -export class Install { - private constructor(readonly fn: InstallFn) {} - static of( - fn: InstallFn, - ) { - return new Install(fn) - } - - async install({ effects }: Parameters[0]) { - await this.fn({ - effects, - }) - } -} - -export function setupInstall( - fn: InstallFn, -) { - return Install.of(fn) -} diff --git a/sdk/lib/inits/setupUninstall.ts b/sdk/lib/inits/setupUninstall.ts deleted file mode 100644 index 918f417e5..000000000 --- a/sdk/lib/inits/setupUninstall.ts +++ /dev/null @@ -1,29 +0,0 @@ -import * as T from "../types" - -export type UninstallFn = (opts: { - effects: T.Effects -}) => Promise -export class Uninstall { - private constructor(readonly fn: UninstallFn) {} - static of( - fn: UninstallFn, - ) { - return new Uninstall(fn) - } - - async uninstall({ - effects, - nextVersion, - }: Parameters[0]) { - if (!nextVersion) - await this.fn({ - effects, - }) - } -} - -export function setupUninstall( - fn: UninstallFn, -) { - return Uninstall.of(fn) -} diff --git a/sdk/lib/interfaces/setupInterfaces.ts b/sdk/lib/interfaces/setupInterfaces.ts deleted file mode 100644 index c82b69e0b..000000000 --- a/sdk/lib/interfaces/setupInterfaces.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Config } from "../config/builder/config" - -import * as T from "../types" -import { AddressReceipt } from "./AddressReceipt" - -export type InterfacesReceipt = Array -export type SetInterfaces< - Manifest extends T.Manifest, - Store, - ConfigInput extends Record, - Output extends InterfacesReceipt, -> = (opts: { effects: T.Effects; input: null | ConfigInput }) => Promise -export type SetupInterfaces = < - Manifest extends T.Manifest, - Store, - ConfigInput extends Record, - Output extends InterfacesReceipt, ->( - config: Config, - fn: SetInterfaces, -) => SetInterfaces -export const NO_INTERFACE_CHANGES = [] as InterfacesReceipt -export const setupInterfaces: SetupInterfaces = (_config, fn) => fn diff --git a/sdk/lib/manifest/ManifestTypes.ts b/sdk/lib/manifest/ManifestTypes.ts deleted file mode 100644 index cc564de2d..000000000 --- a/sdk/lib/manifest/ManifestTypes.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { ValidateExVer, ValidateExVers } from "../exver" -import { - ActionMetadata, - HardwareRequirements, - ImageConfig, - ImageId, - ImageSource, -} from "../types" - -export type SDKManifest = { - /** The package identifier used by the OS. This must be unique amongst all other known packages */ - readonly id: string - /** A human readable service title */ - readonly title: string - /** The type of license for the project. Include the LICENSE in the root of the project directory. A license is required for a Start9 package.*/ - readonly license: string // name of license - /** The Start9 wrapper repository URL for the package. This repo contains the manifest file (this), - * any scripts necessary for configuration, backups, actions, or health checks (more below). This key - * must exist. But could be embedded into the source repository - */ - readonly wrapperRepo: string - /** The original project repository URL. There is no upstream repo in this example */ - readonly upstreamRepo: string - /** URL to the support site / channel for the project. This key can be omitted if none exists, or it can link to the original project repository issues */ - readonly supportSite: string - /** URL to the marketing site for the project. If there is no marketing site, it can link to the original project repository */ - readonly marketingSite: string - /** URL where users can donate to the upstream project */ - readonly donationUrl: string | null - /**Human readable descriptions for the service. These are used throughout the StartOS user interface, primarily in the marketplace. */ - readonly description: { - /**This is the first description visible to the user in the marketplace */ - readonly short: string - /** This description will display with additional details in the service's individual marketplace page */ - readonly long: string - } - - /** Defines the os images needed to run the container processes */ - readonly images: Record - /** This denotes readonly asset directories that should be available to mount to the container. - * These directories are expected to be found in `assets/` at pack time. - **/ - readonly assets: string[] - /** This denotes any data volumes that should be available to mount to the container */ - readonly volumes: string[] - - readonly alerts?: { - readonly install?: string | null - readonly update?: string | null - readonly uninstall?: string | null - readonly restore?: string | null - readonly start?: string | null - readonly stop?: string | null - } - readonly hasConfig?: boolean - readonly dependencies: Readonly> - readonly hardwareRequirements?: { - readonly device?: { display?: RegExp; processor?: RegExp } - readonly ram?: number | null - readonly arch?: string[] | null - } -} - -export type SDKImageConfig = { - source: Exclude - arch?: string[] - emulateMissingAs?: string | null -} - -export type ManifestDependency = { - /** - * A human readable explanation on what the dependency is used for - */ - readonly description: string | null - /** - * Determines if the dependency is optional or not. Times that optional that are good include such situations - * such as being able to toggle other services or to use a different service for the same purpose. - */ - readonly optional: boolean - /** - * A url or local path for an s9pk that satisfies this dependency - */ - readonly s9pk: string -} diff --git a/sdk/lib/manifest/index.ts b/sdk/lib/manifest/index.ts deleted file mode 100644 index 806ef5e61..000000000 --- a/sdk/lib/manifest/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -import "./setupManifest" -import "./ManifestTypes" diff --git a/sdk/lib/osBindings/ImageSource.ts b/sdk/lib/osBindings/ImageSource.ts deleted file mode 100644 index a71684e46..000000000 --- a/sdk/lib/osBindings/ImageSource.ts +++ /dev/null @@ -1,6 +0,0 @@ -// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. - -export type ImageSource = - | "packed" - | { dockerBuild: { workdir: string | null; dockerfile: string | null } } - | { dockerTag: string } diff --git a/sdk/lib/osBindings/Status.ts b/sdk/lib/osBindings/Status.ts deleted file mode 100644 index b784f4d6a..000000000 --- a/sdk/lib/osBindings/Status.ts +++ /dev/null @@ -1,4 +0,0 @@ -// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -import type { MainStatus } from "./MainStatus" - -export type Status = { configured: boolean; main: MainStatus } diff --git a/sdk/lib/store/setupExposeStore.ts b/sdk/lib/store/setupExposeStore.ts deleted file mode 100644 index 9272a9a6b..000000000 --- a/sdk/lib/store/setupExposeStore.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Affine, _ } from "../util" -import { PathBuilder, extractJsonPath, pathBuilder } from "./PathBuilder" - -export type ExposedStorePaths = string[] & Affine<"ExposedStorePaths"> - -export const setupExposeStore = >( - fn: (pathBuilder: PathBuilder) => PathBuilder[], -) => { - return fn(pathBuilder()).map( - (x) => extractJsonPath(x) as string, - ) as ExposedStorePaths -} diff --git a/sdk/lib/test/output.sdk.ts b/sdk/lib/test/output.sdk.ts deleted file mode 100644 index 4cdf85111..000000000 --- a/sdk/lib/test/output.sdk.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { StartSdk } from "../StartSdk" -import { setupManifest } from "../manifest/setupManifest" -import { VersionInfo } from "../version/VersionInfo" -import { VersionGraph } from "../version/VersionGraph" - -export type Manifest = any -export const sdk = StartSdk.of() - .withManifest( - setupManifest( - VersionGraph.of( - VersionInfo.of({ - version: "1.0.0:0", - releaseNotes: "", - migrations: {}, - }) - .satisfies("#other:1.0.0:0") - .satisfies("#other:2.0.0:0"), - ), - { - id: "testOutput", - title: "", - license: "", - replaces: [], - wrapperRepo: "", - upstreamRepo: "", - supportSite: "", - marketingSite: "", - donationUrl: null, - description: { - short: "", - long: "", - }, - containers: {}, - images: {}, - volumes: [], - assets: [], - alerts: { - install: null, - update: null, - uninstall: null, - restore: null, - start: null, - stop: null, - }, - dependencies: { - "remote-test": { - description: "", - optional: false, - s9pk: "https://example.com/remote-test.s9pk", - }, - }, - }, - ), - ) - .withStore<{ storeRoot: { storeLeaf: "value" } }>() - .build(true) diff --git a/sdk/lib/test/output.ts b/sdk/lib/test/output.ts new file mode 100644 index 000000000..c8fa73600 --- /dev/null +++ b/sdk/lib/test/output.ts @@ -0,0 +1,377 @@ + +import { sdk } from "./output.sdk" +const {Config, List, Value, Variants} = sdk + +export const configSpec = Config.of({"mediasources": Value.multiselect({ + "name": "Media Sources", + "minLength": null, + "maxLength": null, + "default": [ + "nextcloud" + ], + "description": "List of Media Sources to use with Jellyfin", + "warning": null, + "values": { + "nextcloud": "NextCloud", + "filebrowser": "File Browser" + } +}),"testListUnion": Value.list(/* TODO: Convert range for this value ([1,*))*/List.obj({ + name:"Lightning Nodes", + minLength:null, + maxLength:null, + default: [], + description: "List of Lightning Network node instances to manage", + warning: null, + }, { + spec: + Config.of({ + "union": /* TODO: Convert range for this value ([1,*))*/ + Value.union({ + name: "Type", + description: "- LND: Lightning Network Daemon from Lightning Labs\n- CLN: Core Lightning from Blockstream\n", + warning: null, + required: {"default":"lnd"}, + }, Variants.of({"lnd": {name: "lnd", spec: Config.of({"name": Value.text({ + "name": "Node Name", + "required": { + "default": "LND Wrapper" + }, + "description": "Name of this node in the list", + "warning": null, + "masked": false, + "placeholder": null, + "inputmode": "text", + "patterns": [], + "minLength": null, + "maxLength": null +}),})},})) + + }) + , + displayAs: "{{name}}", + uniqueBy: "name", + })),"rpc": Value.object({ + name: "RPC Settings", + description: "RPC configuration options.", + warning: null, + }, Config.of({"enable": Value.toggle({ + "name": "Enable", + "default": true, + "description": "Allow remote RPC requests.", + "warning": null +}),"username": Value.text({ + "name": "Username", + "required": { + "default": "bitcoin" + }, + "description": "The username for connecting to Bitcoin over RPC.", + "warning": null, + "masked": true, + "placeholder": null, + "inputmode": "text", + "patterns": [ + { + "regex": "^[a-zA-Z0-9_]+$", + "description": "Must be alphanumeric (can contain underscore)." + } + ], + "minLength": null, + "maxLength": null +}),"password": Value.text({ + "name": "RPC Password", + "required": { + "default": { + "charset": "a-z,2-7", + "len": 20 + } + }, + "description": "The password for connecting to Bitcoin over RPC.", + "warning": null, + "masked": true, + "placeholder": null, + "inputmode": "text", + "patterns": [ + { + "regex": "^[^\\n\"]*$", + "description": "Must not contain newline or quote characters." + } + ], + "minLength": null, + "maxLength": null +}),"bio": Value.textarea({ + "name": "Username", + "description": "The username for connecting to Bitcoin over RPC.", + "warning": null, + "required": true, + "placeholder": null, + "maxLength": null, + "minLength": null +}),"advanced": Value.object({ + name: "Advanced", + description: "Advanced RPC Settings", + warning: null, + }, Config.of({"auth": Value.list(/* TODO: Convert range for this value ([0,*))*/List.text({ + "name": "Authorization", + "minLength": null, + "maxLength": null, + "default": [], + "description": "Username and hashed password for JSON-RPC connections. RPC clients connect using the usual http basic authentication.", + "warning": null +}, {"masked":false,"placeholder":null,"patterns":[{"regex":"^[a-zA-Z0-9_-]+:([0-9a-fA-F]{2})+\\$([0-9a-fA-F]{2})+$","description":"Each item must be of the form \":$\"."}],"minLength":null,"maxLength":null})),"serialversion": Value.select({ + "name": "Serialization Version", + "description": "Return raw transaction or block hex with Segwit or non-SegWit serialization.", + "warning": null, + "required": { + "default": "segwit" + }, + "values": { + "non-segwit": "non-segwit", + "segwit": "segwit" + } +} as const),"servertimeout": /* TODO: Convert range for this value ([5,300])*/Value.number({ + "name": "Rpc Server Timeout", + "description": "Number of seconds after which an uncompleted RPC call will time out.", + "warning": null, + "required": { + "default": 30 + }, + "min": null, + "max": null, + "step": null, + "integer": true, + "units": "seconds", + "placeholder": null +}),"threads": /* TODO: Convert range for this value ([1,64])*/Value.number({ + "name": "Threads", + "description": "Set the number of threads for handling RPC calls. You may wish to increase this if you are making lots of calls via an integration.", + "warning": null, + "required": { + "default": 16 + }, + "min": null, + "max": null, + "step": null, + "integer": true, + "units": null, + "placeholder": null +}),"workqueue": /* TODO: Convert range for this value ([8,256])*/Value.number({ + "name": "Work Queue", + "description": "Set the depth of the work queue to service RPC calls. Determines how long the backlog of RPC requests can get before it just rejects new ones.", + "warning": null, + "required": { + "default": 128 + }, + "min": null, + "max": null, + "step": null, + "integer": true, + "units": "requests", + "placeholder": null +}),})),})),"zmq-enabled": Value.toggle({ + "name": "ZeroMQ Enabled", + "default": true, + "description": "Enable the ZeroMQ interface", + "warning": null +}),"txindex": Value.toggle({ + "name": "Transaction Index", + "default": true, + "description": "Enable the Transaction Index (txindex)", + "warning": null +}),"wallet": Value.object({ + name: "Wallet", + description: "Wallet Settings", + warning: null, + }, Config.of({"enable": Value.toggle({ + "name": "Enable Wallet", + "default": true, + "description": "Load the wallet and enable wallet RPC calls.", + "warning": null +}),"avoidpartialspends": Value.toggle({ + "name": "Avoid Partial Spends", + "default": true, + "description": "Group outputs by address, selecting all or none, instead of selecting on a per-output basis. This improves privacy at the expense of higher transaction fees.", + "warning": null +}),"discardfee": /* TODO: Convert range for this value ([0,.01])*/Value.number({ + "name": "Discard Change Tolerance", + "description": "The fee rate (in BTC/kB) that indicates your tolerance for discarding change by adding it to the fee.", + "warning": null, + "required": { + "default": 0.0001 + }, + "min": null, + "max": null, + "step": null, + "integer": false, + "units": "BTC/kB", + "placeholder": null +}),})),"advanced": Value.object({ + name: "Advanced", + description: "Advanced Settings", + warning: null, + }, Config.of({"mempool": Value.object({ + name: "Mempool", + description: "Mempool Settings", + warning: null, + }, Config.of({"mempoolfullrbf": Value.toggle({ + "name": "Enable Full RBF", + "default": false, + "description": "Policy for your node to use for relaying and mining unconfirmed transactions. For details, see https://github.com/bitcoin/bitcoin/blob/master/doc/release-notes/release-notes-24.0.md#notice-of-new-option-for-transaction-replacement-policies", + "warning": null +}),"persistmempool": Value.toggle({ + "name": "Persist Mempool", + "default": true, + "description": "Save the mempool on shutdown and load on restart.", + "warning": null +}),"maxmempool": /* TODO: Convert range for this value ([1,*))*/Value.number({ + "name": "Max Mempool Size", + "description": "Keep the transaction memory pool below megabytes.", + "warning": null, + "required": { + "default": 300 + }, + "min": null, + "max": null, + "step": null, + "integer": true, + "units": "MiB", + "placeholder": null +}),"mempoolexpiry": /* TODO: Convert range for this value ([1,*))*/Value.number({ + "name": "Mempool Expiration", + "description": "Do not keep transactions in the mempool longer than hours.", + "warning": null, + "required": { + "default": 336 + }, + "min": null, + "max": null, + "step": null, + "integer": true, + "units": "Hr", + "placeholder": null +}),})),"peers": Value.object({ + name: "Peers", + description: "Peer Connection Settings", + warning: null, + }, Config.of({"listen": Value.toggle({ + "name": "Make Public", + "default": true, + "description": "Allow other nodes to find your server on the network.", + "warning": null +}),"onlyconnect": Value.toggle({ + "name": "Disable Peer Discovery", + "default": false, + "description": "Only connect to specified peers.", + "warning": null +}),"onlyonion": Value.toggle({ + "name": "Disable Clearnet", + "default": false, + "description": "Only connect to peers over Tor.", + "warning": null +}),"addnode": Value.list(/* TODO: Convert range for this value ([0,*))*/List.obj({ + name: "Add Nodes", + minLength: null, + maxLength: null, + default: [], + description: "Add addresses of nodes to connect to.", + warning: null, + }, { + spec: Config.of({"hostname": Value.text({ + "name": "Hostname", + "required": false, + "description": "Domain or IP address of bitcoin peer", + "warning": null, + "masked": false, + "placeholder": null, + "inputmode": "text", + "patterns": [ + { + "regex": "(^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$)|((^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$)|(^[a-z2-7]{16}\\.onion$)|(^([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]$))", + "description": "Must be either a domain name, or an IPv4 or IPv6 address. Do not include protocol scheme (eg 'http://') or port." + } + ], + "minLength": null, + "maxLength": null +}),"port": /* TODO: Convert range for this value ([0,65535])*/Value.number({ + "name": "Port", + "description": "Port that peer is listening on for inbound p2p connections", + "warning": null, + "required": false, + "min": null, + "max": null, + "step": null, + "integer": true, + "units": null, + "placeholder": null +}),}), + displayAs: null, + uniqueBy: null, + })),})),"dbcache": /* TODO: Convert range for this value ((0,*))*/Value.number({ + "name": "Database Cache", + "description": "How much RAM to allocate for caching the TXO set. Higher values improve syncing performance, but increase your chance of using up all your system's memory or corrupting your database in the event of an ungraceful shutdown. Set this high but comfortably below your system's total RAM during IBD, then turn down to 450 (or leave blank) once the sync completes.", + "warning": "WARNING: Increasing this value results in a higher chance of ungraceful shutdowns, which can leave your node unusable if it happens during the initial block download. Use this setting with caution. Be sure to set this back to the default (450 or leave blank) once your node is synced. DO NOT press the STOP button if your dbcache is large. Instead, set this number back to the default, hit save, and wait for bitcoind to restart on its own.", + "required": false, + "min": null, + "max": null, + "step": null, + "integer": true, + "units": "MiB", + "placeholder": null +}),"pruning": Value.union({ + name: "Pruning Settings", + description: "- Disabled: Disable pruning\n- Automatic: Limit blockchain size on disk to a certain number of megabytes\n- Manual: Prune blockchain with the \"pruneblockchain\" RPC\n", + warning: null, + + // prettier-ignore + required: {"default":"disabled"}, + }, Variants.of({"disabled": {name: "Disabled", spec: Config.of({})},"automatic": {name: "Automatic", spec: Config.of({"size": /* TODO: Convert range for this value ([550,1000000))*/Value.number({ + "name": "Max Chain Size", + "description": "Limit of blockchain size on disk.", + "warning": "Increasing this value will require re-syncing your node.", + "required": { + "default": 550 + }, + "min": null, + "max": null, + "step": null, + "integer": true, + "units": "MiB", + "placeholder": null +}),})},"manual": {name: "Manual", spec: Config.of({"size": /* TODO: Convert range for this value ([550,1000000))*/Value.number({ + "name": "Failsafe Chain Size", + "description": "Prune blockchain if size expands beyond this.", + "warning": null, + "required": { + "default": 65536 + }, + "min": null, + "max": null, + "step": null, + "integer": true, + "units": "MiB", + "placeholder": null +}),})},})),"blockfilters": Value.object({ + name: "Block Filters", + description: "Settings for storing and serving compact block filters", + warning: null, + }, Config.of({"blockfilterindex": Value.toggle({ + "name": "Compute Compact Block Filters (BIP158)", + "default": true, + "description": "Generate Compact Block Filters during initial sync (IBD) to enable 'getblockfilter' RPC. This is useful if dependent services need block filters to efficiently scan for addresses/transactions etc.", + "warning": null +}),"peerblockfilters": Value.toggle({ + "name": "Serve Compact Block Filters to Peers (BIP157)", + "default": false, + "description": "Serve Compact Block Filters as a peer service to other nodes on the network. This is useful if you wish to connect an SPV client to your node to make it efficient to scan transactions without having to download all block data. 'Compute Compact Block Filters (BIP158)' is required.", + "warning": null +}),})),"bloomfilters": Value.object({ + name: "Bloom Filters (BIP37)", + description: "Setting for serving Bloom Filters", + warning: null, + }, Config.of({"peerbloomfilters": Value.toggle({ + "name": "Serve Bloom Filters to Peers", + "default": false, + "description": "Peers have the option of setting filters on each connection they make after the version handshake has completed. Bloom filters are for clients implementing SPV (Simplified Payment Verification) that want to check that block headers connect together correctly, without needing to verify the full blockchain. The client must trust that the transactions in the chain are in fact valid. It is highly recommended AGAINST using for anything except Bisq integration.", + "warning": "This is ONLY for use with Bisq integration, please use Block Filters for all other applications." +}),})),})),}); +export const matchConfigSpec = configSpec.validator; +export type ConfigSpec = typeof matchConfigSpec._TYPE; \ No newline at end of file diff --git a/sdk/lib/test/setupDependencyConfig.test.ts b/sdk/lib/test/setupDependencyConfig.test.ts deleted file mode 100644 index 622559eb6..000000000 --- a/sdk/lib/test/setupDependencyConfig.test.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { sdk } from "./output.sdk" - -describe("setupDependencyConfig", () => { - test("test", () => { - const testConfig = sdk.Config.of({ - test: sdk.Value.text({ - name: "testValue", - required: false, - }), - }) - - const testConfig2 = sdk.Config.of({ - test2: sdk.Value.text({ - name: "testValue2", - required: false, - }), - }) - const remoteTest = sdk.DependencyConfig.of({ - localConfigSpec: testConfig, - remoteConfigSpec: testConfig2, - dependencyConfig: async ({}) => {}, - }) - sdk.setupDependencyConfig(testConfig, { - "remote-test": remoteTest, - }) - }) -}) diff --git a/sdk/lib/types.ts b/sdk/lib/types.ts deleted file mode 100644 index 4820f419d..000000000 --- a/sdk/lib/types.ts +++ /dev/null @@ -1,520 +0,0 @@ -export * as configTypes from "./config/configTypes" - -import { - DependencyRequirement, - SetHealth, - NamedHealthCheckResult, - SetMainStatus, - ServiceInterface, - Host, - ExportServiceInterfaceParams, - GetPrimaryUrlParams, - LanInfo, - BindParams, - Manifest, - CheckDependenciesResult, - ActionId, - HostId, -} from "./osBindings" - -import { MainEffects, ServiceInterfaceType, Signals } from "./StartSdk" -import { InputSpec } from "./config/configTypes" -import { DependenciesReceipt } from "./config/setupConfig" -import { BindOptions, Scheme } from "./interfaces/Host" -import { Daemons } from "./mainFn/Daemons" -import { StorePath } from "./store/PathBuilder" -import { ExposedStorePaths } from "./store/setupExposeStore" -import { UrlString } from "./util/getServiceInterface" -import { StringObject, ToKebab } from "./util" -export * from "./osBindings" -export { SDKManifest } from "./manifest/ManifestTypes" -export { HealthReceipt } from "./health/HealthReceipt" - -export type PathMaker = (options: { volume: string; path: string }) => string -export type ExportedAction = (options: { - effects: Effects - input?: Record -}) => Promise -export type MaybePromise = Promise | A -export namespace ExpectedExports { - version: 1 - /** Set configuration is called after we have modified and saved the configuration in the start9 ui. Use this to make a file for the docker to read from for configuration. */ - export type setConfig = (options: { - effects: Effects - input: Record - }) => Promise - /** Get configuration returns a shape that describes the format that the start9 ui will generate, and later send to the set config */ - export type getConfig = (options: { effects: Effects }) => Promise - // /** These are how we make sure the our dependency configurations are valid and if not how to fix them. */ - // export type dependencies = Dependencies; - /** For backing up service data though the startOS UI */ - export type createBackup = (options: { - effects: Effects - pathMaker: PathMaker - }) => Promise - /** For restoring service data that was previously backed up using the startOS UI create backup flow. Backup restores are also triggered via the startOS UI, or doing a system restore flow during setup. */ - export type restoreBackup = (options: { - effects: Effects - pathMaker: PathMaker - }) => Promise - - // /** Health checks are used to determine if the service is working properly after starting - // * A good use case is if we are using a web server, seeing if we can get to the web server. - // */ - // export type health = { - // /** Should be the health check id */ - // [id: string]: (options: { effects: Effects; input: TimeMs }) => Promise; - // }; - - /** - * Actions are used so we can effect the service, like deleting a directory. - * One old use case is to add a action where we add a file, that will then be run during the - * service starting, and that file would indicate that it would rescan all the data. - */ - export type actions = (options: { effects: Effects }) => MaybePromise<{ - [id: string]: { - run: ExportedAction - getConfig: (options: { effects: Effects }) => Promise - } - }> - - export type actionsMetadata = (options: { - effects: Effects - }) => Promise> - - /** - * This is the entrypoint for the main container. Used to start up something like the service that the - * package represents, like running a bitcoind in a bitcoind-wrapper. - */ - export type main = (options: { - effects: MainEffects - started(onTerm: () => PromiseLike): PromiseLike - }) => Promise> - - /** - * After a shutdown, if we wanted to do any operations to clean up things, like - * set the action as unavailable or something. - */ - export type afterShutdown = (options: { - effects: Effects - }) => Promise - - /** - * Every time a package completes an install, this function is called before the main. - * Can be used to do migration like things. - */ - export type init = (options: { effects: Effects }) => Promise - /** This will be ran during any time a package is uninstalled, for example during a update - * this will be called. - */ - export type uninit = (options: { - effects: Effects - nextVersion: null | string - }) => Promise - - /** Auto configure is used to make sure that other dependencies have the values t - * that this service could use. - */ - export type dependencyConfig = Record - - export type properties = (options: { - effects: Effects - }) => Promise - - export type manifest = Manifest -} -export type ABI = { - setConfig: ExpectedExports.setConfig - getConfig: ExpectedExports.getConfig - createBackup: ExpectedExports.createBackup - restoreBackup: ExpectedExports.restoreBackup - actions: ExpectedExports.actions - actionsMetadata: ExpectedExports.actionsMetadata - main: ExpectedExports.main - afterShutdown: ExpectedExports.afterShutdown - init: ExpectedExports.init - uninit: ExpectedExports.uninit - dependencyConfig: ExpectedExports.dependencyConfig - properties: ExpectedExports.properties - manifest: ExpectedExports.manifest -} -export type TimeMs = number -export type VersionString = string - -/** - * AutoConfigure is used as the value to the key of package id, - * this is used to make sure that other dependencies have the values that this service could use. - */ -export type DependencyConfig = { - /** During autoconfigure, we have access to effects and local data. We are going to figure out all the data that we need and send it to update. For the sdk it is the desired delta */ - query(options: { effects: Effects }): Promise - /** This is the second part. Given the query results off the previous function, we will determine what to change the remote config to. In our sdk normall we are going to use the previous as a deep merge. */ - update(options: { - queryResults: unknown - remoteConfig: unknown - }): Promise -} - -export type ConfigRes = { - /** This should be the previous config, that way during set config we start with the previous */ - config?: null | Record - /** Shape that is describing the form in the ui */ - spec: InputSpec -} - -declare const DaemonProof: unique symbol -export type DaemonReceipt = { - [DaemonProof]: never -} -export type Daemon = { - wait(): Promise - term(): Promise - [DaemonProof]: never -} - -export type HealthStatus = NamedHealthCheckResult["result"] -export type SmtpValue = { - server: string - port: number - from: string - login: string - password: string | null | undefined -} - -export type CommandType = string | [string, ...string[]] - -export type DaemonReturned = { - wait(): Promise - term(options?: { signal?: Signals; timeout?: number }): Promise -} - -export type ActionMetadata = { - name: string - description: string - warning: string | null - input: InputSpec - disabled: boolean - allowedStatuses: "onlyRunning" | "onlyStopped" | "any" - /** - * So the ordering of the actions is by alphabetical order of the group, then followed by the alphabetical of the actions - */ - group: string | null -} -export declare const hostName: unique symbol -// asdflkjadsf.onion | 1.2.3.4 -export type Hostname = string & { [hostName]: never } - -export type HostnameInfoIp = { - kind: "ip" - networkInterfaceId: string - public: boolean - hostname: - | { - kind: "ipv4" | "ipv6" | "local" - value: string - port: number | null - sslPort: number | null - } - | { - kind: "domain" - domain: string - subdomain: string | null - port: number | null - sslPort: number | null - } -} - -export type HostnameInfoOnion = { - kind: "onion" - hostname: { value: string; port: number | null; sslPort: number | null } -} - -export type HostnameInfo = HostnameInfoIp | HostnameInfoOnion - -export type ServiceInterfaceId = string - -export { ServiceInterface } -export type ExposeServicePaths = { - /** The path to the value in the Store. [JsonPath](https://jsonpath.com/) */ - paths: ExposedStorePaths -} - -export type SdkPropertiesValue = - | { - type: "object" - value: { [k: string]: SdkPropertiesValue } - description?: string - } - | { - type: "string" - /** The value to display to the user */ - value: string - /** A human readable description or explanation of the value */ - description?: string - /** Whether or not to mask the value, for example, when displaying a password */ - masked: boolean - /** Whether or not to include a button for copying the value to clipboard */ - copyable?: boolean - /** Whether or not to include a button for displaying the value as a QR code */ - qr?: boolean - } - -export type SdkPropertiesReturn = { - [key: string]: SdkPropertiesValue -} - -export type PropertiesValue = - | { - type: "object" - value: { [k: string]: PropertiesValue } - description: string | null - } - | { - type: "string" - /** The value to display to the user */ - value: string - /** A human readable description or explanation of the value */ - description: string | null - /** Whether or not to mask the value, for example, when displaying a password */ - masked: boolean - /** Whether or not to include a button for copying the value to clipboard */ - copyable: boolean | null - /** Whether or not to include a button for displaying the value as a QR code */ - qr: boolean | null - } - -export type PropertiesReturn = { - [key: string]: PropertiesValue -} - -export type EffectMethod = { - [K in keyof T]-?: K extends string - ? T[K] extends Function - ? ToKebab - : T[K] extends StringObject - ? `${ToKebab}.${EffectMethod}` - : never - : never -}[keyof T] - -/** Used to reach out from the pure js runtime */ -export type Effects = { - // action - - /** Run an action exported by a service */ - executeAction(opts: { - packageId?: PackageId - actionId: ActionId - input: Input - }): Promise - /** Define an action that can be invoked by a user or service */ - exportAction(options: { - id: ActionId - metadata: ActionMetadata - }): Promise - /** Remove all exported actions */ - clearActions(): Promise - - // config - - /** Returns whether or not the package has been configured */ - getConfigured(options: { packageId?: PackageId }): Promise - /** Indicates that this package has been configured. Called during setConfig or init */ - setConfigured(options: { configured: boolean }): Promise - - // control - - /** restart this service's main function */ - restart(): Promise - /** stop this service's main function */ - shutdown(): Promise - /** indicate to the host os what runstate the service is in */ - setMainStatus(options: SetMainStatus): Promise - - // dependency - - /** Set the dependencies of what the service needs, usually run during the set config as a best practice */ - setDependencies(options: { - dependencies: Dependencies - }): Promise - /** Get the list of the dependencies, both the dynamic set by the effect of setDependencies and the end result any required in the manifest */ - getDependencies(): Promise - /** Test whether current dependency requirements are satisfied */ - checkDependencies(options: { - packageIds?: PackageId[] - }): Promise - /** mount a volume of a dependency */ - mount(options: { - location: string - target: { - packageId: string - volumeId: string - subpath: string | null - readonly: boolean - } - }): Promise - /** Returns a list of the ids of all installed packages */ - getInstalledPackages(): Promise - /** grants access to certain paths in the store to dependents */ - exposeForDependents(options: { paths: string[] }): Promise - - // health - - /** sets the result of a health check */ - setHealth(o: SetHealth): Promise - - // subcontainer - subcontainer: { - /** A low level api used by SubContainer */ - createFs(options: { imageId: string }): Promise<[string, string]> - /** A low level api used by SubContainer */ - destroyFs(options: { guid: string }): Promise - } - - // net - - // bind - /** Creates a host connected to the specified port with the provided options */ - bind(options: BindParams): Promise - /** Get the port address for a service */ - getServicePortForward(options: { - packageId?: PackageId - hostId: HostId - internalPort: number - }): Promise - /** Removes all network bindings, called in the setupConfig */ - clearBindings(): Promise - // host - /** Returns information about the specified host, if it exists */ - getHostInfo(options: { - packageId?: PackageId - hostId: HostId - callback?: () => void - }): Promise - /** Returns the primary url that a user has selected for a host, if it exists */ - getPrimaryUrl(options: { - packageId?: PackageId - hostId: HostId - callback?: () => void - }): Promise - /** Returns the IP address of the container */ - getContainerIp(): Promise - // interface - /** Creates an interface bound to a specific host and port to show to the user */ - exportServiceInterface(options: ExportServiceInterfaceParams): Promise - /** Returns an exported service interface */ - getServiceInterface(options: { - packageId?: PackageId - serviceInterfaceId: ServiceInterfaceId - callback?: () => void - }): Promise - /** Returns all exported service interfaces for a package */ - listServiceInterfaces(options: { - packageId?: PackageId - callback?: () => void - }): Promise> - /** Removes all service interfaces */ - clearServiceInterfaces(): Promise - // ssl - /** Returns a PEM encoded fullchain for the hostnames specified */ - getSslCertificate: (options: { - hostnames: string[] - algorithm?: "ecdsa" | "ed25519" - callback?: () => void - }) => Promise<[string, string, string]> - /** Returns a PEM encoded private key corresponding to the certificate for the hostnames specified */ - getSslKey: (options: { - hostnames: string[] - algorithm?: "ecdsa" | "ed25519" - }) => Promise - - // store - - store: { - /** Get a value in a json like data, can be observed and subscribed */ - get(options: { - /** If there is no packageId it is assumed the current package */ - packageId?: string - /** The path defaults to root level, using the [JsonPath](https://jsonpath.com/) */ - path: StorePath - callback?: () => void - }): Promise - /** Used to store values that can be accessed and subscribed to */ - set(options: { - /** Sets the value for the wrapper at the path, it will override, using the [JsonPath](https://jsonpath.com/) */ - path: StorePath - value: ExtractStore - }): Promise - } - /** sets the version that this service's data has been migrated to */ - setDataVersion(options: { version: string }): Promise - /** returns the version that this service's data has been migrated to */ - getDataVersion(): Promise - - // system - - /** Returns globally configured SMTP settings, if they exist */ - getSystemSmtp(options: { callback?: () => void }): Promise -} - -/** rsync options: https://linux.die.net/man/1/rsync - */ -export type BackupOptions = { - delete: boolean - force: boolean - ignoreExisting: boolean - exclude: string[] -} -/** - * This is the metadata that is returned from the metadata call. - */ -export type Metadata = { - fileType: string - isDir: boolean - isFile: boolean - isSymlink: boolean - len: number - modified?: Date - accessed?: Date - created?: Date - readonly: boolean - uid: number - gid: number - mode: number -} - -export type MigrationRes = { - configured: boolean -} - -export type ActionResult = { - version: "0" - message: string - value: string | null - copyable: boolean - qr: boolean -} -export type SetResult = { - dependsOn: DependsOn - signal: Signals -} - -export type PackageId = string -export type Message = string -export type DependencyKind = "running" | "exists" - -export type DependsOn = { - [packageId: string]: string[] | readonly string[] -} - -export type KnownError = - | { error: string } - | { - errorCode: [number, string] | readonly [number, string] - } - -export type Dependencies = Array - -export type DeepPartial = T extends {} - ? { [P in keyof T]?: DeepPartial } - : T diff --git a/sdk/lib/util/asError.ts b/sdk/lib/util/asError.ts deleted file mode 100644 index 6e98afb6a..000000000 --- a/sdk/lib/util/asError.ts +++ /dev/null @@ -1,6 +0,0 @@ -export const asError = (e: unknown) => { - if (e instanceof Error) { - return new Error(e as any) - } - return new Error(`${e}`) -} diff --git a/sdk/lib/util/deepMerge.ts b/sdk/lib/util/deepMerge.ts deleted file mode 100644 index ae68c242f..000000000 --- a/sdk/lib/util/deepMerge.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { object } from "ts-matches" - -export function deepMerge(...args: unknown[]): unknown { - const lastItem = (args as any)[args.length - 1] - if (!object.test(lastItem)) return lastItem - const objects = args.filter(object.test).filter((x) => !Array.isArray(x)) - if (objects.length === 0) return lastItem as any - if (objects.length === 1) objects.unshift({}) - const allKeys = new Set(objects.flatMap((x) => Object.keys(x))) - for (const key of allKeys) { - const filteredValues = objects.flatMap((x) => - key in x ? [(x as any)[key]] : [], - ) - ;(objects as any)[0][key] = deepMerge(...filteredValues) - } - return objects[0] as any -} diff --git a/sdk/lib/util/fileHelper.ts b/sdk/lib/util/fileHelper.ts deleted file mode 100644 index 383b4fd31..000000000 --- a/sdk/lib/util/fileHelper.ts +++ /dev/null @@ -1,150 +0,0 @@ -import * as matches from "ts-matches" -import * as YAML from "yaml" -import * as TOML from "@iarna/toml" -import merge from "lodash.merge" -import * as T from "../types" -import * as fs from "node:fs/promises" - -const previousPath = /(.+?)\/([^/]*)$/ - -/** - * Used in the get config and the set config exported functions. - * The idea is that we are going to be reading/ writing to a file, or multiple files. And then we use this tool - * to keep the same path on the read and write, and have methods for helping with structured data. - * And if we are not using a structured data, we can use the raw method which forces the construction of a BiMap - * ```ts - import {InputSpec} from './InputSpec.ts' - import {matches, T} from '../deps.ts'; - const { object, string, number, boolean, arrayOf, array, anyOf, allOf } = matches - const someValidator = object({ - data: string - }) - const jsonFile = FileHelper.json({ - path: 'data.json', - validator: someValidator, - volume: 'main' - }) - const tomlFile = FileHelper.toml({ - path: 'data.toml', - validator: someValidator, - volume: 'main' - }) - const rawFile = FileHelper.raw({ - path: 'data.amazingSettings', - volume: 'main' - fromData(dataIn: Data): string { - return `myDatais ///- ${dataIn.data}` - }, - toData(rawData: string): Data { - const [,data] = /myDatais \/\/\/- (.*)/.match(rawData) - return {data} - } - }) - - export const setConfig : T.ExpectedExports.setConfig= async (effects, config) => { - await jsonFile.write({ data: 'here lies data'}, effects) - } - - export const getConfig: T.ExpectedExports.getConfig = async (effects, config) => ({ - spec: InputSpec, - config: nullIfEmpty({ - ...jsonFile.get(effects) - }) - ``` - */ -export class FileHelper { - protected constructor( - readonly path: string, - readonly writeData: (dataIn: A) => string, - readonly readData: (stringValue: string) => A, - ) {} - async write(data: A, effects: T.Effects) { - const parent = previousPath.exec(this.path) - if (parent) { - await fs.mkdir(parent[1], { recursive: true }) - } - - await fs.writeFile(this.path, this.writeData(data)) - } - async read(effects: T.Effects) { - if ( - !(await fs.access(this.path).then( - () => true, - () => false, - )) - ) { - return null - } - return this.readData( - await fs.readFile(this.path).then((data) => data.toString("utf-8")), - ) - } - - async merge(data: A, effects: T.Effects) { - const fileData = (await this.read(effects).catch(() => ({}))) || {} - const mergeData = merge({}, fileData, data) - return await this.write(mergeData, effects) - } - /** - * Create a File Helper for an arbitrary file type. - * - * Provide custom functions for translating data to the file format and visa versa. - */ - static raw( - path: string, - toFile: (dataIn: A) => string, - fromFile: (rawData: string) => A, - ) { - return new FileHelper(path, toFile, fromFile) - } - /** - * Create a File Helper for a .json file - */ - static json(path: string, shape: matches.Validator) { - return new FileHelper( - path, - (inData) => { - return JSON.stringify(inData, null, 2) - }, - (inString) => { - return shape.unsafeCast(JSON.parse(inString)) - }, - ) - } - /** - * Create a File Helper for a .toml file - */ - static toml>( - path: string, - shape: matches.Validator, - ) { - return new FileHelper( - path, - (inData) => { - return TOML.stringify(inData as any) - }, - (inString) => { - return shape.unsafeCast(TOML.parse(inString)) - }, - ) - } - /** - * Create a File Helper for a .yaml file - */ - static yaml>( - path: string, - shape: matches.Validator, - ) { - return new FileHelper( - path, - (inData) => { - return YAML.stringify(inData, null, 2) - }, - (inString) => { - return shape.unsafeCast(YAML.parse(inString)) - }, - ) - } -} - -export default FileHelper diff --git a/sdk/lib/util/index.browser.ts b/sdk/lib/util/index.browser.ts deleted file mode 100644 index 94339e7f7..000000000 --- a/sdk/lib/util/index.browser.ts +++ /dev/null @@ -1,10 +0,0 @@ -import * as T from "../types" - -/// Currently being used -export { addressHostToUrl } from "./getServiceInterface" -export { getDefaultString } from "./getDefaultString" - -/// Not being used, but known to be browser compatible -export { GetServiceInterface, getServiceInterface } from "./getServiceInterface" -export { getServiceInterfaces } from "./getServiceInterfaces" -export * from "./typeHelpers" diff --git a/sdk/lib/util/index.ts b/sdk/lib/util/index.ts deleted file mode 100644 index 9246cf791..000000000 --- a/sdk/lib/util/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -import "./nullIfEmpty" -import "./fileHelper" -import "../store/getStore" -import "./deepEqual" -import "./deepMerge" -import "./SubContainer" -import "./once" - -export { GetServiceInterface, getServiceInterface } from "./getServiceInterface" -export { asError } from "./asError" -export { getServiceInterfaces } from "./getServiceInterfaces" -export { addressHostToUrl } from "./getServiceInterface" -export { hostnameInfoToAddress } from "./Hostname" -export * from "./typeHelpers" -export { getDefaultString } from "./getDefaultString" -export { inMs } from "./inMs" diff --git a/sdk/lib/util/nullIfEmpty.ts b/sdk/lib/util/nullIfEmpty.ts deleted file mode 100644 index 337b9098f..000000000 --- a/sdk/lib/util/nullIfEmpty.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** - * A useful tool when doing a getConfig. - * Look into the config {@link FileHelper} for an example of the use. - * @param s - * @returns - */ -export default function nullIfEmpty>( - s: null | A, -) { - if (s === null) return null - return Object.keys(s).length === 0 ? null : s -} diff --git a/sdk/node_modules/.package-lock.json b/sdk/node_modules/.package-lock.json new file mode 100644 index 000000000..9699e0851 --- /dev/null +++ b/sdk/node_modules/.package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "sdk", + "lockfileVersion": 3, + "requires": true, + "packages": {} +} diff --git a/sdk/package/.gitignore b/sdk/package/.gitignore new file mode 100644 index 000000000..a7ca92b2d --- /dev/null +++ b/sdk/package/.gitignore @@ -0,0 +1,5 @@ +.vscode +dist/ +node_modules/ +lib/coverage +lib/test/output.ts \ No newline at end of file diff --git a/sdk/package/.npmignore b/sdk/package/.npmignore new file mode 100644 index 000000000..40b878db5 --- /dev/null +++ b/sdk/package/.npmignore @@ -0,0 +1 @@ +node_modules/ \ No newline at end of file diff --git a/sdk/package/.prettierignore b/sdk/package/.prettierignore new file mode 100644 index 000000000..19b24bbe8 --- /dev/null +++ b/sdk/package/.prettierignore @@ -0,0 +1 @@ +/lib/exver/exver.ts \ No newline at end of file diff --git a/sdk/package/LICENSE b/sdk/package/LICENSE new file mode 100644 index 000000000..793257b96 --- /dev/null +++ b/sdk/package/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Start9 Labs + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/sdk/README.md b/sdk/package/README.md similarity index 100% rename from sdk/README.md rename to sdk/package/README.md diff --git a/sdk/package/jest.config.js b/sdk/package/jest.config.js new file mode 100644 index 000000000..c38fa5062 --- /dev/null +++ b/sdk/package/jest.config.js @@ -0,0 +1,8 @@ +/** @type {import('ts-jest').JestConfigWithTsJest} */ +module.exports = { + preset: "ts-jest", + automock: false, + testEnvironment: "node", + rootDir: "./lib/", + modulePathIgnorePatterns: ["./dist/"], +} diff --git a/sdk/package/lib/StartSdk.ts b/sdk/package/lib/StartSdk.ts new file mode 100644 index 000000000..634af249d --- /dev/null +++ b/sdk/package/lib/StartSdk.ts @@ -0,0 +1,1369 @@ +import { Value } from "../../base/lib/actions/input/builder/value" +import { + InputSpec, + ExtractInputSpecType, + LazyBuild, +} from "../../base/lib/actions/input/builder/inputSpec" +import { + DefaultString, + ListValueSpecText, + Pattern, + RandomString, + UniqueBy, + ValueSpecDatetime, + ValueSpecText, +} from "../../base/lib/actions/input/inputSpecTypes" +import { Variants } from "../../base/lib/actions/input/builder/variants" +import { Action, Actions } from "../../base/lib/actions/setupActions" +import { + SyncOptions, + ServiceInterfaceId, + PackageId, + HealthReceipt, + ServiceInterfaceType, + Effects, +} from "../../base/lib/types" +import * as patterns from "../../base/lib/util/patterns" +import { BackupSync, Backups } from "./backup/Backups" +import { smtpInputSpec } from "../../base/lib/actions/input/inputSpecConstants" +import { Daemons } from "./mainFn/Daemons" +import { healthCheck, HealthCheckParams } from "./health/HealthCheck" +import { checkPortListening } from "./health/checkFns/checkPortListening" +import { checkWebUrl, runHealthScript } from "./health/checkFns" +import { List } from "../../base/lib/actions/input/builder/list" +import { Install, InstallFn } from "./inits/setupInstall" +import { SetupBackupsParams, setupBackups } from "./backup/setupBackups" +import { Uninstall, UninstallFn, setupUninstall } from "./inits/setupUninstall" +import { setupMain } from "./mainFn" +import { defaultTrigger } from "./trigger/defaultTrigger" +import { changeOnFirstSuccess, cooldownTrigger } from "./trigger" +import { + ServiceInterfacesReceipt, + UpdateServiceInterfaces, + setupServiceInterfaces, +} from "../../base/lib/interfaces/setupInterfaces" +import { successFailure } from "./trigger/successFailure" +import { MultiHost, Scheme } from "../../base/lib/interfaces/Host" +import { ServiceInterfaceBuilder } from "../../base/lib/interfaces/ServiceInterfaceBuilder" +import { GetSystemSmtp } from "./util" +import { nullIfEmpty } from "./util" +import { getServiceInterface, getServiceInterfaces } from "./util" +import { getStore } from "./store/getStore" +import { CommandOptions, MountOptions, SubContainer } from "./util/SubContainer" +import { splitCommand } from "./util" +import { Mounts } from "./mainFn/Mounts" +import { setupDependencies } from "../../base/lib/dependencies/setupDependencies" +import * as T from "../../base/lib/types" +import { testTypeVersion } from "../../base/lib/exver" +import { ExposedStorePaths } from "./store/setupExposeStore" +import { + PathBuilder, + extractJsonPath, + pathBuilder, +} from "../../base/lib/util/PathBuilder" +import { + CheckDependencies, + checkDependencies, +} from "../../base/lib/dependencies/dependencies" +import { GetSslCertificate } from "./util" +import { VersionGraph } from "./version" +import { MaybeFn } from "../../base/lib/actions/setupActions" +import { GetInput } from "../../base/lib/actions/setupActions" +import { Run } from "../../base/lib/actions/setupActions" +import * as actions from "../../base/lib/actions" +import { setupInit } from "./inits/setupInit" + +export const SDKVersion = testTypeVersion("0.3.6") + +// prettier-ignore +type AnyNeverCond = + T extends [] ? Else : + T extends [never, ...Array] ? Then : + T extends [any, ...infer U] ? AnyNeverCond : + never + +export class StartSdk { + private constructor(readonly manifest: Manifest) {} + static of() { + return new StartSdk(null as never) + } + withManifest(manifest: Manifest) { + return new StartSdk(manifest) + } + withStore>() { + return new StartSdk(this.manifest) + } + + build(isReady: AnyNeverCond<[Manifest, Store], "Build not ready", true>) { + type NestedEffects = "subcontainer" | "store" | "action" + type InterfaceEffects = + | "getServiceInterface" + | "listServiceInterfaces" + | "exportServiceInterface" + | "clearServiceInterfaces" + | "bind" + | "getHostInfo" + | "getPrimaryUrl" + type MainUsedEffects = "setMainStatus" | "setHealth" + type CallbackEffects = "constRetry" | "clearCallbacks" + type AlreadyExposed = "getSslCertificate" | "getSystemSmtp" + + // prettier-ignore + type StartSdkEffectWrapper = { + [K in keyof Omit]: (effects: Effects, ...args: Parameters) => ReturnType + } + const startSdkEffectWrapper: StartSdkEffectWrapper = { + restart: (effects, ...args) => effects.restart(...args), + setDependencies: (effects, ...args) => effects.setDependencies(...args), + checkDependencies: (effects, ...args) => + effects.checkDependencies(...args), + mount: (effects, ...args) => effects.mount(...args), + getInstalledPackages: (effects, ...args) => + effects.getInstalledPackages(...args), + exposeForDependents: (effects, ...args) => + effects.exposeForDependents(...args), + getServicePortForward: (effects, ...args) => + effects.getServicePortForward(...args), + clearBindings: (effects, ...args) => effects.clearBindings(...args), + getContainerIp: (effects, ...args) => effects.getContainerIp(...args), + getSslKey: (effects, ...args) => effects.getSslKey(...args), + setDataVersion: (effects, ...args) => effects.setDataVersion(...args), + getDataVersion: (effects, ...args) => effects.getDataVersion(...args), + shutdown: (effects, ...args) => effects.shutdown(...args), + getDependencies: (effects, ...args) => effects.getDependencies(...args), + getStatus: (effects, ...args) => effects.getStatus(...args), + } + + return { + manifest: this.manifest, + ...startSdkEffectWrapper, + action: { + run: actions.runAction, + request: >( + effects: T.Effects, + packageId: T.PackageId, + action: T, + severity: T.ActionSeverity, + options?: actions.ActionRequestOptions, + ) => + actions.requestAction({ + effects, + packageId, + action, + severity, + options: options, + }), + requestOwn: >( + effects: T.Effects, + action: T, + severity: T.ActionSeverity, + options?: actions.ActionRequestOptions, + ) => + actions.requestAction({ + effects, + packageId: this.manifest.id, + action, + severity, + options: options, + }), + clearRequest: (effects: T.Effects, ...replayIds: string[]) => + effects.action.clearRequests({ only: replayIds }), + }, + checkDependencies: checkDependencies as < + DependencyId extends keyof Manifest["dependencies"] & + PackageId = keyof Manifest["dependencies"] & PackageId, + >( + effects: Effects, + packageIds?: DependencyId[], + ) => Promise>, + serviceInterface: { + getOwn: (effects: E, id: ServiceInterfaceId) => + getServiceInterface(effects, { + id, + }), + get: ( + effects: E, + opts: { id: ServiceInterfaceId; packageId: PackageId }, + ) => getServiceInterface(effects, opts), + getAllOwn: (effects: E) => + getServiceInterfaces(effects, {}), + getAll: ( + effects: E, + opts: { packageId: PackageId }, + ) => getServiceInterfaces(effects, opts), + }, + + store: { + get: ( + effects: E, + packageId: string, + path: PathBuilder, + ) => + getStore(effects, path, { + packageId, + }), + getOwn: ( + effects: E, + path: PathBuilder, + ) => getStore(effects, path), + setOwn: >( + effects: E, + path: Path, + value: Path extends PathBuilder ? Value : never, + ) => + effects.store.set({ + value, + path: extractJsonPath(path), + }), + }, + + host: { + // static: (effects: Effects, id: string) => + // new StaticHost({ id, effects }), + // single: (effects: Effects, id: string) => + // new SingleHost({ id, effects }), + multi: (effects: Effects, id: string) => new MultiHost({ id, effects }), + }, + nullIfEmpty, + runCommand: async ( + effects: Effects, + image: { + id: keyof Manifest["images"] & T.ImageId + sharedRun?: boolean + }, + command: T.CommandType, + options: CommandOptions & { + mounts?: { path: string; options: MountOptions }[] + }, + name: string, + ): Promise<{ stdout: string | Buffer; stderr: string | Buffer }> => { + return runCommand(effects, image, command, options, name) + }, + /** + * TODO: rewrite this + * @description Use this function to create a static Action, including optional form input. + * + * By convention, each Action should receive its own file. + * + * @param id + * @param metaData + * @param fn + * @returns + * @example + * In this example, we create an Action that prints a name to the console. We present a user + * with a form for optionally entering a temp name. If no temp name is provided, we use the name + * from the underlying `inputSpec.yaml` file. If no name is there, we use "Unknown". Then, we return + * a message to the user informing them what happened. + * + * ``` + import { sdk } from '../sdk' + const { InputSpec, Value } = sdk + import { yamlFile } from '../file-models/inputSpec.yml' + + const input = InputSpec.of({ + nameToPrint: Value.text({ + name: 'Temp Name', + description: 'If no name is provided, the name from inputSpec will be used', + required: false, + }), + }) + + export const nameToLog = sdk.createAction( + // id + 'nameToLogs', + + // metadata + { + name: 'Name to Logs', + description: 'Prints "Hello [Name]" to the service logs.', + warning: null, + disabled: false, + input, + allowedStatuses: 'onlyRunning', + group: null, + }, + + // the execution function + async ({ effects, input }) => { + const name = + input.nameToPrint || (await yamlFile.read(effects))?.name || 'Unknown' + + console.info(`Hello ${name}`) + + return { + version: '0', + message: `"Hello ${name}" has been written to the service logs. Open your logs to view it.`, + value: name, + copyable: true, + qr: false, + } + }, + ) + * ``` + */ + Action: { + withInput: < + Id extends T.ActionId, + InputSpecType extends + | Record + | InputSpec + | InputSpec, + Type extends + ExtractInputSpecType = ExtractInputSpecType, + >( + id: Id, + metadata: MaybeFn>, + inputSpec: InputSpecType, + getInput: GetInput, + run: Run, + ) => Action.withInput(id, metadata, inputSpec, getInput, run), + withoutInput: ( + id: Id, + metadata: MaybeFn>, + run: Run<{}>, + ) => Action.withoutInput(id, metadata, run), + }, + inputSpecConstants: { smtpInputSpec }, + /** + * @description Use this function to create a service interface. + * @param effects + * @param options + * @example + * In this example, we create a standard web UI + * + * ``` + const ui = sdk.createInterface(effects, { + name: 'Web UI', + id: 'ui', + description: 'The primary web app for this service.', + type: 'ui', + hasPrimary: false, + masked: false, + schemeOverride: null, + username: null, + path: '', + search: {}, + }) + * ``` + */ + createInterface: ( + effects: Effects, + options: { + /** The human readable name of this service interface. */ + name: string + /** A unique ID for this service interface. */ + id: string + /** The human readable description. */ + description: string + /** Not available until StartOS v0.4.0. If true, forces the user to select one URL (i.e. .onion, .local, or IP address) as the primary URL. This is needed by some services to function properly. */ + hasPrimary: boolean + /** Affects how the interface appears to the user. One of: 'ui', 'api', 'p2p'. */ + type: ServiceInterfaceType + /** (optional) prepends the provided username to all URLs. */ + username: null | string + /** (optional) appends the provided path to all URLs. */ + path: string + /** (optional) appends the provided query params to all URLs. */ + search: Record + /** (optional) overrides the protocol prefix provided by the bind function. + * + * @example `ftp://` + */ + schemeOverride: { ssl: Scheme; noSsl: Scheme } | null + /** TODO Aiden how would someone include a password in the URL? Whether or not to mask the URLs on the screen, for example, when they contain a password */ + masked: boolean + }, + ) => new ServiceInterfaceBuilder({ ...options, effects }), + getSystemSmtp: (effects: E) => + new GetSystemSmtp(effects), + getSslCerificate: ( + effects: E, + hostnames: string[], + algorithm?: T.Algorithm, + ) => new GetSslCertificate(effects, hostnames, algorithm), + HealthCheck: { + of(effects: T.Effects, o: Omit) { + return healthCheck({ effects, ...o }) + }, + }, + healthCheck: { + checkPortListening, + checkWebUrl, + runHealthScript, + }, + patterns, + /** + * @description Use this function to list every Action offered by the service. Actions will be displayed in the provided order. + * + * By convention, each Action should receive its own file in the "actions" directory. + * @example + * + * ``` + import { sdk } from '../sdk' + import { config } from './config' + import { nameToLogs } from './nameToLogs' + + export const actions = sdk.Actions.of().addAction(config).addAction(nameToLogs) + * ``` + */ + Actions: Actions, + /** + * @description Use this function to determine which volumes are backed up when a user creates a backup, including advanced options. + * @example + * In this example, we back up the entire "main" volume and nothing else. + * + * ``` + export const { createBackup, restoreBackup } = sdk.setupBackups(sdk.Backups.addVolume('main')) + * ``` + * @example + * In this example, we back up the "main" and the "other" volume, but exclude hypothetical directory "excludedDir" from the "other". + * + * ``` + export const { createBackup, restoreBackup } = sdk.setupBackups(sdk.Backups + .addVolume('main') + .addVolume('other', { exclude: ['path/to/excludedDir'] }) + ) + * ``` + */ + setupBackups: (options: SetupBackupsParams) => + setupBackups(options), + /** + * @description Use this function to set dependency information. + * + * The function executes on service install, update, and inputSpec save. "input" will be of type `Input` for inputSpec save. It will be `null` for install and update. + * @example + * In this example, we create a static dependency on Hello World >=1.0.0:0, where Hello World must be running and passing its "webui" health check. + * + * ``` + export const setDependencies = sdk.setupDependencies( + async ({ effects, input }) => { + return { + 'hello-world': sdk.Dependency.of({ + type: 'running', + versionRange: VersionRange.parse('>=1.0.0:0'), + healthChecks: ['webui'], + }), + } + }, + ) + * ``` + * @example + * In this example, we create a conditional dependency on Hello World based on a hypothetical "needsWorld" boolean in the store. + * + * ``` + export const setDependencies = sdk.setupDependencies( + async ({ effects }) => { + if (sdk.store.getOwn(sdk.StorePath.needsWorld).const()) { + return { + 'hello-world': sdk.Dependency.of({ + type: 'running', + versionRange: VersionRange.parse('>=1.0.0:0'), + healthChecks: ['webui'], + }), + } + } + return {} + }, + ) + * ``` + */ + setupDependencies: setupDependencies, + setupInit: setupInit, + /** + * @description Use this function to execute arbitrary logic *once*, on initial install only. + * @example + * In the this example, we bootstrap our Store with a random, 16-char admin password. + * + * ``` + const install = sdk.setupInstall(async ({ effects }) => { + await sdk.store.setOwn( + effects, + sdk.StorePath.adminPassword, + utils.getDefaultString({ + charset: 'a-z,A-Z,1-9,!,@,$,%,&,', + len: 16, + }), + ) + }) + * ``` + */ + setupInstall: (fn: InstallFn) => Install.of(fn), + /** + * @description Use this function to determine how this service will be hosted and served. The function executes on service install, service update, and inputSpec save. + * + * "input" will be of type `Input` for inputSpec save. It will be `null` for install and update. + * + * To learn about creating multi-hosts and interfaces, check out the {@link https://docs.start9.com/packaging-guide/learn/interfaces documentation}. + * @param inputSpec - The inputSpec spec of this service as exported from /inputSpec/spec. + * @param fn - an async function that returns an array of interface receipts. The function always has access to `effects`; it has access to `input` only after inputSpec save, otherwise `input` will be null. + * @example + * In this example, we create two UIs from one multi-host, and one API from another multi-host. + * + * ``` + export const setInterfaces = sdk.setupInterfaces( + inputSpecSpec, + async ({ effects, input }) => { + // ** UI multi-host ** + const uiMulti = sdk.host.multi(effects, 'ui-multi') + const uiMultiOrigin = await uiMulti.bindPort(80, { + protocol: 'http', + }) + // Primary UI + const primaryUi = sdk.createInterface(effects, { + name: 'Primary UI', + id: 'primary-ui', + description: 'The primary web app for this service.', + type: 'ui', + hasPrimary: false, + masked: false, + schemeOverride: null, + username: null, + path: '', + search: {}, + }) + // Admin UI + const adminUi = sdk.createInterface(effects, { + name: 'Admin UI', + id: 'admin-ui', + description: 'The admin web app for this service.', + type: 'ui', + hasPrimary: false, + masked: false, + schemeOverride: null, + username: null, + path: '/admin', + search: {}, + }) + // UI receipt + const uiReceipt = await uiMultiOrigin.export([primaryUi, adminUi]) + + // ** API multi-host ** + const apiMulti = sdk.host.multi(effects, 'api-multi') + const apiMultiOrigin = await apiMulti.bindPort(5959, { + protocol: 'http', + }) + // API + const api = sdk.createInterface(effects, { + name: 'Admin API', + id: 'api', + description: 'The advanced API for this service.', + type: 'api', + hasPrimary: false, + masked: false, + schemeOverride: null, + username: null, + path: '', + search: {}, + }) + // API receipt + const apiReceipt = await apiMultiOrigin.export([api]) + + // ** Return receipts ** + return [uiReceipt, apiReceipt] + }, + ) + * ``` + */ + setupInterfaces: setupServiceInterfaces, + setupMain: ( + fn: (o: { + effects: Effects + started(onTerm: () => PromiseLike): PromiseLike + }) => Promise>, + ) => setupMain(fn), + /** + * Use this function to execute arbitrary logic *once*, on uninstall only. Most services will not use this. + */ + setupUninstall: (fn: UninstallFn) => + setupUninstall(fn), + trigger: { + defaultTrigger, + cooldownTrigger, + changeOnFirstSuccess, + successFailure, + }, + Mounts: { + of() { + return Mounts.of() + }, + }, + Backups: { + volumes: ( + ...volumeNames: Array + ) => Backups.withVolumes(...volumeNames), + addSets: ( + ...options: BackupSync[] + ) => Backups.withSyncs(...options), + withOptions: (options?: Partial) => + Backups.withOptions(options), + }, + InputSpec: { + /** + * @description Use this function to define the inputSpec specification that will ultimately present to the user as validated form inputs. + * + * Most form controls are supported, including text, textarea, number, toggle, select, multiselect, list, color, datetime, object (sub form), and union (conditional sub form). + * @example + * In this example, we define a inputSpec form with two value: name and makePublic. + * + * ``` + import { sdk } from '../sdk' + const { InputSpec, Value } = sdk + + export const inputSpecSpec = InputSpec.of({ + name: Value.text({ + name: 'Name', + description: + 'When you launch the Hello World UI, it will display "Hello [Name]"', + required: { default: 'World' }, + }), + makePublic: Value.toggle({ + name: 'Make Public', + description: 'Whether or not to expose the service to the network', + default: false, + }), + }) + * ``` + */ + of: < + Spec extends Record | Value>, + >( + spec: Spec, + ) => InputSpec.of(spec), + }, + Daemons: { + of( + effects: Effects, + started: (onTerm: () => PromiseLike) => PromiseLike, + healthReceipts: HealthReceipt[], + ) { + return Daemons.of({ effects, started, healthReceipts }) + }, + }, + List: { + /** + * @description Create a list of text inputs. + * @param a - attributes of the list itself. + * @param aSpec - attributes describing each member of the list. + */ + text: List.text, + /** + * @description Create a list of objects. + * @param a - attributes of the list itself. + * @param aSpec - attributes describing each member of the list. + */ + obj: >( + a: { + name: string + description?: string | null + /** Presents a warning before adding/removing/editing a list item. */ + warning?: string | null + default?: [] + minLength?: number | null + maxLength?: number | null + }, + aSpec: { + spec: InputSpec + /** + * @description The ID of a required field on the inner object whose value will be used to display items in the list. + * @example + * In this example, we use the value of the `label` field to display members of the list. + * + * ``` + spec: InputSpec.of({ + label: Value.text({ + name: 'Label', + required: false, + }) + }) + displayAs: 'label', + uniqueBy: null, + * ``` + * + */ + displayAs?: null | string + /** + * @description The ID(s) of required fields on the inner object whose value(s) will be used to enforce uniqueness in the list. + * @example + * In this example, we use the `label` field to enforce uniqueness, meaning the label field must be unique from other entries. + * + * ``` + spec: InputSpec.of({ + label: Value.text({ + name: 'Label', + required: { default: null }, + }) + pubkey: Value.text({ + name: 'Pubkey', + required: { default: null }, + }) + }) + displayAs: 'label', + uniqueBy: 'label', + * ``` + * @example + * In this example, we use the `label` field AND the `pubkey` field to enforce uniqueness, meaning both these fields must be unique from other entries. + * + * ``` + spec: InputSpec.of({ + label: Value.text({ + name: 'Label', + required: { default: null }, + }) + pubkey: Value.text({ + name: 'Pubkey', + required: { default: null }, + }) + }) + displayAs: 'label', + uniqueBy: { all: ['label', 'pubkey'] }, + * ``` + */ + uniqueBy?: null | UniqueBy + }, + ) => List.obj(a, aSpec), + /** + * @description Create a list of dynamic text inputs. + * @param a - attributes of the list itself. + * @param aSpec - attributes describing each member of the list. + */ + dynamicText: ( + getA: LazyBuild< + Store, + { + name: string + description?: string | null + warning?: string | null + default?: string[] + minLength?: number | null + maxLength?: number | null + disabled?: false | string + generate?: null | RandomString + spec: { + masked?: boolean + placeholder?: string | null + minLength?: number | null + maxLength?: number | null + patterns: Pattern[] + inputmode?: ListValueSpecText["inputmode"] + } + } + >, + ) => List.dynamicText(getA), + }, + StorePath: pathBuilder(), + Value: { + /** + * @description Displays a boolean toggle to enable/disable + * @example + * ``` + toggleExample: Value.toggle({ + // required + name: 'Toggle Example', + default: true, + + // optional + description: null, + warning: null, + immutable: false, + }), + * ``` + */ + toggle: Value.toggle, + /** + * @description Displays a text input field + * @example + * ``` + textExample: Value.text({ + // required + name: 'Text Example', + required: false, + + // optional + description: null, + placeholder: null, + warning: null, + generate: null, + inputmode: 'text', + masked: false, + minLength: null, + maxLength: null, + patterns: [], + immutable: false, + }), + * ``` + */ + text: Value.text, + /** + * @description Displays a large textarea field for long form entry. + * @example + * ``` + textareaExample: Value.textarea({ + // required + name: 'Textarea Example', + required: false, + + // optional + description: null, + placeholder: null, + warning: null, + minLength: null, + maxLength: null, + immutable: false, + }), + * ``` + */ + textarea: Value.textarea, + /** + * @description Displays a number input field + * @example + * ``` + numberExample: Value.number({ + // required + name: 'Number Example', + required: false, + integer: true, + + // optional + description: null, + placeholder: null, + warning: null, + min: null, + max: null, + immutable: false, + step: null, + units: null, + }), + * ``` + */ + number: Value.number, + /** + * @description Displays a browser-native color selector. + * @example + * ``` + colorExample: Value.color({ + // required + name: 'Color Example', + required: false, + + // optional + description: null, + warning: null, + immutable: false, + }), + * ``` + */ + color: Value.color, + /** + * @description Displays a browser-native date/time selector. + * @example + * ``` + datetimeExample: Value.datetime({ + // required + name: 'Datetime Example', + required: false, + + // optional + description: null, + warning: null, + immutable: false, + inputmode: 'datetime-local', + min: null, + max: null, + }), + * ``` + */ + datetime: Value.datetime, + /** + * @description Displays a select modal with radio buttons, allowing for a single selection. + * @example + * ``` + selectExample: Value.select({ + // required + name: 'Select Example', + required: false, + values: { + radio1: 'Radio 1', + radio2: 'Radio 2', + }, + + // optional + description: null, + warning: null, + immutable: false, + disabled: false, + }), + * ``` + */ + select: Value.select, + /** + * @description Displays a select modal with checkboxes, allowing for multiple selections. + * @example + * ``` + multiselectExample: Value.multiselect({ + // required + name: 'Multiselect Example', + values: { + option1: 'Option 1', + option2: 'Option 2', + }, + default: [], + + // optional + description: null, + warning: null, + immutable: false, + disabled: false, + minlength: null, + maxLength: null, + }), + * ``` + */ + multiselect: Value.multiselect, + /** + * @description Display a collapsable grouping of additional fields, a "sub form". The second value is the inputSpec spec for the sub form. + * @example + * ``` + objectExample: Value.object( + { + // required + name: 'Object Example', + + // optional + description: null, + warning: null, + }, + InputSpec.of({}), + ), + * ``` + */ + object: Value.object, + /** + * @description Displays a dropdown, allowing for a single selection. Depending on the selection, a different object ("sub form") is presented. + * @example + * ``` + unionExample: Value.union( + { + // required + name: 'Union Example', + required: false, + + // optional + description: null, + warning: null, + disabled: false, + immutable: false, + }, + Variants.of({ + option1: { + name: 'Option 1', + spec: InputSpec.of({}), + }, + option2: { + name: 'Option 2', + spec: InputSpec.of({}), + }, + }), + ), + * ``` + */ + union: Value.union, + /** + * @description Presents an interface to add/remove/edit items in a list. + * @example + * In this example, we create a list of text inputs. + * + * ``` + listExampleText: Value.list( + List.text( + { + // required + name: 'Text List', + + // optional + description: null, + warning: null, + default: [], + minLength: null, + maxLength: null, + }, + { + // required + patterns: [], + + // optional + placeholder: null, + generate: null, + inputmode: 'url', + masked: false, + minLength: null, + maxLength: null, + }, + ), + ), + * ``` + * @example + * In this example, we create a list of objects. + * + * ``` + listExampleObject: Value.list( + List.obj( + { + // required + name: 'Object List', + + // optional + description: null, + warning: null, + default: [], + minLength: null, + maxLength: null, + }, + { + // required + spec: InputSpec.of({}), + + // optional + displayAs: null, + uniqueBy: null, + }, + ), + ), + * ``` + */ + list: Value.list, + hidden: Value.hidden, + dynamicToggle: ( + a: LazyBuild< + Store, + { + name: string + description?: string | null + /** Presents a warning prompt before permitting the value to change. */ + warning?: string | null + default: boolean + disabled?: false | string + } + >, + ) => Value.dynamicToggle(a), + dynamicText: ( + getA: LazyBuild< + Store, + { + name: string + description?: string | null + /** Presents a warning prompt before permitting the value to change. */ + warning?: string | null + /** + * @description optionally provide a default value. + * @type { string | RandomString | null } + * @example default: null + * @example default: 'World' + * @example default: { charset: 'abcdefg', len: 16 } + */ + default: DefaultString | null + required: boolean + /** + * @description Mask (aka camouflage) text input with dots: ● ● ● + * @default false + */ + masked?: boolean + placeholder?: string | null + minLength?: number | null + maxLength?: number | null + /** + * @description A list of regular expressions to which the text must conform to pass validation. A human readable description is provided in case the validation fails. + * @default [] + * @example + * ``` + [ + { + regex: "[a-z]", + description: "May only contain lower case letters from the English alphabet." + } + ] + * ``` + */ + patterns?: Pattern[] + /** + * @description Informs the browser how to behave and which keyboard to display on mobile + * @default "text" + */ + inputmode?: ValueSpecText["inputmode"] + /** + * @description Displays a button that will generate a random string according to the provided charset and len attributes. + */ + generate?: null | RandomString + } + >, + ) => Value.dynamicText(getA), + dynamicTextarea: ( + getA: LazyBuild< + Store, + { + name: string + description?: string | null + /** Presents a warning prompt before permitting the value to change. */ + warning?: string | null + default: string | null + required: boolean + minLength?: number | null + maxLength?: number | null + placeholder?: string | null + disabled?: false | string + } + >, + ) => Value.dynamicTextarea(getA), + dynamicNumber: ( + getA: LazyBuild< + Store, + { + name: string + description?: string | null + /** Presents a warning prompt before permitting the value to change. */ + warning?: string | null + /** + * @description optionally provide a default value. + * @type { number | null } + * @example default: null + * @example default: 7 + */ + default: number | null + required: boolean + min?: number | null + max?: number | null + /** + * @description How much does the number increase/decrease when using the arrows provided by the browser. + * @default 1 + */ + step?: number | null + /** + * @description Requires the number to be an integer. + */ + integer: boolean + /** + * @description Optionally display units to the right of the input box. + */ + units?: string | null + placeholder?: string | null + disabled?: false | string + } + >, + ) => Value.dynamicNumber(getA), + dynamicColor: ( + getA: LazyBuild< + Store, + { + name: string + description?: string | null + /** Presents a warning prompt before permitting the value to change. */ + warning?: string | null + /** + * @description optionally provide a default value. + * @type { string | null } + * @example default: null + * @example default: 'ffffff' + */ + default: string | null + required: boolean + disabled?: false | string + } + >, + ) => Value.dynamicColor(getA), + dynamicDatetime: ( + getA: LazyBuild< + Store, + { + name: string + description?: string | null + /** Presents a warning prompt before permitting the value to change. */ + warning?: string | null + /** + * @description optionally provide a default value. + * @type { string | null } + * @example default: null + * @example default: '1985-12-16 18:00:00.000' + */ + default: string + required: boolean + /** + * @description Informs the browser how to behave and which date/time component to display. + * @default "datetime-local" + */ + inputmode?: ValueSpecDatetime["inputmode"] + min?: string | null + max?: string | null + disabled?: false | string + } + >, + ) => Value.dynamicDatetime(getA), + dynamicSelect: >( + getA: LazyBuild< + Store, + { + name: string + description?: string | null + /** Presents a warning prompt before permitting the value to change. */ + warning?: string | null + /** + * @description provide a default value from the list of values. + * @type { default: string } + * @example default: 'radio1' + */ + default: keyof Variants & string + required: boolean + /** + * @description A mapping of unique radio options to their human readable display format. + * @example + * ``` + { + radio1: "Radio 1" + radio2: "Radio 2" + radio3: "Radio 3" + } + * ``` + */ + values: Variants + /** + * @options + * - false - The field can be modified. + * - string - The field cannot be modified. The provided text explains why. + * - string[] - The field can be modified, but the values contained in the array cannot be selected. + * @default false + */ + disabled?: false | string | string[] + } + >, + ) => Value.dynamicSelect(getA), + dynamicMultiselect: ( + getA: LazyBuild< + Store, + { + name: string + description?: string | null + /** Presents a warning prompt before permitting the value to change. */ + warning?: string | null + /** + * @description A simple list of which options should be checked by default. + */ + default: string[] + /** + * @description A mapping of checkbox options to their human readable display format. + * @example + * ``` + { + option1: "Option 1" + option2: "Option 2" + option3: "Option 3" + } + * ``` + */ + values: Record + minLength?: number | null + maxLength?: number | null + /** + * @options + * - false - The field can be modified. + * - string - The field cannot be modified. The provided text explains why. + * - string[] - The field can be modified, but the values contained in the array cannot be selected. + * @default false + */ + disabled?: false | string | string[] + } + >, + ) => Value.dynamicMultiselect(getA), + filteredUnion: < + VariantValues extends { + [K in string]: { + name: string + spec: InputSpec | InputSpec + } + }, + >( + getDisabledFn: LazyBuild, + a: { + name: string + description?: string | null + warning?: string | null + default: keyof VariantValues & string + }, + aVariants: + | Variants + | Variants, + ) => + Value.filteredUnion( + getDisabledFn, + a, + aVariants, + ), + + dynamicUnion: < + VariantValues extends { + [K in string]: { + name: string + spec: InputSpec | InputSpec + } + }, + >( + getA: LazyBuild< + Store, + { + name: string + description?: string | null + /** Presents a warning prompt before permitting the value to change. */ + warning?: string | null + /** + * @description provide a default value from the list of variants. + * @type { string } + * @example default: 'variant1' + */ + default: keyof VariantValues & string + required: boolean + /** + * @options + * - false - The field can be modified. + * - string - The field cannot be modified. The provided text explains why. + * - string[] - The field can be modified, but the values contained in the array cannot be selected. + * @default false + */ + disabled: false | string | string[] + } + >, + aVariants: + | Variants + | Variants, + ) => Value.dynamicUnion(getA, aVariants), + }, + Variants: { + of: < + VariantValues extends { + [K in string]: { + name: string + spec: InputSpec + } + }, + >( + a: VariantValues, + ) => Variants.of(a), + }, + } + } +} + +export async function runCommand( + effects: Effects, + image: { id: keyof Manifest["images"] & T.ImageId; sharedRun?: boolean }, + command: string | [string, ...string[]], + options: CommandOptions & { + mounts?: { path: string; options: MountOptions }[] + }, + name: string, +): Promise<{ stdout: string | Buffer; stderr: string | Buffer }> { + const commands = splitCommand(command) + return SubContainer.with( + effects, + image, + options.mounts || [], + name, + (subcontainer) => subcontainer.exec(commands), + ) +} diff --git a/sdk/package/lib/backup/Backups.ts b/sdk/package/lib/backup/Backups.ts new file mode 100644 index 000000000..c27f2be72 --- /dev/null +++ b/sdk/package/lib/backup/Backups.ts @@ -0,0 +1,208 @@ +import * as T from "../../../base/lib/types" +import * as child_process from "child_process" +import { asError } from "../util" + +export const DEFAULT_OPTIONS: T.SyncOptions = { + delete: true, + exclude: [], +} +export type BackupSync = { + dataPath: `/media/startos/volumes/${Volumes}/${string}` + backupPath: `/media/startos/backup/${string}` + options?: Partial + backupOptions?: Partial + restoreOptions?: Partial +} +/** + * This utility simplifies the volume backup process. + * ```ts + * export const { createBackup, restoreBackup } = Backups.volumes("main").build(); + * ``` + * + * Changing the options of the rsync, (ie excludes) use either + * ```ts + * Backups.volumes("main").set_options({exclude: ['bigdata/']}).volumes('excludedVolume').build() + * // or + * Backups.with_options({exclude: ['bigdata/']}).volumes('excludedVolume').build() + * ``` + * + * Using the more fine control, using the addSets for more control + * ```ts + * Backups.addSets({ + * srcVolume: 'main', srcPath:'smallData/', dstPath: 'main/smallData/', dstVolume: : Backups.BACKUP + * }, { + * srcVolume: 'main', srcPath:'bigData/', dstPath: 'main/bigData/', dstVolume: : Backups.BACKUP, options: {exclude:['bigData/excludeThis']}} + * ).build()q + * ``` + */ +export class Backups { + private constructor( + private options = DEFAULT_OPTIONS, + private restoreOptions: Partial = {}, + private backupOptions: Partial = {}, + private backupSet = [] as BackupSync[], + ) {} + + static withVolumes( + ...volumeNames: Array + ): Backups { + return Backups.withSyncs( + ...volumeNames.map((srcVolume) => ({ + dataPath: `/media/startos/volumes/${srcVolume}/` as const, + backupPath: `/media/startos/backup/${srcVolume}/` as const, + })), + ) + } + + static withSyncs( + ...syncs: BackupSync[] + ) { + return syncs.reduce((acc, x) => acc.addSync(x), new Backups()) + } + + static withOptions( + options?: Partial, + ) { + return new Backups({ ...DEFAULT_OPTIONS, ...options }) + } + + setOptions(options?: Partial) { + this.options = { + ...this.options, + ...options, + } + return this + } + + setBackupOptions(options?: Partial) { + this.backupOptions = { + ...this.backupOptions, + ...options, + } + return this + } + + setRestoreOptions(options?: Partial) { + this.restoreOptions = { + ...this.restoreOptions, + ...options, + } + return this + } + + addVolume( + volume: M["volumes"][number], + options?: Partial<{ + options: T.SyncOptions + backupOptions: T.SyncOptions + restoreOptions: T.SyncOptions + }>, + ) { + return this.addSync({ + dataPath: `/media/startos/volumes/${volume}/` as const, + backupPath: `/media/startos/backup/${volume}/` as const, + ...options, + }) + } + addSync(sync: BackupSync) { + this.backupSet.push({ + ...sync, + options: { ...this.options, ...sync.options }, + }) + return this + } + + async createBackup() { + for (const item of this.backupSet) { + const rsyncResults = await runRsync({ + srcPath: item.dataPath, + dstPath: item.backupPath, + options: { + ...this.options, + ...this.backupOptions, + ...item.options, + ...item.backupOptions, + }, + }) + await rsyncResults.wait() + } + return + } + + async restoreBackup() { + for (const item of this.backupSet) { + const rsyncResults = await runRsync({ + srcPath: item.backupPath, + dstPath: item.dataPath, + options: { + ...this.options, + ...this.backupOptions, + ...item.options, + ...item.backupOptions, + }, + }) + await rsyncResults.wait() + } + return + } +} + +async function runRsync(rsyncOptions: { + srcPath: string + dstPath: string + options: T.SyncOptions +}): Promise<{ + id: () => Promise + wait: () => Promise + progress: () => Promise +}> { + const { srcPath, dstPath, options } = rsyncOptions + + const command = "rsync" + const args: string[] = [] + if (options.delete) { + args.push("--delete") + } + for (const exclude of options.exclude) { + args.push(`--exclude=${exclude}`) + } + args.push("-actAXH") + args.push("--info=progress2") + args.push("--no-inc-recursive") + args.push(srcPath) + args.push(dstPath) + const spawned = child_process.spawn(command, args, { detached: true }) + let percentage = 0.0 + spawned.stdout.on("data", (data: unknown) => { + const lines = String(data).replace("\r", "\n").split("\n") + for (const line of lines) { + const parsed = /$([0-9.]+)%/.exec(line)?.[1] + if (!parsed) continue + percentage = Number.parseFloat(parsed) + } + }) + + spawned.stderr.on("data", (data: unknown) => { + console.error(`Backups.runAsync`, asError(data)) + }) + + const id = async () => { + const pid = spawned.pid + if (pid === undefined) { + throw new Error("rsync process has no pid") + } + return String(pid) + } + const waitPromise = new Promise((resolve, reject) => { + spawned.on("exit", (code: any) => { + if (code === 0) { + resolve(null) + } else { + reject(new Error(`rsync exited with code ${code}`)) + } + }) + }) + const wait = () => waitPromise + const progress = () => Promise.resolve(percentage) + return { id, wait, progress } +} diff --git a/sdk/lib/backup/index.ts b/sdk/package/lib/backup/index.ts similarity index 97% rename from sdk/lib/backup/index.ts rename to sdk/package/lib/backup/index.ts index fe9cd8569..1e7995252 100644 --- a/sdk/lib/backup/index.ts +++ b/sdk/package/lib/backup/index.ts @@ -1,3 +1,2 @@ import "./Backups" - import "./setupBackups" diff --git a/sdk/package/lib/backup/setupBackups.ts b/sdk/package/lib/backup/setupBackups.ts new file mode 100644 index 000000000..722d245ff --- /dev/null +++ b/sdk/package/lib/backup/setupBackups.ts @@ -0,0 +1,39 @@ +import { Backups } from "./Backups" +import * as T from "../../../base/lib/types" +import { _ } from "../util" + +export type SetupBackupsParams = + | M["volumes"][number][] + | ((_: { effects: T.Effects }) => Promise>) + +type SetupBackupsRes = { + createBackup: T.ExpectedExports.createBackup + restoreBackup: T.ExpectedExports.restoreBackup +} + +export function setupBackups( + options: SetupBackupsParams, +) { + let backupsFactory: (_: { effects: T.Effects }) => Promise> + if (options instanceof Function) { + backupsFactory = options + } else { + backupsFactory = async () => Backups.withVolumes(...options) + } + const answer: { + createBackup: T.ExpectedExports.createBackup + restoreBackup: T.ExpectedExports.restoreBackup + } = { + get createBackup() { + return (async (options) => { + return (await backupsFactory(options)).createBackup() + }) as T.ExpectedExports.createBackup + }, + get restoreBackup() { + return (async (options) => { + return (await backupsFactory(options)).restoreBackup() + }) as T.ExpectedExports.restoreBackup + }, + } + return answer +} diff --git a/sdk/lib/health/HealthCheck.ts b/sdk/package/lib/health/HealthCheck.ts similarity index 88% rename from sdk/lib/health/HealthCheck.ts rename to sdk/package/lib/health/HealthCheck.ts index e007c4ea2..05c1a214a 100644 --- a/sdk/lib/health/HealthCheck.ts +++ b/sdk/package/lib/health/HealthCheck.ts @@ -1,14 +1,10 @@ -import { Effects } from "../types" +import { Effects, HealthReceipt } from "../../../base/lib/types" import { HealthCheckResult } from "./checkFns/HealthCheckResult" -import { HealthReceipt } from "./HealthReceipt" import { Trigger } from "../trigger" import { TriggerInput } from "../trigger/TriggerInput" import { defaultTrigger } from "../trigger/defaultTrigger" -import { once } from "../util/once" -import { SubContainer } from "../util/SubContainer" +import { once, asError } from "../util" import { object, unknown } from "ts-matches" -import * as T from "../types" -import { asError } from "../util/asError" export type HealthCheckParams = { effects: Effects diff --git a/sdk/lib/health/checkFns/HealthCheckResult.ts b/sdk/package/lib/health/checkFns/HealthCheckResult.ts similarity index 63% rename from sdk/lib/health/checkFns/HealthCheckResult.ts rename to sdk/package/lib/health/checkFns/HealthCheckResult.ts index ba2468488..92d4afddf 100644 --- a/sdk/lib/health/checkFns/HealthCheckResult.ts +++ b/sdk/package/lib/health/checkFns/HealthCheckResult.ts @@ -1,3 +1,3 @@ -import { T } from "../.." +import { T } from "../../../../base/lib" export type HealthCheckResult = Omit diff --git a/sdk/lib/health/checkFns/checkPortListening.ts b/sdk/package/lib/health/checkFns/checkPortListening.ts similarity index 94% rename from sdk/lib/health/checkFns/checkPortListening.ts rename to sdk/package/lib/health/checkFns/checkPortListening.ts index 94d0becc0..e745bce4f 100644 --- a/sdk/lib/health/checkFns/checkPortListening.ts +++ b/sdk/package/lib/health/checkFns/checkPortListening.ts @@ -1,5 +1,5 @@ -import { Effects } from "../../types" -import { stringFromStdErrOut } from "../../util/stringFromStdErrOut" +import { Effects } from "../../../../base/lib/types" +import { stringFromStdErrOut } from "../../util" import { HealthCheckResult } from "./HealthCheckResult" import { promisify } from "node:util" diff --git a/sdk/lib/health/checkFns/checkWebUrl.ts b/sdk/package/lib/health/checkFns/checkWebUrl.ts similarity index 90% rename from sdk/lib/health/checkFns/checkWebUrl.ts rename to sdk/package/lib/health/checkFns/checkWebUrl.ts index 042115211..e04ee7531 100644 --- a/sdk/lib/health/checkFns/checkWebUrl.ts +++ b/sdk/package/lib/health/checkFns/checkWebUrl.ts @@ -1,5 +1,5 @@ -import { Effects } from "../../types" -import { asError } from "../../util/asError" +import { Effects } from "../../../../base/lib/types" +import { asError } from "../../util" import { HealthCheckResult } from "./HealthCheckResult" import { timeoutPromise } from "./index" import "isomorphic-fetch" diff --git a/sdk/lib/health/checkFns/index.ts b/sdk/package/lib/health/checkFns/index.ts similarity index 100% rename from sdk/lib/health/checkFns/index.ts rename to sdk/package/lib/health/checkFns/index.ts diff --git a/sdk/lib/health/checkFns/runHealthScript.ts b/sdk/package/lib/health/checkFns/runHealthScript.ts similarity index 91% rename from sdk/lib/health/checkFns/runHealthScript.ts rename to sdk/package/lib/health/checkFns/runHealthScript.ts index 4bac211a9..7ecd1ad75 100644 --- a/sdk/lib/health/checkFns/runHealthScript.ts +++ b/sdk/package/lib/health/checkFns/runHealthScript.ts @@ -1,8 +1,6 @@ -import { Effects } from "../../types" -import { SubContainer } from "../../util/SubContainer" -import { stringFromStdErrOut } from "../../util/stringFromStdErrOut" import { HealthCheckResult } from "./HealthCheckResult" import { timeoutPromise } from "./index" +import { SubContainer } from "../../util/SubContainer" /** * Running a health script, is used when we want to have a simple diff --git a/sdk/package/lib/health/index.ts b/sdk/package/lib/health/index.ts new file mode 100644 index 000000000..b969037a5 --- /dev/null +++ b/sdk/package/lib/health/index.ts @@ -0,0 +1 @@ +import "./checkFns" diff --git a/sdk/lib/index.ts b/sdk/package/lib/index.ts similarity index 53% rename from sdk/lib/index.ts rename to sdk/package/lib/index.ts index a4caf9c01..3619765e1 100644 --- a/sdk/lib/index.ts +++ b/sdk/package/lib/index.ts @@ -1,32 +1,48 @@ +import { + S9pk, + Version, + VersionRange, + ExtendedVersion, + inputSpec, + ISB, + IST, + types, + T, + matches, + utils, +} from "../../base/lib" + +export { + S9pk, + Version, + VersionRange, + ExtendedVersion, + inputSpec, + ISB, + IST, + types, + T, + matches, + utils, +} export { Daemons } from "./mainFn/Daemons" export { SubContainer } from "./util/SubContainer" export { StartSdk } from "./StartSdk" -export { setupManifest } from "./manifest/setupManifest" +export { setupManifest, buildManifest } from "./manifest/setupManifest" export { FileHelper } from "./util/fileHelper" export { setupExposeStore } from "./store/setupExposeStore" -export { pathBuilder } from "./store/PathBuilder" -export { S9pk } from "./s9pk" -export { VersionRange, ExtendedVersion, Version } from "./exver" +export { pathBuilder } from "../../base/lib/util/PathBuilder" -export * as actions from "./actions" +export * as actions from "../../base/lib/actions" export * as backup from "./backup" -export * as config from "./config" -export * as CB from "./config/builder" -export * as CT from "./config/configTypes" -export * as dependencyConfig from "./dependencies" export * as daemons from "./mainFn/Daemons" export * as health from "./health" export * as healthFns from "./health/checkFns" export * as inits from "./inits" export * as mainFn from "./mainFn" -export * as manifest from "./manifest" export * as toml from "@iarna/toml" -export * as types from "./types" -export * as T from "./types" export * as yaml from "yaml" export * as startSdk from "./StartSdk" -export * as utils from "./util" -export * as matches from "ts-matches" export * as YAML from "yaml" export * as TOML from "@iarna/toml" export * from "./version" diff --git a/sdk/lib/inits/index.ts b/sdk/package/lib/inits/index.ts similarity index 100% rename from sdk/lib/inits/index.ts rename to sdk/package/lib/inits/index.ts diff --git a/sdk/lib/inits/setupInit.ts b/sdk/package/lib/inits/setupInit.ts similarity index 56% rename from sdk/lib/inits/setupInit.ts rename to sdk/package/lib/inits/setupInit.ts index 5fd1c481c..8d30f5b1f 100644 --- a/sdk/lib/inits/setupInit.ts +++ b/sdk/package/lib/inits/setupInit.ts @@ -1,29 +1,29 @@ -import { DependenciesReceipt } from "../config/setupConfig" -import { ExtendedVersion, VersionRange } from "../exver" -import { SetInterfaces } from "../interfaces/setupInterfaces" - -import { ExposedStorePaths } from "../store/setupExposeStore" -import * as T from "../types" +import { Actions } from "../../../base/lib/actions/setupActions" +import { ExtendedVersion } from "../../../base/lib/exver" +import { UpdateServiceInterfaces } from "../../../base/lib/interfaces/setupInterfaces" +import { ExposedStorePaths } from "../../../base/lib/types" +import * as T from "../../../base/lib/types" import { VersionGraph } from "../version/VersionGraph" import { Install } from "./setupInstall" import { Uninstall } from "./setupUninstall" -export function setupInit( - versions: VersionGraph, +export function setupInit( + versions: VersionGraph, install: Install, uninstall: Uninstall, - setInterfaces: SetInterfaces, + setServiceInterfaces: UpdateServiceInterfaces, setDependencies: (options: { effects: T.Effects - input: any - }) => Promise, + }) => Promise, + actions: Actions, exposedStore: ExposedStorePaths, ): { - init: T.ExpectedExports.init - uninit: T.ExpectedExports.uninit + packageInit: T.ExpectedExports.packageInit + packageUninit: T.ExpectedExports.packageUninit + containerInit: T.ExpectedExports.containerInit } { return { - init: async (opts) => { + packageInit: async (opts) => { const prev = await opts.effects.getDataVersion() if (prev) { await versions.migrate({ @@ -37,14 +37,8 @@ export function setupInit( version: versions.current.options.version, }) } - await setInterfaces({ - ...opts, - input: null, - }) - await opts.effects.exposeForDependents({ paths: exposedStore }) - await setDependencies({ effects: opts.effects, input: null }) }, - uninit: async (opts) => { + packageUninit: async (opts) => { if (opts.nextVersion) { const prev = await opts.effects.getDataVersion() if (prev) { @@ -58,5 +52,13 @@ export function setupInit( await uninstall.uninstall(opts) } }, + containerInit: async (opts) => { + await setServiceInterfaces({ + ...opts, + }) + await actions.update({ effects: opts.effects }) + await opts.effects.exposeForDependents({ paths: exposedStore }) + await setDependencies({ effects: opts.effects }) + }, } } diff --git a/sdk/package/lib/inits/setupInstall.ts b/sdk/package/lib/inits/setupInstall.ts new file mode 100644 index 000000000..38a96a00b --- /dev/null +++ b/sdk/package/lib/inits/setupInstall.ts @@ -0,0 +1,25 @@ +import * as T from "../../../base/lib/types" + +export type InstallFn = (opts: { + effects: T.Effects +}) => Promise +export class Install { + private constructor(readonly fn: InstallFn) {} + static of( + fn: InstallFn, + ) { + return new Install(fn) + } + + async install({ effects }: Parameters[0]) { + await this.fn({ + effects, + }) + } +} + +export function setupInstall( + fn: InstallFn, +) { + return Install.of(fn) +} diff --git a/sdk/package/lib/inits/setupUninstall.ts b/sdk/package/lib/inits/setupUninstall.ts new file mode 100644 index 000000000..fc4a71b8e --- /dev/null +++ b/sdk/package/lib/inits/setupUninstall.ts @@ -0,0 +1,29 @@ +import * as T from "../../../base/lib/types" + +export type UninstallFn = (opts: { + effects: T.Effects +}) => Promise +export class Uninstall { + private constructor(readonly fn: UninstallFn) {} + static of( + fn: UninstallFn, + ) { + return new Uninstall(fn) + } + + async uninstall({ + effects, + nextVersion, + }: Parameters[0]) { + if (!nextVersion) + await this.fn({ + effects, + }) + } +} + +export function setupUninstall( + fn: UninstallFn, +) { + return Uninstall.of(fn) +} diff --git a/sdk/lib/mainFn/CommandController.ts b/sdk/package/lib/mainFn/CommandController.ts similarity index 75% rename from sdk/lib/mainFn/CommandController.ts rename to sdk/package/lib/mainFn/CommandController.ts index 8a0505f68..1aefc854f 100644 --- a/sdk/lib/mainFn/CommandController.ts +++ b/sdk/package/lib/mainFn/CommandController.ts @@ -1,15 +1,15 @@ import { DEFAULT_SIGTERM_TIMEOUT } from "." -import { NO_TIMEOUT, SIGKILL, SIGTERM } from "../StartSdk" +import { NO_TIMEOUT, SIGKILL, SIGTERM } from "../../../base/lib/types" -import * as T from "../types" -import { asError } from "../util/asError" +import * as T from "../../../base/lib/types" +import { asError } from "../../../base/lib/util/asError" import { ExecSpawnable, MountOptions, SubContainerHandle, SubContainer, } from "../util/SubContainer" -import { splitCommand } from "../util/splitCommand" +import { splitCommand } from "../util" import * as cp from "child_process" export class CommandController { @@ -17,10 +17,10 @@ export class CommandController { readonly runningAnswer: Promise, private state: { exited: boolean }, private readonly subcontainer: SubContainer, - private process: cp.ChildProcessWithoutNullStreams, + private process: cp.ChildProcess, readonly sigtermTimeout: number = DEFAULT_SIGTERM_TIMEOUT, ) {} - static of() { + static of() { return async ( effects: T.Effects, subcontainer: @@ -31,6 +31,7 @@ export class CommandController { | SubContainer, command: T.CommandType, options: { + subcontainerName?: string // Defaults to the DEFAULT_SIGTERM_TIMEOUT = 30_000ms sigtermTimeout?: number mounts?: { path: string; options: MountOptions }[] @@ -42,8 +43,8 @@ export class CommandController { | undefined cwd?: string | undefined user?: string | undefined - onStdout?: (x: Buffer) => void - onStderr?: (x: Buffer) => void + onStdout?: (chunk: Buffer | string | any) => void + onStderr?: (chunk: Buffer | string | any) => void }, ) => { const commands = splitCommand(command) @@ -51,13 +52,17 @@ export class CommandController { subcontainer instanceof SubContainer ? subcontainer : await (async () => { - const subc = await SubContainer.of(effects, subcontainer) + const subc = await SubContainer.of( + effects, + subcontainer, + options?.subcontainerName || commands.join(" "), + ) for (let mount of options.mounts || []) { await subc.mount(mount.options, mount.path) } return subc })() - let childProcess: cp.ChildProcessWithoutNullStreams + let childProcess: cp.ChildProcess if (options.runAsInit) { childProcess = await subc.launch(commands, { env: options.env, @@ -65,8 +70,13 @@ export class CommandController { } else { childProcess = await subc.spawn(commands, { env: options.env, + stdio: options.onStdout || options.onStderr ? "pipe" : "inherit", }) } + + if (options.onStdout) childProcess.stdout?.on("data", options.onStdout) + if (options.onStderr) childProcess.stderr?.on("data", options.onStderr) + const state = { exited: false } const answer = new Promise((resolve, reject) => { childProcess.on("exit", (code) => { @@ -119,6 +129,11 @@ export class CommandController { async term({ signal = SIGTERM, timeout = this.sigtermTimeout } = {}) { try { if (!this.state.exited) { + if (signal !== "SIGKILL") { + setTimeout(() => { + if (!this.state.exited) this.process.kill("SIGKILL") + }, timeout) + } if (!this.process.kill(signal)) { console.error( `failed to send signal ${signal} to pid ${this.process.pid}`, @@ -126,11 +141,6 @@ export class CommandController { } } - if (signal !== "SIGKILL") { - setTimeout(() => { - this.process.kill("SIGKILL") - }, timeout) - } await this.runningAnswer } finally { await this.subcontainer.destroy?.() diff --git a/sdk/lib/mainFn/Daemon.ts b/sdk/package/lib/mainFn/Daemon.ts similarity index 89% rename from sdk/lib/mainFn/Daemon.ts rename to sdk/package/lib/mainFn/Daemon.ts index 87a7d705d..d9db89b6a 100644 --- a/sdk/lib/mainFn/Daemon.ts +++ b/sdk/package/lib/mainFn/Daemon.ts @@ -1,5 +1,5 @@ -import * as T from "../types" -import { asError } from "../util/asError" +import * as T from "../../../base/lib/types" +import { asError } from "../../../base/lib/util/asError" import { ExecSpawnable, MountOptions, SubContainer } from "../util/SubContainer" import { CommandController } from "./CommandController" @@ -17,7 +17,7 @@ export class Daemon { get subContainerHandle(): undefined | ExecSpawnable { return this.commandController?.subContainerHandle } - static of() { + static of() { return async ( effects: T.Effects, subcontainer: @@ -28,6 +28,7 @@ export class Daemon { | SubContainer, command: T.CommandType, options: { + subcontainerName?: string mounts?: { path: string; options: MountOptions }[] env?: | { @@ -36,8 +37,8 @@ export class Daemon { | undefined cwd?: string | undefined user?: string | undefined - onStdout?: (x: Buffer) => void - onStderr?: (x: Buffer) => void + onStdout?: (chunk: Buffer | string | any) => void + onStderr?: (chunk: Buffer | string | any) => void sigtermTimeout?: number }, ) => { diff --git a/sdk/lib/mainFn/Daemons.ts b/sdk/package/lib/mainFn/Daemons.ts similarity index 83% rename from sdk/lib/mainFn/Daemons.ts rename to sdk/package/lib/mainFn/Daemons.ts index 1ecec28d3..cefa06698 100644 --- a/sdk/lib/mainFn/Daemons.ts +++ b/sdk/package/lib/mainFn/Daemons.ts @@ -1,19 +1,11 @@ -import { NO_TIMEOUT, SIGKILL, SIGTERM, Signals } from "../StartSdk" -import { HealthReceipt } from "../health/HealthReceipt" +import { HealthReceipt, Signals } from "../../../base/lib/types" + import { HealthCheckResult } from "../health/checkFns" import { Trigger } from "../trigger" -import { TriggerInput } from "../trigger/TriggerInput" -import { defaultTrigger } from "../trigger/defaultTrigger" -import * as T from "../types" +import * as T from "../../../base/lib/types" import { Mounts } from "./Mounts" -import { - CommandOptions, - ExecSpawnable, - MountOptions, - SubContainer, -} from "../util/SubContainer" -import { splitCommand } from "../util/splitCommand" +import { ExecSpawnable, MountOptions } from "../util/SubContainer" import { promisify } from "node:util" import * as CP from "node:child_process" @@ -35,7 +27,7 @@ export type Ready = { } type DaemonsParams< - Manifest extends T.Manifest, + Manifest extends T.SDKManifest, Ids extends string, Command extends string, Id extends string, @@ -47,11 +39,13 @@ type DaemonsParams< ready: Ready requires: Exclude[] sigtermTimeout?: number + onStdout?: (chunk: Buffer | string | any) => void + onStderr?: (chunk: Buffer | string | any) => void } type ErrorDuplicateId = `The id '${Id}' is already used` -export const runCommand = () => +export const runCommand = () => CommandController.of() /** @@ -77,32 +71,34 @@ Daemons.of({ }) ``` */ -export class Daemons { +export class Daemons + implements T.DaemonBuildable +{ private constructor( readonly effects: T.Effects, - readonly started: (onTerm: () => PromiseLike) => PromiseLike, + readonly started: (onTerm: () => PromiseLike) => PromiseLike, readonly daemons: Promise[], readonly ids: Ids[], readonly healthDaemons: HealthDaemon[], ) {} /** - * Returns an empty new Daemons class with the provided config. + * Returns an empty new Daemons class with the provided inputSpec. * * Call .addDaemon() on the returned class to add a daemon. * * Daemons run in the order they are defined, with latter daemons being capable of * depending on prior daemons - * @param config + * @param options * @returns */ - static of(config: { + static of(options: { effects: T.Effects - started: (onTerm: () => PromiseLike) => PromiseLike + started: (onTerm: () => PromiseLike) => PromiseLike healthReceipts: HealthReceipt[] }) { return new Daemons( - config.effects, - config.started, + options.effects, + options.started, [], [], [], @@ -127,6 +123,7 @@ export class Daemons { const daemon = Daemon.of()(this.effects, options.image, options.command, { ...options, mounts: options.mounts.build(), + subcontainerName: id, }) const healthDaemon = new HealthDaemon( daemon, diff --git a/sdk/lib/mainFn/HealthDaemon.ts b/sdk/package/lib/mainFn/HealthDaemon.ts similarity index 95% rename from sdk/lib/mainFn/HealthDaemon.ts rename to sdk/package/lib/mainFn/HealthDaemon.ts index 7ace3ed7b..b66e3e406 100644 --- a/sdk/lib/mainFn/HealthDaemon.ts +++ b/sdk/package/lib/mainFn/HealthDaemon.ts @@ -2,9 +2,9 @@ import { HealthCheckResult } from "../health/checkFns" import { defaultTrigger } from "../trigger/defaultTrigger" import { Ready } from "./Daemons" import { Daemon } from "./Daemon" -import { Effects, SetHealth } from "../types" +import { SetHealth, Effects } from "../../../base/lib/types" import { DEFAULT_SIGTERM_TIMEOUT } from "." -import { asError } from "../util/asError" +import { asError } from "../../../base/lib/util/asError" const oncePromise = () => { let resolve: (value: T) => void @@ -81,7 +81,7 @@ export class HealthDaemon { } } - private healthCheckCleanup: (() => void) | null = null + private healthCheckCleanup: (() => null) | null = null private turnOffHealthCheck() { this.healthCheckCleanup?.() } @@ -125,6 +125,7 @@ export class HealthDaemon { this.healthCheckCleanup = () => { setStatus({ done: true }) this.healthCheckCleanup = null + return null } } diff --git a/sdk/lib/mainFn/Mounts.ts b/sdk/package/lib/mainFn/Mounts.ts similarity index 92% rename from sdk/lib/mainFn/Mounts.ts rename to sdk/package/lib/mainFn/Mounts.ts index bd947b759..38b3ce2a7 100644 --- a/sdk/lib/mainFn/Mounts.ts +++ b/sdk/package/lib/mainFn/Mounts.ts @@ -1,9 +1,9 @@ -import * as T from "../types" +import * as T from "../../../base/lib/types" import { MountOptions } from "../util/SubContainer" type MountArray = { path: string; options: MountOptions }[] -export class Mounts { +export class Mounts { private constructor( readonly volumes: { id: Manifest["volumes"][number] @@ -25,7 +25,7 @@ export class Mounts { }[], ) {} - static of() { + static of() { return new Mounts([], [], []) } @@ -57,7 +57,7 @@ export class Mounts { return this } - addDependency( + addDependency( dependencyId: keyof Manifest["dependencies"] & string, volumeId: DependencyManifest["volumes"][number], subpath: string | null, diff --git a/sdk/lib/mainFn/index.ts b/sdk/package/lib/mainFn/index.ts similarity index 63% rename from sdk/lib/mainFn/index.ts rename to sdk/package/lib/mainFn/index.ts index 7a094a31a..be30c652d 100644 --- a/sdk/lib/mainFn/index.ts +++ b/sdk/package/lib/mainFn/index.ts @@ -1,11 +1,7 @@ -import * as T from "../types" +import * as T from "../../../base/lib/types" import { Daemons } from "./Daemons" -import "../interfaces/ServiceInterfaceBuilder" -import "../interfaces/Origin" - -import "./Daemons" - -import { MainEffects } from "../StartSdk" +import "../../../base/lib/interfaces/ServiceInterfaceBuilder" +import "../../../base/lib/interfaces/Origin" export const DEFAULT_SIGTERM_TIMEOUT = 30_000 /** @@ -18,10 +14,10 @@ export const DEFAULT_SIGTERM_TIMEOUT = 30_000 * @param fn * @returns */ -export const setupMain = ( +export const setupMain = ( fn: (o: { - effects: MainEffects - started(onTerm: () => PromiseLike): PromiseLike + effects: T.Effects + started(onTerm: () => PromiseLike): PromiseLike }) => Promise>, ): T.ExpectedExports.main => { return async (options) => { diff --git a/sdk/lib/manifest/setupManifest.ts b/sdk/package/lib/manifest/setupManifest.ts similarity index 57% rename from sdk/lib/manifest/setupManifest.ts rename to sdk/package/lib/manifest/setupManifest.ts index 10aaa03db..5dfdb2451 100644 --- a/sdk/lib/manifest/setupManifest.ts +++ b/sdk/package/lib/manifest/setupManifest.ts @@ -1,15 +1,43 @@ -import * as T from "../types" -import { ImageConfig, ImageId, VolumeId } from "../osBindings" -import { SDKManifest, SDKImageConfig } from "./ManifestTypes" +import * as T from "../../../base/lib/types" +import { ImageConfig, ImageId, VolumeId } from "../../../base/lib/types" +import { + SDKManifest, + SDKImageInputSpec, +} from "../../../base/lib/types/ManifestTypes" import { SDKVersion } from "../StartSdk" import { VersionGraph } from "../version/VersionGraph" +import { execSync } from "child_process" /** - * This is an example of a function that takes a manifest and returns a new manifest with additional properties - * @param manifest Manifests are the description of the package - * @returns The manifest with additional properties + * @description Use this function to define critical information about your package + * + * @param versions Every version of the package, imported from ./versions + * @param manifest Static properties of the package */ export function setupManifest< + Id extends string, + VolumesTypes extends VolumeId, + AssetTypes extends VolumeId, + Manifest extends { + id: Id + assets: AssetTypes[] + volumes: VolumesTypes[] + } & SDKManifest, +>(manifest: Manifest): Manifest { + return manifest +} + +function gitHash(): string { + const hash = execSync("git rev-parse HEAD").toString().trim() + try { + execSync("git diff-index --quiet HEAD --") + return hash + } catch (e) { + return hash + "-modified" + } +} + +export function buildManifest< Id extends string, Version extends string, Dependencies extends Record, @@ -20,10 +48,9 @@ export function setupManifest< dependencies: Dependencies id: Id assets: AssetTypes[] - images: Record + images: Record volumes: VolumesTypes[] }, - Satisfies extends string[] = [], >( versions: VersionGraph, manifest: SDKManifest & Manifest, @@ -32,7 +59,9 @@ export function setupManifest< (images, [k, v]) => { v.arch = v.arch || ["aarch64", "x86_64"] if (v.emulateMissingAs === undefined) - v.emulateMissingAs = v.arch[0] || null + v.emulateMissingAs = (v.arch as string[]).includes("aarch64") + ? "aarch64" + : v.arch[0] || null images[k] = v as ImageConfig return images }, @@ -40,7 +69,7 @@ export function setupManifest< ) return { ...manifest, - gitHash: null, + gitHash: gitHash(), osVersion: SDKVersion, version: versions.current.options.version, releaseNotes: versions.current.options.releaseNotes, @@ -56,25 +85,20 @@ export function setupManifest< start: manifest.alerts?.start || null, stop: manifest.alerts?.stop || null, }, - hasConfig: manifest.hasConfig === undefined ? true : manifest.hasConfig, hardwareRequirements: { - device: Object.fromEntries( - Object.entries(manifest.hardwareRequirements?.device || {}).map( - ([k, v]) => [k, v.source], - ), - ), + device: manifest.hardwareRequirements?.device || [], ram: manifest.hardwareRequirements?.ram || null, arch: manifest.hardwareRequirements?.arch === undefined ? Object.values(images).reduce( - (arch, config) => { - if (config.emulateMissingAs) { + (arch, inputSpec) => { + if (inputSpec.emulateMissingAs) { return arch } if (arch === null) { - return config.arch + return inputSpec.arch } - return arch.filter((a) => config.arch.includes(a)) + return arch.filter((a) => inputSpec.arch.includes(a)) }, null as string[] | null, ) diff --git a/sdk/lib/store/getStore.ts b/sdk/package/lib/store/getStore.ts similarity index 90% rename from sdk/lib/store/getStore.ts rename to sdk/package/lib/store/getStore.ts index 5250a02a1..3bde46a25 100644 --- a/sdk/lib/store/getStore.ts +++ b/sdk/package/lib/store/getStore.ts @@ -1,5 +1,5 @@ -import { Effects } from "../types" -import { PathBuilder, extractJsonPath } from "./PathBuilder" +import { Effects } from "../../../base/lib/Effects" +import { PathBuilder, extractJsonPath } from "../util" export class GetStore { constructor( @@ -18,7 +18,7 @@ export class GetStore { return this.effects.store.get({ ...this.options, path: extractJsonPath(this.path), - callback: this.effects.restart, + callback: () => this.effects.constRetry(), }) } /** diff --git a/sdk/package/lib/store/setupExposeStore.ts b/sdk/package/lib/store/setupExposeStore.ts new file mode 100644 index 000000000..1ae0bf13f --- /dev/null +++ b/sdk/package/lib/store/setupExposeStore.ts @@ -0,0 +1,28 @@ +import { ExposedStorePaths } from "../../../base/lib/types" +import { Affine, _ } from "../util" +import { + PathBuilder, + extractJsonPath, + pathBuilder, +} from "../../../base/lib/util/PathBuilder" + +/** + * @description Use this function to determine which Store values to expose and make available to other services running on StartOS. Store values not exposed here will be kept private. Use the type safe pathBuilder to traverse your Store's structure. + * @example + * In this example, we expose the hypothetical Store values "adminPassword" and "nameLastUpdatedAt". + * + * ``` + export const exposedStore = setupExposeStore((pathBuilder) => [ + pathBuilder.adminPassword + pathBuilder.nameLastUpdatedAt, + ]) + * ``` + */ +export const setupExposeStore = >( + fn: (pathBuilder: PathBuilder) => PathBuilder[], +) => { + return fn(pathBuilder()).map( + (x) => extractJsonPath(x) as string, + ) as ExposedStorePaths +} +export { ExposedStorePaths } diff --git a/sdk/lib/test/health.readyCheck.test.ts b/sdk/package/lib/test/health.readyCheck.test.ts similarity index 100% rename from sdk/lib/test/health.readyCheck.test.ts rename to sdk/package/lib/test/health.readyCheck.test.ts diff --git a/sdk/lib/test/host.test.ts b/sdk/package/lib/test/host.test.ts similarity index 78% rename from sdk/lib/test/host.test.ts rename to sdk/package/lib/test/host.test.ts index 64d486a94..87f22b8bd 100644 --- a/sdk/lib/test/host.test.ts +++ b/sdk/package/lib/test/host.test.ts @@ -1,6 +1,6 @@ -import { ServiceInterfaceBuilder } from "../interfaces/ServiceInterfaceBuilder" -import { Effects } from "../types" -import { sdk } from "./output.sdk" +import { ServiceInterfaceBuilder } from "../../../base/lib/interfaces/ServiceInterfaceBuilder" +import { Effects } from "../../../base/lib/Effects" +import { sdk } from "../test/output.sdk" describe("host", () => { test("Testing that the types work", () => { diff --git a/sdk/lib/test/configBuilder.test.ts b/sdk/package/lib/test/inputSpecBuilder.test.ts similarity index 79% rename from sdk/lib/test/configBuilder.test.ts rename to sdk/package/lib/test/inputSpecBuilder.test.ts index 5c65271a8..27869067d 100644 --- a/sdk/lib/test/configBuilder.test.ts +++ b/sdk/package/lib/test/inputSpecBuilder.test.ts @@ -1,9 +1,9 @@ import { testOutput } from "./output.test" -import { Config } from "../config/builder/config" -import { List } from "../config/builder/list" -import { Value } from "../config/builder/value" -import { Variants } from "../config/builder/variants" -import { ValueSpec } from "../config/configTypes" +import { InputSpec } from "../../../base/lib/actions/input/builder/inputSpec" +import { List } from "../../../base/lib/actions/input/builder/list" +import { Value } from "../../../base/lib/actions/input/builder/value" +import { Variants } from "../../../base/lib/actions/input/builder/variants" +import { ValueSpec } from "../../../base/lib/actions/input/inputSpecTypes" import { setupManifest } from "../manifest/setupManifest" import { StartSdk } from "../StartSdk" import { VersionGraph } from "../version/VersionGraph" @@ -13,11 +13,12 @@ describe("builder tests", () => { test("text", async () => { const bitcoinPropertiesBuilt: { "peer-tor-address": ValueSpec - } = await Config.of({ + } = await InputSpec.of({ "peer-tor-address": Value.text({ name: "Peer tor address", description: "The Tor address of the peer interface", - required: { default: null }, + required: true, + default: null, }), }).build({} as any) expect(bitcoinPropertiesBuilt).toMatchObject({ @@ -55,7 +56,8 @@ describe("values", () => { test("text", async () => { const value = Value.text({ name: "Testing", - required: { default: null }, + required: true, + default: null, }) const validator = value.validator const rawIs = await value.build({} as any) @@ -66,7 +68,8 @@ describe("values", () => { test("text with default", async () => { const value = Value.text({ name: "Testing", - required: { default: "this is a default value" }, + required: true, + default: "this is a default value", }) const validator = value.validator const rawIs = await value.build({} as any) @@ -78,28 +81,31 @@ describe("values", () => { const value = Value.text({ name: "Testing", required: false, + default: null, }) const validator = value.validator const rawIs = await value.build({} as any) validator.unsafeCast("test text") validator.unsafeCast(null) - testOutput()(null) + testOutput()(null) }) test("color", async () => { const value = Value.color({ name: "Testing", required: false, + default: null, description: null, warning: null, }) const validator = value.validator validator.unsafeCast("#000000") - testOutput()(null) + testOutput()(null) }) test("datetime", async () => { const value = Value.datetime({ name: "Testing", - required: { default: null }, + required: true, + default: null, description: null, warning: null, inputmode: "date", @@ -114,6 +120,7 @@ describe("values", () => { const value = Value.datetime({ name: "Testing", required: false, + default: null, description: null, warning: null, inputmode: "date", @@ -122,12 +129,13 @@ describe("values", () => { }) const validator = value.validator validator.unsafeCast("2021-01-01") - testOutput()(null) + testOutput()(null) }) test("textarea", async () => { const value = Value.textarea({ name: "Testing", required: false, + default: null, description: null, warning: null, minLength: null, @@ -136,12 +144,13 @@ describe("values", () => { }) const validator = value.validator validator.unsafeCast("test text") - testOutput()(null) + testOutput()(null) }) test("number", async () => { const value = Value.number({ name: "Testing", - required: { default: null }, + required: true, + default: null, integer: false, description: null, warning: null, @@ -159,6 +168,7 @@ describe("values", () => { const value = Value.number({ name: "Testing", required: false, + default: null, integer: false, description: null, warning: null, @@ -170,12 +180,12 @@ describe("values", () => { }) const validator = value.validator validator.unsafeCast(2) - testOutput()(null) + testOutput()(null) }) test("select", async () => { const value = Value.select({ name: "Testing", - required: { default: null }, + default: "a", values: { a: "A", b: "B", @@ -192,7 +202,7 @@ describe("values", () => { test("nullable select", async () => { const value = Value.select({ name: "Testing", - required: false, + default: "a", values: { a: "A", b: "B", @@ -203,8 +213,7 @@ describe("values", () => { const validator = value.validator validator.unsafeCast("a") validator.unsafeCast("b") - validator.unsafeCast(null) - testOutput()(null) + testOutput()(null) }) test("multiselect", async () => { const value = Value.multiselect({ @@ -232,9 +241,8 @@ describe("values", () => { { name: "Testing", description: null, - warning: null, }, - Config.of({ + InputSpec.of({ a: Value.toggle({ name: "test", description: null, @@ -251,14 +259,14 @@ describe("values", () => { const value = Value.union( { name: "Testing", - required: { default: null }, + default: "a", description: null, warning: null, }, Variants.of({ a: { name: "a", - spec: Config.of({ + spec: InputSpec.of({ b: Value.toggle({ name: "b", description: null, @@ -272,12 +280,21 @@ describe("values", () => { const validator = value.validator validator.unsafeCast({ selection: "a", value: { b: false } }) type Test = typeof validator._TYPE - testOutput()(null) + testOutput< + Test, + { + selection: "a" + value: { + b: boolean + } + other?: {} + } + >()(null) }) describe("dynamic", () => { const fakeOptions = { - config: "config", + inputSpec: "inputSpec", effects: "effects", utils: "utils", } as any @@ -302,31 +319,33 @@ describe("values", () => { test("text", async () => { const value = Value.dynamicText(async () => ({ name: "Testing", - required: { default: null }, + required: false, + default: null, })) const validator = value.validator const rawIs = await value.build({} as any) validator.unsafeCast("test text") validator.unsafeCast(null) - testOutput()(null) + testOutput()(null) expect(await value.build(fakeOptions)).toMatchObject({ name: "Testing", - required: true, + required: false, default: null, }) }) test("text with default", async () => { const value = Value.dynamicText(async () => ({ name: "Testing", - required: { default: "this is a default value" }, + required: false, + default: "this is a default value", })) const validator = value.validator validator.unsafeCast("test text") validator.unsafeCast(null) - testOutput()(null) + testOutput()(null) expect(await value.build(fakeOptions)).toMatchObject({ name: "Testing", - required: true, + required: false, default: "this is a default value", }) }) @@ -334,12 +353,13 @@ describe("values", () => { const value = Value.dynamicText(async () => ({ name: "Testing", required: false, + default: null, })) const validator = value.validator const rawIs = await value.build({} as any) validator.unsafeCast("test text") validator.unsafeCast(null) - testOutput()(null) + testOutput()(null) expect(await value.build(fakeOptions)).toMatchObject({ name: "Testing", required: false, @@ -350,13 +370,14 @@ describe("values", () => { const value = Value.dynamicColor(async () => ({ name: "Testing", required: false, + default: null, description: null, warning: null, })) const validator = value.validator validator.unsafeCast("#000000") validator.unsafeCast(null) - testOutput()(null) + testOutput()(null) expect(await value.build(fakeOptions)).toMatchObject({ name: "Testing", required: false, @@ -368,48 +389,39 @@ describe("values", () => { test("datetime", async () => { const sdk = StartSdk.of() .withManifest( - setupManifest( - VersionGraph.of( - VersionInfo.of({ - version: "1.0.0:0", - releaseNotes: "", - migrations: {}, - }), - ), - { - id: "testOutput", - title: "", - license: "", - wrapperRepo: "", - upstreamRepo: "", - supportSite: "", - marketingSite: "", - donationUrl: null, - description: { - short: "", - long: "", - }, - containers: {}, - images: {}, - volumes: [], - assets: [], - alerts: { - install: null, - update: null, - uninstall: null, - restore: null, - start: null, - stop: null, - }, - dependencies: { - "remote-test": { - description: "", - optional: true, - s9pk: "https://example.com/remote-test.s9pk", - }, + setupManifest({ + id: "testOutput", + title: "", + license: "", + wrapperRepo: "", + upstreamRepo: "", + supportSite: "", + marketingSite: "", + donationUrl: null, + description: { + short: "", + long: "", + }, + containers: {}, + images: {}, + volumes: [], + assets: [], + alerts: { + install: null, + update: null, + uninstall: null, + restore: null, + start: null, + stop: null, + }, + dependencies: { + "remote-test": { + description: "", + optional: true, + s9pk: "https://example.com/remote-test.s9pk", }, }, - ), + }), ) .withStore<{ test: "a" }>() .build(true) @@ -424,7 +436,8 @@ describe("values", () => { return { name: "Testing", - required: { default: null }, + required: true, + default: null, inputmode: "date", } }, @@ -432,7 +445,7 @@ describe("values", () => { const validator = value.validator validator.unsafeCast("2021-01-01") validator.unsafeCast(null) - testOutput()(null) + testOutput()(null) expect(await value.build(fakeOptions)).toMatchObject({ name: "Testing", required: true, @@ -446,6 +459,7 @@ describe("values", () => { const value = Value.dynamicTextarea(async () => ({ name: "Testing", required: false, + default: null, description: null, warning: null, minLength: null, @@ -454,8 +468,7 @@ describe("values", () => { })) const validator = value.validator validator.unsafeCast("test text") - expect(() => validator.unsafeCast(null)).toThrowError() - testOutput()(null) + testOutput()(null) expect(await value.build(fakeOptions)).toMatchObject({ name: "Testing", required: false, @@ -464,7 +477,8 @@ describe("values", () => { test("number", async () => { const value = Value.dynamicNumber(() => ({ name: "Testing", - required: { default: null }, + required: true, + default: null, integer: false, description: null, warning: null, @@ -478,7 +492,7 @@ describe("values", () => { validator.unsafeCast(2) validator.unsafeCast(null) expect(() => validator.unsafeCast("null")).toThrowError() - testOutput()(null) + testOutput()(null) expect(await value.build(fakeOptions)).toMatchObject({ name: "Testing", required: true, @@ -487,7 +501,7 @@ describe("values", () => { test("select", async () => { const value = Value.dynamicSelect(() => ({ name: "Testing", - required: { default: null }, + default: "a", values: { a: "A", b: "B", @@ -499,11 +513,9 @@ describe("values", () => { validator.unsafeCast("a") validator.unsafeCast("b") validator.unsafeCast("c") - validator.unsafeCast(null) - testOutput()(null) + testOutput()(null) expect(await value.build(fakeOptions)).toMatchObject({ name: "Testing", - required: true, }) }) test("multiselect", async () => { @@ -539,14 +551,14 @@ describe("values", () => { () => ["a", "c"], { name: "Testing", - required: { default: null }, + default: "a", description: null, warning: null, }, Variants.of({ a: { name: "a", - spec: Config.of({ + spec: InputSpec.of({ b: Value.toggle({ name: "b", description: null, @@ -557,7 +569,7 @@ describe("values", () => { }, b: { name: "b", - spec: Config.of({ + spec: InputSpec.of({ b: Value.toggle({ name: "b", description: null, @@ -573,8 +585,28 @@ describe("values", () => { type Test = typeof validator._TYPE testOutput< Test, - | { selection: "a"; value: { b: boolean } } - | { selection: "b"; value: { b: boolean } } + | { + selection: "a" + value: { + b: boolean + } + other?: { + b?: { + b?: boolean + } + } + } + | { + selection: "b" + value: { + b: boolean + } + other?: { + a?: { + b?: boolean + } + } + } >()(null) const built = await value.build({} as any) @@ -606,14 +638,14 @@ describe("values", () => { () => ({ disabled: ["a", "c"], name: "Testing", - required: { default: null }, + default: "b", description: null, warning: null, }), Variants.of({ a: { name: "a", - spec: Config.of({ + spec: InputSpec.of({ b: Value.toggle({ name: "b", description: null, @@ -624,7 +656,7 @@ describe("values", () => { }, b: { name: "b", - spec: Config.of({ + spec: InputSpec.of({ b: Value.toggle({ name: "b", description: null, @@ -640,10 +672,28 @@ describe("values", () => { type Test = typeof validator._TYPE testOutput< Test, - | { selection: "a"; value: { b: boolean } } - | { selection: "b"; value: { b: boolean } } - | null - | undefined + | { + selection: "a" + value: { + b: boolean + } + other?: { + b?: { + b?: boolean + } + } + } + | { + selection: "b" + value: { + b: boolean + } + other?: { + a?: { + b?: boolean + } + } + } >()(null) const built = await value.build({} as any) @@ -679,7 +729,7 @@ describe("Builder List", () => { name: "test", }, { - spec: Config.of({ + spec: InputSpec.of({ test: Value.toggle({ name: "test", description: null, @@ -732,27 +782,29 @@ describe("Builder List", () => { describe("Nested nullable values", () => { test("Testing text", async () => { - const value = Config.of({ + const value = InputSpec.of({ a: Value.text({ name: "Temp Name", description: - "If no name is provided, the name from config will be used", + "If no name is provided, the name from inputSpec will be used", required: false, + default: null, }), }) const validator = value.validator validator.unsafeCast({ a: null }) validator.unsafeCast({ a: "test" }) expect(() => validator.unsafeCast({ a: 4 })).toThrowError() - testOutput()(null) + testOutput()(null) }) test("Testing number", async () => { - const value = Config.of({ + const value = InputSpec.of({ a: Value.number({ name: "Temp Name", description: - "If no name is provided, the name from config will be used", + "If no name is provided, the name from inputSpec will be used", required: false, + default: null, warning: null, placeholder: null, integer: false, @@ -766,15 +818,16 @@ describe("Nested nullable values", () => { validator.unsafeCast({ a: null }) validator.unsafeCast({ a: 5 }) expect(() => validator.unsafeCast({ a: "4" })).toThrowError() - testOutput()(null) + testOutput()(null) }) test("Testing color", async () => { - const value = Config.of({ + const value = InputSpec.of({ a: Value.color({ name: "Temp Name", description: - "If no name is provided, the name from config will be used", + "If no name is provided, the name from inputSpec will be used", required: false, + default: null, warning: null, }), }) @@ -782,15 +835,15 @@ describe("Nested nullable values", () => { validator.unsafeCast({ a: null }) validator.unsafeCast({ a: "5" }) expect(() => validator.unsafeCast({ a: 4 })).toThrowError() - testOutput()(null) + testOutput()(null) }) test("Testing select", async () => { - const value = Config.of({ + const value = InputSpec.of({ a: Value.select({ name: "Temp Name", description: - "If no name is provided, the name from config will be used", - required: false, + "If no name is provided, the name from inputSpec will be used", + default: "a", warning: null, values: { a: "A", @@ -799,8 +852,9 @@ describe("Nested nullable values", () => { }) const higher = await Value.select({ name: "Temp Name", - description: "If no name is provided, the name from config will be used", - required: false, + description: + "If no name is provided, the name from inputSpec will be used", + default: "a", warning: null, values: { a: "A", @@ -808,17 +862,16 @@ describe("Nested nullable values", () => { }).build({} as any) const validator = value.validator - validator.unsafeCast({ a: null }) validator.unsafeCast({ a: "a" }) expect(() => validator.unsafeCast({ a: "4" })).toThrowError() - testOutput()(null) + testOutput()(null) }) test("Testing multiselect", async () => { - const value = Config.of({ + const value = InputSpec.of({ a: Value.multiselect({ name: "Temp Name", description: - "If no name is provided, the name from config will be used", + "If no name is provided, the name from inputSpec will be used", warning: null, default: [], diff --git a/sdk/lib/test/makeOutput.ts b/sdk/package/lib/test/makeOutput.ts similarity index 99% rename from sdk/lib/test/makeOutput.ts rename to sdk/package/lib/test/makeOutput.ts index cef17a7e8..434484be9 100644 --- a/sdk/lib/test/makeOutput.ts +++ b/sdk/package/lib/test/makeOutput.ts @@ -3,7 +3,7 @@ import { oldSpecToBuilder } from "../../scripts/oldSpecToBuilder" oldSpecToBuilder( // Make the location "./lib/test/output.ts", - // Put the config here + // Put the inputSpec here { mediasources: { type: "list", diff --git a/sdk/package/lib/test/output.sdk.ts b/sdk/package/lib/test/output.sdk.ts new file mode 100644 index 000000000..3f3bb5411 --- /dev/null +++ b/sdk/package/lib/test/output.sdk.ts @@ -0,0 +1,53 @@ +import { CurrentDependenciesResult } from "../../../base/lib/dependencies/setupDependencies" +import { StartSdk } from "../StartSdk" +import { setupManifest } from "../manifest/setupManifest" +import { VersionGraph } from "../version/VersionGraph" + +export type Manifest = any +export const sdk = StartSdk.of() + .withManifest( + setupManifest({ + id: "testOutput", + title: "", + license: "", + replaces: [], + wrapperRepo: "", + upstreamRepo: "", + supportSite: "", + marketingSite: "", + donationUrl: null, + description: { + short: "", + long: "", + }, + containers: {}, + images: { + main: { + source: { + dockerTag: "start9/hello-world", + }, + arch: ["aarch64", "x86_64"], + emulateMissingAs: "aarch64", + }, + }, + volumes: [], + assets: [], + alerts: { + install: null, + update: null, + uninstall: null, + restore: null, + start: null, + stop: null, + }, + dependencies: { + "remote-test": { + description: "", + optional: false, + s9pk: "https://example.com/remote-test.s9pk", + }, + }, + }), + ) + .withStore<{ storeRoot: { storeLeaf: "value" } }>() + .build(true) diff --git a/sdk/lib/test/output.test.ts b/sdk/package/lib/test/output.test.ts similarity index 71% rename from sdk/lib/test/output.test.ts rename to sdk/package/lib/test/output.test.ts index 1df84f3af..a2e9c35d5 100644 --- a/sdk/lib/test/output.test.ts +++ b/sdk/package/lib/test/output.test.ts @@ -1,7 +1,7 @@ -import { ConfigSpec, matchConfigSpec } from "./output" +import { InputSpecSpec, matchInputSpecSpec } from "./output" import * as _I from "../index" import { camelCase } from "../../scripts/oldSpecToBuilder" -import { deepMerge } from "../util/deepMerge" +import { deepMerge } from "../../../base/lib/util" export type IfEquals = (() => G extends T ? 1 : 2) extends () => G extends U ? 1 : 2 ? Y : N @@ -10,37 +10,40 @@ export function testOutput(): (c: IfEquals) => null { } /// Testing the types of the input spec -testOutput()(null) -testOutput()(null) -testOutput()(null) +testOutput()(null) +testOutput()(null) +testOutput()(null) -testOutput()(null) +testOutput()(null) testOutput< - ConfigSpec["rpc"]["advanced"]["serialversion"], + InputSpecSpec["rpc"]["advanced"]["serialversion"], "segwit" | "non-segwit" >()(null) -testOutput()(null) +testOutput()(null) testOutput< - ConfigSpec["advanced"]["peers"]["addnode"][0]["hostname"], - string | null | undefined + InputSpecSpec["advanced"]["peers"]["addnode"][0]["hostname"], + string | null >()(null) -testOutput()( +testOutput< + InputSpecSpec["testListUnion"][0]["union"]["value"]["name"], + string +>()(null) +testOutput()( null, ) -testOutput()(null) -testOutput>()( +testOutput>()( null, ) // @ts-expect-error Because enable should be a boolean -testOutput()(null) +testOutput()(null) // prettier-ignore // @ts-expect-error Expect that the string is the one above -testOutput()(null); +testOutput()(null); -/// Here we test the output of the matchConfigSpec function +/// Here we test the output of the matchInputSpecSpec function describe("Inputs", () => { - const validInput: ConfigSpec = { + const validInput: InputSpecSpec = { mediasources: ["filebrowser"], testListUnion: [ { @@ -84,7 +87,7 @@ describe("Inputs", () => { dbcache: 5, pruning: { selection: "disabled", - value: {}, + value: { disabled: {} }, }, blockfilters: { blockfilterindex: false, @@ -95,24 +98,24 @@ describe("Inputs", () => { } test("test valid input", () => { - const output = matchConfigSpec.unsafeCast(validInput) + const output = matchInputSpecSpec.unsafeCast(validInput) expect(output).toEqual(validInput) }) test("test no longer care about the conversion of min/max and validating", () => { - matchConfigSpec.unsafeCast( + matchInputSpecSpec.unsafeCast( deepMerge({}, validInput, { rpc: { advanced: { threads: 0 } } }), ) }) test("test errors should throw for number in string", () => { expect(() => - matchConfigSpec.unsafeCast( + matchInputSpecSpec.unsafeCast( deepMerge({}, validInput, { rpc: { enable: 2 } }), ), ).toThrowError() }) test("Test that we set serialversion to something not segwit or non-segwit", () => { expect(() => - matchConfigSpec.unsafeCast( + matchInputSpecSpec.unsafeCast( deepMerge({}, validInput, { rpc: { advanced: { serialversion: "testing" } }, }), diff --git a/sdk/lib/test/store.test.ts b/sdk/package/lib/test/store.test.ts similarity index 52% rename from sdk/lib/test/store.test.ts rename to sdk/package/lib/test/store.test.ts index fa7bc4a4c..f876e76d8 100644 --- a/sdk/lib/test/store.test.ts +++ b/sdk/package/lib/test/store.test.ts @@ -1,9 +1,9 @@ -import { MainEffects, StartSdk } from "../StartSdk" -import { extractJsonPath } from "../store/PathBuilder" -import { Effects } from "../types" +import { Effects } from "../../../base/lib/types" +import { extractJsonPath } from "../../../base/lib/util/PathBuilder" +import { StartSdk } from "../StartSdk" type Store = { - config: { + inputSpec: { someValue: "a" | "b" } } @@ -23,16 +23,16 @@ const storePath = sdk.StorePath describe("Store", () => { test("types", async () => { ;async () => { - sdk.store.setOwn(todo(), storePath.config, { + sdk.store.setOwn(todo(), storePath.inputSpec, { someValue: "a", }) - sdk.store.setOwn(todo(), storePath.config.someValue, "b") + sdk.store.setOwn(todo(), storePath.inputSpec.someValue, "b") sdk.store.setOwn(todo(), storePath, { - config: { someValue: "b" }, + inputSpec: { someValue: "b" }, }) sdk.store.setOwn( todo(), - storePath.config.someValue, + storePath.inputSpec.someValue, // @ts-expect-error Type is wrong for the setting value 5, @@ -40,73 +40,70 @@ describe("Store", () => { sdk.store.setOwn( todo(), // @ts-expect-error Path is wrong - "/config/someVae3lue", + "/inputSpec/someVae3lue", "someValue", ) todo().store.set({ - path: extractJsonPath(storePath.config.someValue), + path: extractJsonPath(storePath.inputSpec.someValue), value: "b", }) - todo().store.set({ - path: extractJsonPath(storePath.config.someValue), + todo().store.set({ + path: extractJsonPath(storePath.inputSpec.someValue), //@ts-expect-error Path is wrong value: "someValueIn", }) ;(await sdk.store - .getOwn(todo(), storePath.config.someValue) + .getOwn(todo(), storePath.inputSpec.someValue) .const()) satisfies string ;(await sdk.store - .getOwn(todo(), storePath.config) - .const()) satisfies Store["config"] + .getOwn(todo(), storePath.inputSpec) + .const()) satisfies Store["inputSpec"] await sdk.store // @ts-expect-error Path is wrong - .getOwn(todo(), "/config/somdsfeValue") + .getOwn(todo(), "/inputSpec/somdsfeValue") .const() /// ----------------- ERRORS ----------------- - sdk.store.setOwn(todo(), storePath, { + sdk.store.setOwn(todo(), storePath, { // @ts-expect-error Type is wrong for the setting value - config: { someValue: "notInAOrB" }, + inputSpec: { someValue: "notInAOrB" }, }) sdk.store.setOwn( - todo(), - sdk.StorePath.config.someValue, + todo(), + sdk.StorePath.inputSpec.someValue, // @ts-expect-error Type is wrong for the setting value "notInAOrB", ) ;(await sdk.store - .getOwn(todo(), storePath.config.someValue) - // @ts-expect-error Const should normally not be callable + .getOwn(todo(), storePath.inputSpec.someValue) .const()) satisfies string ;(await sdk.store - .getOwn(todo(), storePath.config) - // @ts-expect-error Const should normally not be callable - .const()) satisfies Store["config"] + .getOwn(todo(), storePath.inputSpec) + .const()) satisfies Store["inputSpec"] await sdk.store // @ts-expect-error Path is wrong - .getOwn("/config/somdsfeValue") - // @ts-expect-error Const should normally not be callable + .getOwn("/inputSpec/somdsfeValue") .const() /// ;(await sdk.store - .getOwn(todo(), storePath.config.someValue) + .getOwn(todo(), storePath.inputSpec.someValue) // @ts-expect-error satisfies type is wrong .const()) satisfies number await sdk.store // @ts-expect-error Path is wrong - .getOwn(todo(), extractJsonPath(storePath.config)) + .getOwn(todo(), extractJsonPath(storePath.inputSpec)) .const() ;(await todo().store.get({ - path: extractJsonPath(storePath.config.someValue), + path: extractJsonPath(storePath.inputSpec.someValue), callback: noop, })) satisfies string - await todo().store.get({ + await todo().store.get({ // @ts-expect-error Path is wrong as in it doesn't match above - path: "/config/someV2alue", + path: "/inputSpec/someV2alue", callback: noop, }) - await todo().store.get({ + await todo().store.get({ // @ts-expect-error Path is wrong as in it doesn't exists in wrapper type - path: "/config/someV2alue", + path: "/inputSpec/someV2alue", callback: noop, }) } diff --git a/sdk/lib/trigger/TriggerInput.ts b/sdk/package/lib/trigger/TriggerInput.ts similarity index 52% rename from sdk/lib/trigger/TriggerInput.ts rename to sdk/package/lib/trigger/TriggerInput.ts index 82fe79e07..e15cca9b7 100644 --- a/sdk/lib/trigger/TriggerInput.ts +++ b/sdk/package/lib/trigger/TriggerInput.ts @@ -1,4 +1,4 @@ -import { HealthStatus } from "../types" +import { HealthStatus } from "../../../base/lib/types" export type TriggerInput = { lastResult?: HealthStatus diff --git a/sdk/lib/trigger/changeOnFirstSuccess.ts b/sdk/package/lib/trigger/changeOnFirstSuccess.ts similarity index 100% rename from sdk/lib/trigger/changeOnFirstSuccess.ts rename to sdk/package/lib/trigger/changeOnFirstSuccess.ts diff --git a/sdk/lib/trigger/cooldownTrigger.ts b/sdk/package/lib/trigger/cooldownTrigger.ts similarity index 100% rename from sdk/lib/trigger/cooldownTrigger.ts rename to sdk/package/lib/trigger/cooldownTrigger.ts diff --git a/sdk/lib/trigger/defaultTrigger.ts b/sdk/package/lib/trigger/defaultTrigger.ts similarity index 100% rename from sdk/lib/trigger/defaultTrigger.ts rename to sdk/package/lib/trigger/defaultTrigger.ts diff --git a/sdk/lib/trigger/index.ts b/sdk/package/lib/trigger/index.ts similarity index 83% rename from sdk/lib/trigger/index.ts rename to sdk/package/lib/trigger/index.ts index eb058437f..6da034262 100644 --- a/sdk/lib/trigger/index.ts +++ b/sdk/package/lib/trigger/index.ts @@ -1,4 +1,3 @@ -import { ExecSpawnable } from "../util/SubContainer" import { TriggerInput } from "./TriggerInput" export { changeOnFirstSuccess } from "./changeOnFirstSuccess" export { cooldownTrigger } from "./cooldownTrigger" diff --git a/sdk/lib/trigger/lastStatus.ts b/sdk/package/lib/trigger/lastStatus.ts similarity index 93% rename from sdk/lib/trigger/lastStatus.ts rename to sdk/package/lib/trigger/lastStatus.ts index 90b8c9851..01e737314 100644 --- a/sdk/lib/trigger/lastStatus.ts +++ b/sdk/package/lib/trigger/lastStatus.ts @@ -1,5 +1,5 @@ import { Trigger } from "." -import { HealthStatus } from "../types" +import { HealthStatus } from "../../../base/lib/types" export type LastStatusTriggerParams = { [k in HealthStatus]?: Trigger } & { default: Trigger diff --git a/sdk/lib/trigger/successFailure.ts b/sdk/package/lib/trigger/successFailure.ts similarity index 100% rename from sdk/lib/trigger/successFailure.ts rename to sdk/package/lib/trigger/successFailure.ts diff --git a/sdk/lib/util/GetSslCertificate.ts b/sdk/package/lib/util/GetSslCertificate.ts similarity index 91% rename from sdk/lib/util/GetSslCertificate.ts rename to sdk/package/lib/util/GetSslCertificate.ts index df19607d4..72bf9e22d 100644 --- a/sdk/lib/util/GetSslCertificate.ts +++ b/sdk/package/lib/util/GetSslCertificate.ts @@ -1,5 +1,5 @@ import { T } from ".." -import { Effects } from "../types" +import { Effects } from "../../../base/lib/Effects" export class GetSslCertificate { constructor( @@ -15,7 +15,7 @@ export class GetSslCertificate { return this.effects.getSslCertificate({ hostnames: this.hostnames, algorithm: this.algorithm, - callback: this.effects.restart, + callback: () => this.effects.constRetry(), }) } /** diff --git a/sdk/lib/util/SubContainer.ts b/sdk/package/lib/util/SubContainer.ts similarity index 87% rename from sdk/lib/util/SubContainer.ts rename to sdk/package/lib/util/SubContainer.ts index 0d5982886..7274e22d4 100644 --- a/sdk/lib/util/SubContainer.ts +++ b/sdk/package/lib/util/SubContainer.ts @@ -1,9 +1,9 @@ import * as fs from "fs/promises" -import * as T from "../types" +import * as T from "../../../base/lib/types" import * as cp from "child_process" import { promisify } from "util" import { Buffer } from "node:buffer" -import { once } from "./once" +import { once } from "../../../base/lib/util/once" export const execFile = promisify(cp.execFile) const WORKDIR = (imageId: string) => `/media/startos/images/${imageId}/` const False = () => false @@ -27,7 +27,7 @@ const TIMES_TO_WAIT_FOR_PROC = 100 * case where the subcontainer isn't owned by the process, the subcontainer shouldn't be destroyed. */ export interface ExecSpawnable { - get destroy(): undefined | (() => Promise) + get destroy(): undefined | (() => Promise) exec( command: string[], options?: CommandOptions & ExecOptions, @@ -35,8 +35,8 @@ export interface ExecSpawnable { ): Promise spawn( command: string[], - options?: CommandOptions, - ): Promise + options?: CommandOptions & StdioOptions, + ): Promise } /** * Want to limit what we can do in a container, so we want to launch a container with a specific image and the mounts. @@ -47,7 +47,7 @@ export interface ExecSpawnable { export class SubContainer implements ExecSpawnable { private leader: cp.ChildProcess private leaderExited: boolean = false - private waitProc: () => Promise + private waitProc: () => Promise private constructor( readonly effects: T.Effects, readonly imageId: T.ImageId, @@ -57,7 +57,7 @@ export class SubContainer implements ExecSpawnable { this.leaderExited = false this.leader = cp.spawn("start-cli", ["subcontainer", "launch", rootfs], { killSignal: "SIGKILL", - stdio: "ignore", + stdio: "inherit", }) this.leader.on("exit", () => { this.leaderExited = true @@ -79,17 +79,19 @@ export class SubContainer implements ExecSpawnable { } await wait(1) } - resolve() + resolve(null) }), ) } static async of( effects: T.Effects, image: { id: T.ImageId; sharedRun?: boolean }, + name: string, ) { const { id, sharedRun } = image const [rootfs, guid] = await effects.subcontainer.createFs({ imageId: id as string, + name, }) const shared = ["dev", "sys"] @@ -97,7 +99,8 @@ export class SubContainer implements ExecSpawnable { shared.push("run") } - fs.copyFile("/etc/resolv.conf", `${rootfs}/etc/resolv.conf`) + await fs.mkdir(`${rootfs}/etc`, { recursive: true }) + await fs.copyFile("/etc/resolv.conf", `${rootfs}/etc/resolv.conf`) for (const dirPart of shared) { const from = `/${dirPart}` @@ -114,9 +117,10 @@ export class SubContainer implements ExecSpawnable { effects: T.Effects, image: { id: T.ImageId; sharedRun?: boolean }, mounts: { options: MountOptions; path: string }[], + name: string, fn: (subContainer: SubContainer) => Promise, ): Promise { - const subContainer = await SubContainer.of(effects, image) + const subContainer = await SubContainer.of(effects, image, name) try { for (let mount of mounts) { await subContainer.mount(mount.options, mount.path) @@ -176,12 +180,14 @@ export class SubContainer implements ExecSpawnable { if (this.leaderExited) { return } - return new Promise((resolve, reject) => { + return new Promise((resolve, reject) => { try { + let timeout = setTimeout(() => this.leader.kill("SIGKILL"), 30000) this.leader.on("exit", () => { - resolve() + clearTimeout(timeout) + resolve(null) }) - if (!this.leader.kill("SIGKILL")) { + if (!this.leader.kill("SIGTERM")) { reject(new Error("kill(2) failed")) } } catch (e) { @@ -195,6 +201,7 @@ export class SubContainer implements ExecSpawnable { const guid = this.guid await this.killLeader() await this.effects.subcontainer.destroyFs({ guid }) + return null } } @@ -239,30 +246,24 @@ export class SubContainer implements ExecSpawnable { options || {}, ) if (options?.input) { - await new Promise((resolve, reject) => + await new Promise((resolve, reject) => child.stdin.write(options.input, (e) => { if (e) { reject(e) } else { - resolve() + resolve(null) } }), ) - await new Promise((resolve) => child.stdin.end(resolve)) + await new Promise((resolve) => child.stdin.end(resolve)) } const pid = child.pid - const stdout = { data: "" as string | Buffer } - const stderr = { data: "" as string | Buffer } + const stdout = { data: "" as string } + const stderr = { data: "" as string } const appendData = - (appendTo: { data: string | Buffer }) => - (chunk: string | Buffer | any) => { - if (typeof appendTo.data === "string" && typeof chunk === "string") { - appendTo.data += chunk - } else if (typeof chunk === "string" || chunk instanceof Buffer) { - appendTo.data = Buffer.concat([ - Buffer.from(appendTo.data), - Buffer.from(chunk), - ]) + (appendTo: { data: string }) => (chunk: string | Buffer | any) => { + if (typeof chunk === "string" || chunk instanceof Buffer) { + appendTo.data += chunk.toString() } else { console.error("received unexpected chunk", chunk) } @@ -331,8 +332,8 @@ export class SubContainer implements ExecSpawnable { async spawn( command: string[], - options?: CommandOptions, - ): Promise { + options: CommandOptions & StdioOptions = { stdio: "inherit" }, + ): Promise { await this.waitProc() const imageMeta: any = await fs .readFile(`/media/startos/images/${this.imageId}.json`, { @@ -341,12 +342,12 @@ export class SubContainer implements ExecSpawnable { .catch(() => "{}") .then(JSON.parse) let extra: string[] = [] - if (options?.user) { + if (options.user) { extra.push(`--user=${options.user}`) delete options.user } let workdir = imageMeta.workdir || "/" - if (options?.cwd) { + if (options.cwd) { workdir = options.cwd delete options.cwd } @@ -386,8 +387,8 @@ export class SubContainerHandle implements ExecSpawnable { } spawn( command: string[], - options?: CommandOptions, - ): Promise { + options: CommandOptions & StdioOptions = { stdio: "inherit" }, + ): Promise { return this.subContainer.spawn(command, options) } } @@ -398,6 +399,10 @@ export type CommandOptions = { user?: string } +export type StdioOptions = { + stdio?: cp.IOType +} + export type MountOptions = | MountOptionsVolume | MountOptionsAssets diff --git a/sdk/package/lib/util/fileHelper.ts b/sdk/package/lib/util/fileHelper.ts new file mode 100644 index 000000000..80e5b3564 --- /dev/null +++ b/sdk/package/lib/util/fileHelper.ts @@ -0,0 +1,246 @@ +import * as matches from "ts-matches" +import * as YAML from "yaml" +import * as TOML from "@iarna/toml" +import merge from "lodash.merge" +import * as T from "../../../base/lib/types" +import * as fs from "node:fs/promises" +import { asError } from "../../../base/lib/util" + +const previousPath = /(.+?)\/([^/]*)$/ + +const exists = (path: string) => + fs.access(path).then( + () => true, + () => false, + ) + +async function onCreated(path: string) { + if (path === "/") return + if (!path.startsWith("/")) path = `${process.cwd()}/${path}` + if (await exists(path)) { + return + } + const split = path.split("/") + const filename = split.pop() + const parent = split.join("/") + await onCreated(parent) + const ctrl = new AbortController() + const watch = fs.watch(parent, { persistent: false, signal: ctrl.signal }) + if ( + await fs.access(path).then( + () => true, + () => false, + ) + ) { + ctrl.abort("finished") + return + } + for await (let event of watch) { + if (event.filename === filename) { + ctrl.abort("finished") + return + } + } +} + +/** + * @description Use this class to read/write an underlying configuration file belonging to the upstream service. + * + * Using the static functions, choose between officially supported file formats (json, yaml, toml), or a custom format (raw). + * @example + * Below are a few examples + * + * ``` + * import { matches, FileHelper } from '@start9labs/start-sdk' + * const { arrayOf, boolean, literal, literals, object, oneOf, natural, string } = matches + * + * export const jsonFile = FileHelper.json('./inputSpec.json', object({ + * passwords: arrayOf(string) + * type: oneOf(literals('private', 'public')) + * })) + * + * export const tomlFile = FileHelper.toml('./inputSpec.toml', object({ + * url: literal('https://start9.com') + * public: boolean + * })) + * + * export const yamlFile = FileHelper.yaml('./inputSpec.yml', object({ + * name: string + * age: natural + * })) + * + * export const bitcoinConfFile = FileHelper.raw( + * './service.conf', + * (obj: CustomType) => customConvertObjToFormattedString(obj), + * (str) => customParseStringToTypedObj(str), + * ) + * ``` + */ +export class FileHelper { + protected constructor( + readonly path: string, + readonly writeData: (dataIn: A) => string, + readonly readData: (stringValue: string) => unknown, + readonly validate: (value: unknown) => A, + ) {} + + /** + * Accepts structured data and overwrites the existing file on disk. + */ + private async writeFile(data: A): Promise { + const parent = previousPath.exec(this.path) + if (parent) { + await fs.mkdir(parent[1], { recursive: true }) + } + + await fs.writeFile(this.path, this.writeData(data)) + + return null + } + + private async readFile(): Promise { + if (!(await exists(this.path))) { + return null + } + return this.readData( + await fs.readFile(this.path).then((data) => data.toString("utf-8")), + ) + } + + /** + * Reads the file from disk and converts it to structured data. + */ + private async readOnce(): Promise { + const data = await this.readFile() + if (!data) return null + return this.validate(data) + } + + private async readConst(effects: T.Effects): Promise { + const watch = this.readWatch() + const res = await watch.next() + watch.next().then(effects.constRetry) + return res.value + } + + private async *readWatch() { + let res + while (true) { + if (await exists(this.path)) { + const ctrl = new AbortController() + const watch = fs.watch(this.path, { + persistent: false, + signal: ctrl.signal, + }) + res = await this.readOnce() + const listen = Promise.resolve() + .then(async () => { + for await (const _ of watch) { + ctrl.abort("finished") + return null + } + }) + .catch((e) => console.error(asError(e))) + yield res + await listen + } else { + yield null + await onCreated(this.path).catch((e) => console.error(asError(e))) + } + } + return null + } + + get read() { + return { + once: () => this.readOnce(), + const: (effects: T.Effects) => this.readConst(effects), + watch: () => this.readWatch(), + } + } + + /** + * Accepts full structured data and performs a merge with the existing file on disk if it exists. + */ + async write(data: A) { + const fileData = (await this.readFile()) || {} + const mergeData = merge({}, fileData, data) + return await this.writeFile(this.validate(mergeData)) + } + + /** + * Accepts partial structured data and performs a merge with the existing file on disk. + */ + async merge(data: T.DeepPartial) { + const fileData = + (await this.readFile()) || + (() => { + throw new Error(`${this.path}: does not exist`) + })() + const mergeData = merge({}, fileData, data) + return await this.writeFile(this.validate(mergeData)) + } + + /** + * We wanted to be able to have a fileHelper, and just modify the path later in time. + * Like one behaviour of another dependency or something similar. + */ + withPath(path: string) { + return new FileHelper(path, this.writeData, this.readData, this.validate) + } + + /** + * Create a File Helper for an arbitrary file type. + * + * Provide custom functions for translating data to/from the file format. + */ + static raw( + path: string, + toFile: (dataIn: A) => string, + fromFile: (rawData: string) => unknown, + validate: (data: unknown) => A, + ) { + return new FileHelper(path, toFile, fromFile, validate) + } + /** + * Create a File Helper for a .json file. + */ + static json(path: string, shape: matches.Validator) { + return new FileHelper( + path, + (inData) => JSON.stringify(inData, null, 2), + (inString) => JSON.parse(inString), + (data) => shape.unsafeCast(data), + ) + } + /** + * Create a File Helper for a .toml file + */ + static toml>( + path: string, + shape: matches.Validator, + ) { + return new FileHelper( + path, + (inData) => TOML.stringify(inData as any), + (inString) => TOML.parse(inString), + (data) => shape.unsafeCast(data), + ) + } + /** + * Create a File Helper for a .yaml file + */ + static yaml>( + path: string, + shape: matches.Validator, + ) { + return new FileHelper( + path, + (inData) => YAML.stringify(inData, null, 2), + (inString) => YAML.parse(inString), + (data) => shape.unsafeCast(data), + ) + } +} + +export default FileHelper diff --git a/sdk/package/lib/util/index.ts b/sdk/package/lib/util/index.ts new file mode 100644 index 000000000..66c73503e --- /dev/null +++ b/sdk/package/lib/util/index.ts @@ -0,0 +1,4 @@ +export * from "../../../base/lib/util" +export { GetSslCertificate } from "./GetSslCertificate" + +export { hostnameInfoToAddress } from "../../../base/lib/util/Hostname" diff --git a/sdk/lib/version/VersionGraph.ts b/sdk/package/lib/version/VersionGraph.ts similarity index 94% rename from sdk/lib/version/VersionGraph.ts rename to sdk/package/lib/version/VersionGraph.ts index 1b6b49bb9..91c7a0cc0 100644 --- a/sdk/lib/version/VersionGraph.ts +++ b/sdk/package/lib/version/VersionGraph.ts @@ -1,8 +1,6 @@ -import { ExtendedVersion, VersionRange } from "../exver" - -import * as T from "../types" -import { Graph, Vertex } from "../util/graph" -import { once } from "../util/once" +import { ExtendedVersion, VersionRange } from "../../../base/lib/exver" +import * as T from "../../../base/lib/types" +import { Graph, Vertex, once } from "../util" import { IMPOSSIBLE, VersionInfo } from "./VersionInfo" export class VersionGraph { @@ -110,6 +108,11 @@ export class VersionGraph { currentVersion = once(() => ExtendedVersion.parse(this.current.options.version), ) + /** + * Each exported `VersionInfo.of()` should be imported and provided as an argument to this function. + * + * ** The current version must be the FIRST argument. ** + */ static of< CurrentVersion extends string, OtherVersions extends Array>, diff --git a/sdk/lib/version/VersionInfo.ts b/sdk/package/lib/version/VersionInfo.ts similarity index 68% rename from sdk/lib/version/VersionInfo.ts rename to sdk/package/lib/version/VersionInfo.ts index beea16019..952ae5352 100644 --- a/sdk/lib/version/VersionInfo.ts +++ b/sdk/package/lib/version/VersionInfo.ts @@ -1,29 +1,27 @@ -import { ValidateExVer } from "../exver" -import * as T from "../types" +import { ValidateExVer } from "../../../base/lib/exver" +import * as T from "../../../base/lib/types" export const IMPOSSIBLE = Symbol("IMPOSSIBLE") export type VersionOptions = { - /** The version being described */ + /** The exver-compliant version number */ version: Version & ValidateExVer /** The release notes for this version */ releaseNotes: string /** Data migrations for this version */ migrations: { /** - * A migration from the previous version - * Leave blank to indicate no migration is necessary - * Set to `IMPOSSIBLE` to indicate migrating from the previous version is not possible + * A migration from the previous version. Leave empty to indicate no migration is necessary. + * Set to `IMPOSSIBLE` to indicate migrating from the previous version is not possible. */ up?: ((opts: { effects: T.Effects }) => Promise) | typeof IMPOSSIBLE /** - * A migration to the previous version - * Leave blank to indicate no migration is necessary - * Set to `IMPOSSIBLE` to indicate downgrades are prohibited + * A migration to the previous version. Leave blank to indicate no migration is necessary. + * Set to `IMPOSSIBLE` to indicate downgrades are prohibited */ down?: ((opts: { effects: T.Effects }) => Promise) | typeof IMPOSSIBLE /** - * Additional migrations, such as fast-forward migrations, or migrations from other flavors + * Additional migrations, such as fast-forward migrations, or migrations from other flavors. */ other?: Record Promise> } @@ -34,6 +32,13 @@ export class VersionInfo { private constructor( readonly options: VersionOptions & { satisfies: string[] }, ) {} + /** + * @description Use this function to define a new version of the service. By convention, each version should receive its own file. + * @property {string} version + * @property {string} releaseNotes + * @property {object} migrations + * @returns A VersionInfo class instance that is exported, then imported into versions/index.ts. + */ static of(options: VersionOptions) { return new VersionInfo({ ...options, satisfies: [] }) } diff --git a/sdk/lib/version/index.ts b/sdk/package/lib/version/index.ts similarity index 100% rename from sdk/lib/version/index.ts rename to sdk/package/lib/version/index.ts diff --git a/sdk/package/package-lock.json b/sdk/package/package-lock.json new file mode 100644 index 000000000..1f5715258 --- /dev/null +++ b/sdk/package/package-lock.json @@ -0,0 +1,4714 @@ +{ + "name": "@start9labs/start-sdk", + "version": "0.3.6-alpha.21", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@start9labs/start-sdk", + "version": "0.3.6-alpha.21", + "license": "MIT", + "dependencies": { + "@iarna/toml": "^2.2.5", + "@noble/curves": "^1.4.0", + "@noble/hashes": "^1.4.0", + "isomorphic-fetch": "^3.0.0", + "lodash.merge": "^4.6.2", + "mime-types": "^2.1.35", + "ts-matches": "^6.1.0", + "yaml": "^2.2.2" + }, + "devDependencies": { + "@types/jest": "^29.4.0", + "@types/lodash.merge": "^4.6.2", + "jest": "^29.4.3", + "peggy": "^3.0.2", + "prettier": "^3.2.5", + "ts-jest": "^29.0.5", + "ts-node": "^10.9.1", + "ts-pegjs": "^4.2.1", + "tsx": "^4.7.1", + "typescript": "^5.0.4" + } + }, + "../base": { + "name": "@start9labs/start-sdk-base", + "extraneous": true, + "license": "MIT", + "dependencies": { + "@iarna/toml": "^2.2.5", + "@noble/curves": "^1.4.0", + "@noble/hashes": "^1.4.0", + "isomorphic-fetch": "^3.0.0", + "lodash.merge": "^4.6.2", + "mime": "^4.0.3", + "ts-matches": "^5.5.1", + "yaml": "^2.2.2" + }, + "devDependencies": { + "@types/jest": "^29.4.0", + "@types/lodash.merge": "^4.6.2", + "jest": "^29.4.3", + "peggy": "^3.0.2", + "prettier": "^3.2.5", + "ts-jest": "^29.0.5", + "ts-node": "^10.9.1", + "ts-pegjs": "^4.2.1", + "tsx": "^4.7.1", + "typescript": "^5.0.4" + } + }, + "../base/dist": { + "extraneous": true + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.0.tgz", + "integrity": "sha512-gMuZsmsgxk/ENC3O/fRw5QY8A9/uxQbbCEypnLIiYYc/qVJtEV7ouxC3EllIIwNzMqAQee5tanFabWsUOutS7g==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.21.3", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.3.tgz", + "integrity": "sha512-qIJONzoa/qiHghnm0l1n4i/6IIziDpzqc36FBs4pzMhDUraHqponwJLiAKm1hGLP3OSB/TVNz6rMwVGpwxxySw==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.21.3", + "@babel/helper-compilation-targets": "^7.20.7", + "@babel/helper-module-transforms": "^7.21.2", + "@babel/helpers": "^7.21.0", + "@babel/parser": "^7.21.3", + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.21.3", + "@babel/types": "^7.21.3", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.2", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/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 + }, + "node_modules/@babel/generator": { + "version": "7.21.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.3.tgz", + "integrity": "sha512-QS3iR1GYC/YGUnW7IdggFeN5c1poPUurnGttOV/bZgPGV+izC/D8HnD6DLwod0fsatNyVn1G3EVWMYIF0nHbeA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.21.3", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz", + "integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.20.5", + "@babel/helper-validator-option": "^7.18.6", + "browserslist": "^4.21.3", + "lru-cache": "^5.1.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", + "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz", + "integrity": "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==", + "dev": true, + "dependencies": { + "@babel/template": "^7.20.7", + "@babel/types": "^7.21.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", + "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", + "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.21.2", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz", + "integrity": "sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-simple-access": "^7.20.2", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/helper-validator-identifier": "^7.19.1", + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.21.2", + "@babel/types": "^7.21.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", + "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz", + "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", + "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", + "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz", + "integrity": "sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.21.0.tgz", + "integrity": "sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA==", + "dev": true, + "dependencies": { + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.21.0", + "@babel/types": "^7.21.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/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, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/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, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/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, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/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 + }, + "node_modules/@babel/highlight/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, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/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, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/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, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.21.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.3.tgz", + "integrity": "sha512-lobG0d7aOfQRXh8AyklEAgZGvA4FShxo6xQbUrrT/cNBPUdIDojlokwJsQyCC/eKia7ifqM0yP+2DRZ4WKw2RQ==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz", + "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.20.0.tgz", + "integrity": "sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", + "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.21.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.3.tgz", + "integrity": "sha512-XLyopNeaTancVitYZe2MlUEvgKb6YVVPXzofHgqHijCImG33b/uTurMS488ht/Hbsb2XK3U2BnSTxKVNGV3nGQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.21.3", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.21.0", + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/parser": "^7.21.3", + "@babel/types": "^7.21.3", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.21.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.3.tgz", + "integrity": "sha512-sBGdETxC+/M4o/zKC0sl6sjWv62WFR/uzxrJ6uYyMLZOUlPnwzw0tKgVHOXxaAd5l2g8pEDM5RZ495GPQI77kg==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, + "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, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "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, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz", + "integrity": "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@iarna/toml": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.5.tgz", + "integrity": "sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==" + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "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" + } + }, + "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, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.5.0.tgz", + "integrity": "sha512-NEpkObxPwyw/XxZVLPmAGKE89IQRp4puc6IQRPru6JKd1M3fW9v1xM1AnzIJE65hbCkzQAdnL8P47e9hzhiYLQ==", + "dev": true, + "dependencies": { + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.5.0.tgz", + "integrity": "sha512-28UzQc7ulUrOQw1IsN/kv1QES3q2kkbl/wGslyhAclqZ/8cMdB5M68BffkIdSJgKBUt50d3hbwJ92XESlE7LiQ==", + "dev": true, + "dependencies": { + "@jest/console": "^29.5.0", + "@jest/reporters": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", + "@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.5.0", + "jest-config": "^29.5.0", + "jest-haste-map": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-regex-util": "^29.4.3", + "jest-resolve": "^29.5.0", + "jest-resolve-dependencies": "^29.5.0", + "jest-runner": "^29.5.0", + "jest-runtime": "^29.5.0", + "jest-snapshot": "^29.5.0", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", + "jest-watcher": "^29.5.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.5.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 + } + } + }, + "node_modules/@jest/environment": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.5.0.tgz", + "integrity": "sha512-5FXw2+wD29YU1d4I2htpRX7jYnAyTRjP2CsXQdo9SAM8g3ifxWPSV0HnClSn71xwctr0U3oZIIH+dtbfmnbXVQ==", + "dev": true, + "dependencies": { + "@jest/fake-timers": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/node": "*", + "jest-mock": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.5.0.tgz", + "integrity": "sha512-PueDR2HGihN3ciUNGr4uelropW7rqUfTiOn+8u0leg/42UhblPxHkfoh0Ruu3I9Y1962P3u2DY4+h7GVTSVU6g==", + "dev": true, + "dependencies": { + "expect": "^29.5.0", + "jest-snapshot": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.5.0.tgz", + "integrity": "sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg==", + "dev": true, + "dependencies": { + "jest-get-type": "^29.4.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.5.0.tgz", + "integrity": "sha512-9ARvuAAQcBwDAqOnglWq2zwNIRUDtk/SCkp/ToGEhFv5r86K21l+VEs0qNTaXtyiY0lEePl3kylijSYJQqdbDg==", + "dev": true, + "dependencies": { + "@jest/types": "^29.5.0", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.5.0", + "jest-mock": "^29.5.0", + "jest-util": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.5.0.tgz", + "integrity": "sha512-S02y0qMWGihdzNbUiqSAiKSpSozSuHX5UYc7QbnHP+D9Lyw8DgGGCinrN9uSuHPeKgSSzvPom2q1nAtBvUsvPQ==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.5.0", + "@jest/expect": "^29.5.0", + "@jest/types": "^29.5.0", + "jest-mock": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.5.0.tgz", + "integrity": "sha512-D05STXqj/M8bP9hQNSICtPqz97u7ffGzZu+9XLucXhkOFBqKcXe04JLZOgIekOxdb73MAoBUFnqvf7MCpKk5OA==", + "dev": true, + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", + "@jridgewell/trace-mapping": "^0.3.15", + "@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": "^5.1.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0", + "jest-worker": "^29.5.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 + } + } + }, + "node_modules/@jest/schemas": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.3.tgz", + "integrity": "sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.25.16" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.4.3.tgz", + "integrity": "sha512-qyt/mb6rLyd9j1jUts4EQncvS6Yy3PM9HghnNv86QBlV+zdL2inCdK1tuVlL+J+lpiw2BI67qXOrX3UurBqQ1w==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.15", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.5.0.tgz", + "integrity": "sha512-fGl4rfitnbfLsrfx1uUpDEESS7zM8JdgZgOCQuxQvL1Sn/I6ijeAVQWGfXI9zb1i9Mzo495cIpVZhA0yr60PkQ==", + "dev": true, + "dependencies": { + "@jest/console": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.5.0.tgz", + "integrity": "sha512-yPafQEcKjkSfDXyvtgiV4pevSeyuA6MQr6ZIdVkWJly9vkqjnFfcfhRQqpD5whjoU8EORki752xQmjaqoFjzMQ==", + "dev": true, + "dependencies": { + "@jest/test-result": "^29.5.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.5.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.5.0.tgz", + "integrity": "sha512-8vbeZWqLJOvHaDfeMuoHITGKSz5qWc9u04lnWrQE3VyuSw604PzQM824ZeX9XSjUCeDiE3GuxZe5UKa8J61NQw==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.5.0", + "@jridgewell/trace-mapping": "^0.3.15", + "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.5.0", + "jest-regex-util": "^29.4.3", + "jest-util": "^29.5.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" + } + }, + "node_modules/@jest/types": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", + "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.4.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" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "node_modules/@noble/curves": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.0.tgz", + "integrity": "sha512-p+4cb332SFCrReJkCYe8Xzm0OWi4Jji5jVdIZRL/PmacmDkFNw6MrrV+gGpiPxLHbV+zKFRywUWbaseT+tZRXg==", + "dependencies": { + "@noble/hashes": "1.4.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/hashes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "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==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 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==", + "dev": true, + "engines": { + "node": ">= 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==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.25.24", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz", + "integrity": "sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==", + "dev": true + }, + "node_modules/@sinonjs/commons": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.0.2.tgz", + "integrity": "sha512-SwUDyjWnah1AaNl7kxsa7cfLhlTYoiyhDAIgyh+El30YvXs/o7OLXpYH88Zdhyx9JExKrmHDJ+10bwIcY80Jmw==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^2.0.0" + } + }, + "node_modules/@ts-morph/common": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.19.0.tgz", + "integrity": "sha512-Unz/WHmd4pGax91rdIKWi51wnVUW11QttMEPpBiBgIewnc9UQIX7UDLxr5vRlqeByXCwhkF6VabSsI0raWcyAQ==", + "dev": true, + "dependencies": { + "fast-glob": "^3.2.12", + "minimatch": "^7.4.3", + "mkdirp": "^2.1.6", + "path-browserify": "^1.0.1" + } + }, + "node_modules/@ts-morph/common/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@ts-morph/common/node_modules/minimatch": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.6.tgz", + "integrity": "sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "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 + }, + "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 + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", + "dev": true + }, + "node_modules/@types/babel__core": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.0.tgz", + "integrity": "sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", + "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.3.tgz", + "integrity": "sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.3.0" + } + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", + "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "dev": true + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.0.tgz", + "integrity": "sha512-3Emr5VOl/aoBwnWcH/EFQvlSAmjV+XtV9GGu5mwdYew5vhQh0IUZx/60x0TzHDu09Bi7HMx10t/namdJw5QIcg==", + "dev": true, + "dependencies": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + } + }, + "node_modules/@types/lodash": { + "version": "4.17.5", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.5.tgz", + "integrity": "sha512-MBIOHVZqVqgfro1euRDWX7OO0fBVUUMrN6Pwm8LQsz8cWhEpihlvR70ENj3f40j58TNxZaWv2ndSkInykNBBJw==", + "dev": true + }, + "node_modules/@types/lodash.merge": { + "version": "4.6.9", + "resolved": "https://registry.npmjs.org/@types/lodash.merge/-/lodash.merge-4.6.9.tgz", + "integrity": "sha512-23sHDPmzd59kUgWyKGiOMO2Qb9YtqRO/x4IhkgNUiPQ1+5MUVqi6bCZeq9nBJ17msjIMbEIO5u+XW4Kz6aGUhQ==", + "dev": true, + "dependencies": { + "@types/lodash": "*" + } + }, + "node_modules/@types/node": { + "version": "18.15.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.10.tgz", + "integrity": "sha512-9avDaQJczATcXgfmMAW3MIWArOO7A+m90vuCFLr8AotWf8igO/mRoYukrk2cqZVtv38tHs33retzHEilM7FpeQ==", + "dev": true + }, + "node_modules/@types/prettier": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.2.tgz", + "integrity": "sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==", + "dev": true + }, + "node_modules/@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "dev": true + }, + "node_modules/@types/yargs": { + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", + "dev": true + }, + "node_modules/acorn": { + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "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, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "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, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/babel-jest": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.5.0.tgz", + "integrity": "sha512-mA4eCDh5mSo2EcA9xQjVTpmbbNk32Zb3Q3QFQsNhaK56Q+yoXowzFodLux30HRgyOho5rsQ6B0P9QpMkvvnJ0Q==", + "dev": true, + "dependencies": { + "@jest/transform": "^29.5.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.5.0", + "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" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "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" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.5.0.tgz", + "integrity": "sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w==", + "dev": true, + "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" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@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-top-level-await": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-preset-jest": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.5.0.tgz", + "integrity": "sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg==", + "dev": true, + "dependencies": { + "babel-plugin-jest-hoist": "^29.5.0", + "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" + } + }, + "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==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.21.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", + "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001449", + "electron-to-chromium": "^1.4.284", + "node-releases": "^2.0.8", + "update-browserslist-db": "^1.0.10" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "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 + }, + "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, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001470", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001470.tgz", + "integrity": "sha512-065uNwY6QtHCBOExzbV6m236DDhYCCtPmQUCoQtwkVqzud8v5QPidoMr6CoMkC2nfp6nksjttqWQRRh75LqUmA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + } + ] + }, + "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, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ci-info": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", + "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", + "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", + "dev": true + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/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==", + "dev": true + }, + "node_modules/cliui/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==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/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==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/code-block-writer": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-12.0.0.tgz", + "integrity": "sha512-q4dMFMlXtKR3XNBHyMHt/3pwYNA69EDk00lloMOaaUMKPUXBw6lpXtbu3MMVG6/uOihGnRDOlkyqsONEUj60+w==", + "dev": true + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", + "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", + "dev": 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==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "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==", + "dev": true + }, + "node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "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 + }, + "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 + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "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, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", + "dev": true + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "engines": { + "node": ">=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, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/diff-sequences": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz", + "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.341", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.341.tgz", + "integrity": "sha512-R4A8VfUBQY9WmAhuqY5tjHRf5fH2AAf6vqitBOE0y6u2PgHgqHSrhZmu78dIX3fVZtjqlwJNX1i2zwC3VpHtQQ==", + "dev": true + }, + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "engines": { + "node": ">=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, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "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" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.5.0.tgz", + "integrity": "sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg==", + "dev": true, + "dependencies": { + "@jest/expect-utils": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-matcher-utils": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "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" + } + }, + "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==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "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==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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 + }, + "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, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "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, + "engines": { + "node": ">=6.9.0" + } + }, + "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==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, + "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, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-tsconfig": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.2.tgz", + "integrity": "sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A==", + "dev": true, + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "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" + } + }, + "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==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "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==", + "dev": true + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "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, + "engines": { + "node": ">=8" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "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" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "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==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "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 + }, + "node_modules/is-core-module": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "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==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/isomorphic-fetch": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-3.0.0.tgz", + "integrity": "sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA==", + "dependencies": { + "node-fetch": "^2.6.1", + "whatwg-fetch": "^3.4.1" + } + }, + "node_modules/isomorphic-fetch/node_modules/node-fetch": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz", + "integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "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" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", + "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.5.0.tgz", + "integrity": "sha512-juMg3he2uru1QoXX078zTa7pO85QyB9xajZc6bU+d9yEGwrKX6+vGmJQ3UdVZsvTEUARIdObzH68QItim6OSSQ==", + "dev": true, + "dependencies": { + "@jest/core": "^29.5.0", + "@jest/types": "^29.5.0", + "import-local": "^3.0.2", + "jest-cli": "^29.5.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 + } + } + }, + "node_modules/jest-changed-files": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.5.0.tgz", + "integrity": "sha512-IFG34IUMUaNBIxjQXF/iu7g6EcdMrGRRxaUSw92I/2g2YC6vCdTltl4nHvt7Ci5nSJwXIkCu8Ka1DKF+X7Z1Ag==", + "dev": true, + "dependencies": { + "execa": "^5.0.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.5.0.tgz", + "integrity": "sha512-gq/ongqeQKAplVxqJmbeUOJJKkW3dDNPY8PjhJ5G0lBRvu0e3EWGxGy5cI4LAGA7gV2UHCtWBI4EMXK8c9nQKA==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.5.0", + "@jest/expect": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.5.0", + "jest-matcher-utils": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-runtime": "^29.5.0", + "jest-snapshot": "^29.5.0", + "jest-util": "^29.5.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.5.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" + } + }, + "node_modules/jest-cli": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.5.0.tgz", + "integrity": "sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw==", + "dev": true, + "dependencies": { + "@jest/core": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/types": "^29.5.0", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "import-local": "^3.0.2", + "jest-config": "^29.5.0", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", + "prompts": "^2.0.1", + "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 + } + } + }, + "node_modules/jest-config": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.5.0.tgz", + "integrity": "sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.5.0", + "@jest/types": "^29.5.0", + "babel-jest": "^29.5.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.5.0", + "jest-environment-node": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-regex-util": "^29.4.3", + "jest-resolve": "^29.5.0", + "jest-runner": "^29.5.0", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.5.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 + } + } + }, + "node_modules/jest-diff": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.5.0.tgz", + "integrity": "sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.4.3", + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-docblock": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.4.3.tgz", + "integrity": "sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg==", + "dev": true, + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.5.0.tgz", + "integrity": "sha512-HM5kIJ1BTnVt+DQZ2ALp3rzXEl+g726csObrW/jpEGl+CDSSQpOJJX2KE/vEg8cxcMXdyEPu6U4QX5eruQv5hA==", + "dev": true, + "dependencies": { + "@jest/types": "^29.5.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.4.3", + "jest-util": "^29.5.0", + "pretty-format": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.5.0.tgz", + "integrity": "sha512-ExxuIK/+yQ+6PRGaHkKewYtg6hto2uGCgvKdb2nfJfKXgZ17DfXjvbZ+jA1Qt9A8EQSfPnt5FKIfnOO3u1h9qw==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.5.0", + "@jest/fake-timers": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/node": "*", + "jest-mock": "^29.5.0", + "jest-util": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz", + "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.5.0.tgz", + "integrity": "sha512-IspOPnnBro8YfVYSw6yDRKh/TiCdRngjxeacCps1cQ9cgVN6+10JUcuJ1EabrgYLOATsIAigxA0rLR9x/YlrSA==", + "dev": true, + "dependencies": { + "@jest/types": "^29.5.0", + "@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.4.3", + "jest-util": "^29.5.0", + "jest-worker": "^29.5.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" + } + }, + "node_modules/jest-leak-detector": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.5.0.tgz", + "integrity": "sha512-u9YdeeVnghBUtpN5mVxjID7KbkKE1QU4f6uUwuxiY0vYRi9BUCLKlPEZfDGR67ofdFmDz9oPAy2G92Ujrntmow==", + "dev": true, + "dependencies": { + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.5.0.tgz", + "integrity": "sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.5.0", + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.5.0.tgz", + "integrity": "sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.5.0", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.5.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-mock": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.5.0.tgz", + "integrity": "sha512-GqOzvdWDE4fAV2bWQLQCkujxYWL7RxjCnj71b5VhDAGOevB3qj3Ovg26A5NI84ZpODxyzaozXLOh2NCgkbvyaw==", + "dev": true, + "dependencies": { + "@jest/types": "^29.5.0", + "@types/node": "*", + "jest-util": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.4.3.tgz", + "integrity": "sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.5.0.tgz", + "integrity": "sha512-1TzxJ37FQq7J10jPtQjcc+MkCkE3GBpBecsSUWJ0qZNJpmg6m0D9/7II03yJulm3H/fvVjgqLh/k2eYg+ui52w==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.5.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.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" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.5.0.tgz", + "integrity": "sha512-sjV3GFr0hDJMBpYeUuGduP+YeCRbd7S/ck6IvL3kQ9cpySYKqcqhdLLC2rFwrcL7tz5vYibomBrsFYWkIGGjOg==", + "dev": true, + "dependencies": { + "jest-regex-util": "^29.4.3", + "jest-snapshot": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.5.0.tgz", + "integrity": "sha512-m7b6ypERhFghJsslMLhydaXBiLf7+jXy8FwGRHO3BGV1mcQpPbwiqiKUR2zU2NJuNeMenJmlFZCsIqzJCTeGLQ==", + "dev": true, + "dependencies": { + "@jest/console": "^29.5.0", + "@jest/environment": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.4.3", + "jest-environment-node": "^29.5.0", + "jest-haste-map": "^29.5.0", + "jest-leak-detector": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-resolve": "^29.5.0", + "jest-runtime": "^29.5.0", + "jest-util": "^29.5.0", + "jest-watcher": "^29.5.0", + "jest-worker": "^29.5.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.5.0.tgz", + "integrity": "sha512-1Hr6Hh7bAgXQP+pln3homOiEZtCDZFqwmle7Ew2j8OlbkIu6uE3Y/etJQG8MLQs3Zy90xrp2C0BRrtPHG4zryw==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.5.0", + "@jest/fake-timers": "^29.5.0", + "@jest/globals": "^29.5.0", + "@jest/source-map": "^29.4.3", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", + "@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.5.0", + "jest-message-util": "^29.5.0", + "jest-mock": "^29.5.0", + "jest-regex-util": "^29.4.3", + "jest-resolve": "^29.5.0", + "jest-snapshot": "^29.5.0", + "jest-util": "^29.5.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.5.0.tgz", + "integrity": "sha512-x7Wolra5V0tt3wRs3/ts3S6ciSQVypgGQlJpz2rsdQYoUKxMxPNaoHMGJN6qAuPJqS+2iQ1ZUn5kl7HCyls84g==", + "dev": true, + "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/traverse": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/babel__traverse": "^7.0.6", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.5.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-matcher-utils": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.5.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-snapshot/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/jest-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", + "dev": true, + "dependencies": { + "@jest/types": "^29.5.0", + "@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" + } + }, + "node_modules/jest-validate": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.5.0.tgz", + "integrity": "sha512-pC26etNIi+y3HV8A+tUGr/lph9B18GnzSRAkPaaZJIE1eFdiYm6/CewuiJQ8/RlfHd1u/8Ioi8/sJ+CmbA+zAQ==", + "dev": true, + "dependencies": { + "@jest/types": "^29.5.0", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.4.3", + "leven": "^3.1.0", + "pretty-format": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watcher": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.5.0.tgz", + "integrity": "sha512-KmTojKcapuqYrKDpRwfqcQ3zjMlwu27SYext9pt4GlF5FUgB+7XE1mcCnSm6a4uUpFyQIkb6ZhzZvHl+jiBCiA==", + "dev": true, + "dependencies": { + "@jest/test-result": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.5.0", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.5.0.tgz", + "integrity": "sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA==", + "dev": true, + "dependencies": { + "@types/node": "*", + "jest-util": "^29.5.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "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 + }, + "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, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "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 + }, + "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, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "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 + }, + "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==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" + }, + "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, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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 + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "dependencies": { + "tmpl": "1.0.5" + } + }, + "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 + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 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, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "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, + "engines": { + "node": ">=6" + } + }, + "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, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mkdirp": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-2.1.6.tgz", + "integrity": "sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A==", + "dev": true, + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "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 + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true + }, + "node_modules/node-releases": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", + "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==", + "dev": true + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=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==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "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, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-locate/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==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "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, + "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" + } + }, + "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==", + "dev": 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==", + "dev": true, + "engines": { + "node": ">=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, + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "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==", + "dev": true + }, + "node_modules/peggy": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/peggy/-/peggy-3.0.2.tgz", + "integrity": "sha512-n7chtCbEoGYRwZZ0i/O3t1cPr6o+d9Xx4Zwy2LYfzv0vjchMBU0tO+qYYyvZloBPcgRgzYvALzGWHe609JjEpg==", + "dev": true, + "dependencies": { + "commander": "^10.0.0", + "source-map-generator": "0.8.0" + }, + "bin": { + "peggy": "bin/peggy.js" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pirates": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/prettier": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", + "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/pretty-format": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.4.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pure-rand": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.1.tgz", + "integrity": "sha512-t+x1zEHDjBwkDGY5v5ApnZ/utcd4XYDiJsaQQoptTXgUXX95sDg1elCdJghzicm7n2mbCBJ3uYWr6M22SO19rg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ] + }, + "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==", + "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" + } + ] + }, + "node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, + "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==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/resolve.exports": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", + "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "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==", + "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" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "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==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=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==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "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 + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "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, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-generator": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/source-map-generator/-/source-map-generator-0.8.0.tgz", + "integrity": "sha512-psgxdGMwl5MZM9S3FWee4EgsEaIjahYV5AzGnwUvPhWeITz/j6rKpysQHlQ4USdxvINlb8lKfWGIXwfkrgtqkA==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.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 + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "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==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=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==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "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==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/ts-jest": { + "version": "29.0.5", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.5.tgz", + "integrity": "sha512-PL3UciSgIpQ7f6XjVOmbi96vmDHUqAyqDr8YxzopDqX3kfgYtX1cuNeBjP+L9sFXi6nzsGGA6R3fP3DDDJyrxA==", + "dev": true, + "dependencies": { + "bs-logger": "0.x", + "fast-json-stable-stringify": "2.x", + "jest-util": "^29.0.0", + "json5": "^2.2.3", + "lodash.memoize": "4.x", + "make-error": "1.x", + "semver": "7.x", + "yargs-parser": "^21.0.1" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@jest/types": "^29.0.0", + "babel-jest": "^29.0.0", + "jest": "^29.0.0", + "typescript": ">=4.3" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@jest/types": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + } + } + }, + "node_modules/ts-jest/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ts-jest/node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ts-jest/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/ts-matches": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ts-matches/-/ts-matches-6.1.0.tgz", + "integrity": "sha512-01qvbIpOiKdbzzXDH84JeHunvCwBGFdZw94jS6kOGLSN5ms+1nBZtfe8WSuYMIPb1xPA+qyAiVgznFi2VCQ6UQ==", + "license": "MIT" + }, + "node_modules/ts-morph": { + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-18.0.0.tgz", + "integrity": "sha512-Kg5u0mk19PIIe4islUI/HWRvm9bC1lHejK4S0oh1zaZ77TMZAEmQC0sHQYiu2RgCQFZKXz1fMVi/7nOOeirznA==", + "dev": true, + "dependencies": { + "@ts-morph/common": "~0.19.0", + "code-block-writer": "^12.0.0" + } + }, + "node_modules/ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "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 + } + } + }, + "node_modules/ts-pegjs": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ts-pegjs/-/ts-pegjs-4.2.1.tgz", + "integrity": "sha512-mK/O2pu6lzWUeKpEMA/wsa0GdYblfjJI1y0s0GqH6xCTvugQDOWPJbm5rY6AHivpZICuXIriCb+a7Cflbdtc2w==", + "dev": true, + "dependencies": { + "prettier": "^2.8.8", + "ts-morph": "^18.0.0" + }, + "bin": { + "tspegjs": "dist/cli.mjs" + }, + "peerDependencies": { + "peggy": "^3.0.2" + } + }, + "node_modules/ts-pegjs/node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/tsx": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.7.1.tgz", + "integrity": "sha512-8d6VuibXHtlN5E3zFkgY8u4DX7Y3Z27zvvPKVmLon/D4AjuKzarkUBTLDBgj9iTQ0hg5xM7c/mYiRVM+HETf0g==", + "dev": true, + "dependencies": { + "esbuild": "~0.19.10", + "get-tsconfig": "^4.7.2" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-arm": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.12.tgz", + "integrity": "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz", + "integrity": "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.12.tgz", + "integrity": "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/darwin-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz", + "integrity": "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/darwin-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz", + "integrity": "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/freebsd-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz", + "integrity": "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/freebsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz", + "integrity": "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-arm": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz", + "integrity": "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz", + "integrity": "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-ia32": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz", + "integrity": "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-loong64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz", + "integrity": "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-mips64el": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz", + "integrity": "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-ppc64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz", + "integrity": "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-riscv64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz", + "integrity": "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-s390x": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz", + "integrity": "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz", + "integrity": "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/netbsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz", + "integrity": "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/openbsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz", + "integrity": "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/sunos-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz", + "integrity": "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz", + "integrity": "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-ia32": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz", + "integrity": "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz", + "integrity": "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/esbuild": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz", + "integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.19.12", + "@esbuild/android-arm": "0.19.12", + "@esbuild/android-arm64": "0.19.12", + "@esbuild/android-x64": "0.19.12", + "@esbuild/darwin-arm64": "0.19.12", + "@esbuild/darwin-x64": "0.19.12", + "@esbuild/freebsd-arm64": "0.19.12", + "@esbuild/freebsd-x64": "0.19.12", + "@esbuild/linux-arm": "0.19.12", + "@esbuild/linux-arm64": "0.19.12", + "@esbuild/linux-ia32": "0.19.12", + "@esbuild/linux-loong64": "0.19.12", + "@esbuild/linux-mips64el": "0.19.12", + "@esbuild/linux-ppc64": "0.19.12", + "@esbuild/linux-riscv64": "0.19.12", + "@esbuild/linux-s390x": "0.19.12", + "@esbuild/linux-x64": "0.19.12", + "@esbuild/netbsd-x64": "0.19.12", + "@esbuild/openbsd-x64": "0.19.12", + "@esbuild/sunos-x64": "0.19.12", + "@esbuild/win32-arm64": "0.19.12", + "@esbuild/win32-ia32": "0.19.12", + "@esbuild/win32-x64": "0.19.12" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", + "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=12.20" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "browserslist-lint": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "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 + }, + "node_modules/v8-to-istanbul": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz", + "integrity": "sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/v8-to-istanbul/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 + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/whatwg-fetch": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz", + "integrity": "sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/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==", + "dev": true, + "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" + } + }, + "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==", + "dev": true + }, + "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==", + "dev": true, + "engines": { + "node": ">=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==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "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==", + "dev": true + }, + "node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/yaml": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.2.tgz", + "integrity": "sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA==", + "engines": { + "node": ">= 14" + } + }, + "node_modules/yargs": { + "version": "17.7.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", + "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", + "dev": true, + "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" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs/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==", + "dev": true + }, + "node_modules/yargs/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==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/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==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=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, + "engines": { + "node": ">=6" + } + }, + "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, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/sdk/package.json b/sdk/package/package.json similarity index 77% rename from sdk/package.json rename to sdk/package/package.json index 038db0244..7e97d4a32 100644 --- a/sdk/package.json +++ b/sdk/package/package.json @@ -1,24 +1,24 @@ { "name": "@start9labs/start-sdk", - "version": "0.3.6-alpha8", + "version": "0.3.6-alpha.21", "description": "Software development kit to facilitate packaging services for StartOS", - "main": "./cjs/lib/index.js", - "types": "./cjs/lib/index.d.ts", - "module": "./mjs/lib/index.js", - "browser": "./mjs/lib/index.browser.js", + "main": "./package/lib/index.js", + "types": "./package/lib/index.d.ts", "sideEffects": true, "typesVersion": { ">=3.1": { "*": [ - "cjs/lib/*" + "package/lib/*", + "base/lib/*" ] } }, "scripts": { "build": "tsc && tsc --project tsconfig-cjs.json && copyfiles package.json dist", "test": "jest -c ./jest.config.js --coverage", - "buildOutput": "ts-node --project ./tsconfig-cjs.json ./lib/test/makeOutput.ts && npx prettier --write '**/*.ts'", - "check": "tsc --noEmit" + "buildOutput": "ts-node ./lib/test/makeOutput.ts && npx prettier --write \"**/*.ts\"", + "check": "tsc --noEmit", + "tsc": "tsc" }, "repository": { "type": "git", @@ -33,8 +33,8 @@ "dependencies": { "isomorphic-fetch": "^3.0.0", "lodash.merge": "^4.6.2", - "mime": "^4.0.3", - "ts-matches": "^5.5.1", + "mime-types": "^2.1.35", + "ts-matches": "^6.1.0", "yaml": "^2.2.2", "@iarna/toml": "^2.2.5", "@noble/curves": "^1.4.0", diff --git a/sdk/scripts/oldSpecToBuilder.ts b/sdk/package/scripts/oldSpecToBuilder.ts similarity index 85% rename from sdk/scripts/oldSpecToBuilder.ts rename to sdk/package/scripts/oldSpecToBuilder.ts index 6dd726e1b..11ef30340 100644 --- a/sdk/scripts/oldSpecToBuilder.ts +++ b/sdk/package/scripts/oldSpecToBuilder.ts @@ -33,18 +33,18 @@ export default async function makeFileContentFromOld( const outputLines: string[] = [] outputLines.push(` import { sdk } from "${StartSdk}" -const {Config, List, Value, Variants} = sdk +const {InputSpec, List, Value, Variants} = sdk `) const data = await inputData - const namedConsts = new Set(["Config", "Value", "List"]) - const configName = newConst("configSpec", convertInputSpec(data)) - const configMatcherName = newConst( - "matchConfigSpec", - `${configName}.validator`, + const namedConsts = new Set(["InputSpec", "Value", "List"]) + const inputSpecName = newConst("inputSpecSpec", convertInputSpec(data)) + const inputSpecMatcherName = newConst( + "matchInputSpecSpec", + `${inputSpecName}.validator`, ) outputLines.push( - `export type ConfigSpec = typeof ${configMatcherName}._TYPE;`, + `export type InputSpecSpec = typeof ${inputSpecMatcherName}._TYPE;`, ) return outputLines.join("\n") @@ -71,7 +71,7 @@ const {Config, List, Value, Variants} = sdk } function convertInputSpec(data: any) { - return `Config.of(${convertInputSpecInner(data)})` + return `InputSpec.of(${convertInputSpecInner(data)})` } function convertValueSpec(value: any): string { switch (value.type) { @@ -85,6 +85,7 @@ const {Config, List, Value, Variants} = sdk description: value.description || null, warning: value.warning || null, required: !(value.nullable || false), + default: value.default, placeholder: value.placeholder || null, maxLength: null, minLength: null, @@ -96,12 +97,8 @@ const {Config, List, Value, Variants} = sdk return `${rangeToTodoComment(value?.range)}Value.text(${JSON.stringify( { name: value.name || null, - // prettier-ignore - required: ( - value.default != null ? {default: value.default} : - value.nullable === false ? {default: null} : - !value.nullable - ), + default: value.default || null, + required: !value.nullable, description: value.description || null, warning: value.warning || null, masked: value.masked || false, @@ -130,12 +127,8 @@ const {Config, List, Value, Variants} = sdk name: value.name || null, description: value.description || null, warning: value.warning || null, - // prettier-ignore - required: ( - value.default != null ? {default: value.default} : - value.nullable === false ? {default: null} : - !value.nullable - ), + default: value.default || null, + required: !value.nullable, min: null, max: null, step: null, @@ -174,13 +167,7 @@ const {Config, List, Value, Variants} = sdk name: value.name || null, description: value.description || null, warning: value.warning || null, - - // prettier-ignore - required:( - value.default != null ? {default: value.default} : - value.nullable === false ? {default: null} : - !value.nullable - ), + default: value.default, values, }, null, @@ -195,7 +182,6 @@ const {Config, List, Value, Variants} = sdk return `Value.object({ name: ${JSON.stringify(value.name || null)}, description: ${JSON.stringify(value.description || null)}, - warning: ${JSON.stringify(value.warning || null)}, }, ${specName})` } case "union": { @@ -208,14 +194,7 @@ const {Config, List, Value, Variants} = sdk name: ${JSON.stringify(value.name || null)}, description: ${JSON.stringify(value.tag.description || null)}, warning: ${JSON.stringify(value.tag.warning || null)}, - - // prettier-ignore - required: ${JSON.stringify( - // prettier-ignore - value.default != null ? {default: value.default} : - value.nullable === false ? {default: null} : - !value.nullable, - )}, + default: ${JSON.stringify(value.default)}, }, ${variants})` } case "list": { @@ -319,7 +298,6 @@ const {Config, List, Value, Variants} = sdk maxLength: ${JSON.stringify(null)}, default: ${JSON.stringify(value.default || null)}, description: ${JSON.stringify(value.description || null)}, - warning: ${JSON.stringify(value.warning || null)}, }, { spec: ${specName}, displayAs: ${JSON.stringify(value?.spec?.["display-as"] || null)}, @@ -343,19 +321,14 @@ const {Config, List, Value, Variants} = sdk value?.spec?.tag?.description || null, )}, warning: ${JSON.stringify(value?.spec?.tag?.warning || null)}, - required: ${JSON.stringify( - // prettier-ignore - 'default' in value?.spec ? {default: value?.spec?.default} : - !!value?.spec?.tag?.nullable || false ? {default: null} : - false, - )}, + default: ${JSON.stringify(value?.spec?.default || null)}, }, ${variants}) `, ) - const listConfig = maybeNewConst( - value.name + "_list_config", + const listInputSpec = maybeNewConst( + value.name + "_list_inputSpec", ` - Config.of({ + InputSpec.of({ "union": ${unionValueName} }) `, @@ -368,7 +341,7 @@ const {Config, List, Value, Variants} = sdk description: ${JSON.stringify(value.description || null)}, warning: ${JSON.stringify(value.warning || null)}, }, { - spec: ${listConfig}, + spec: ${listInputSpec}, displayAs: ${JSON.stringify(value?.spec?.["display-as"] || null)}, uniqueBy: ${JSON.stringify(value?.spec?.["unique-by"] || null)}, })` @@ -407,7 +380,7 @@ function rangeToTodoComment(range: string | undefined) { } // oldSpecToBuilder( -// "./config.ts", -// // Put config here +// "./inputSpec.ts", +// // Put inputSpec here // {}, // ) diff --git a/sdk/package/tsconfig.json b/sdk/package/tsconfig.json new file mode 100644 index 000000000..7b4d4f7d8 --- /dev/null +++ b/sdk/package/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "strict": true, + "preserveConstEnums": true, + "sourceMap": true, + "pretty": true, + "declaration": true, + "noImplicitAny": true, + "esModuleInterop": true, + "types": ["node", "jest"], + "moduleResolution": "node", + "skipLibCheck": true, + "module": "commonjs", + "outDir": "../dist", + "target": "es2018" + }, + "include": ["lib/**/*", "../base/lib/util/Hostname.ts"], + "exclude": ["lib/**/*.spec.ts", "lib/**/*.gen.ts", "list", "node_modules"] +} diff --git a/sdk/tsconfig-cjs.json b/sdk/tsconfig-cjs.json deleted file mode 100644 index 8413cf248..000000000 --- a/sdk/tsconfig-cjs.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": "./tsconfig-base.json", - "compilerOptions": { - "module": "commonjs", - "outDir": "dist/cjs", - "target": "es2018" - } -} diff --git a/sdk/tsconfig.json b/sdk/tsconfig.json deleted file mode 100644 index 8ae7d62a8..000000000 --- a/sdk/tsconfig.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": "./tsconfig-base.json", - "compilerOptions": { - "module": "esnext", - "outDir": "dist/mjs", - "target": "esnext" - } -} diff --git a/web/README.md b/web/README.md index dc594579a..565d0f7d3 100644 --- a/web/README.md +++ b/web/README.md @@ -24,10 +24,10 @@ Additionally, there are two libraries for shared code: ```sh node --version -v18.15.0 +v20.17.0 npm --version -v8.0.0 +v10.8.2 ``` #### Install and enable the Prettier extension for your text editor @@ -48,6 +48,8 @@ npm ci npm run build:deps ``` +> Note if you are on **Windows** you need to install `make` for these scripts to work. Easiest way to do so is to install [Chocolatey](https://chocolatey.org/install) and then run `choco install make`. + #### Copy `config-sample.json` to a new file `config.json`. ```sh diff --git a/web/package-lock.json b/web/package-lock.json index 3a9c7eeb5..3258cf9fc 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -1,12 +1,12 @@ { "name": "startos-ui", - "version": "0.3.6-alpha.5", + "version": "0.3.6-alpha.8", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "startos-ui", - "version": "0.3.6-alpha.5", + "version": "0.3.6-alpha.8", "license": "MIT", "dependencies": { "@angular/animations": "^17.3.1", @@ -21,10 +21,13 @@ "@angular/router": "^17.3.1", "@angular/service-worker": "^17.3.1", "@materia-ui/ngx-monaco-editor": "^6.0.0", + "@ng-web-apis/common": "^3.2.3", + "@ng-web-apis/mutation-observer": "^3.2.3", + "@ng-web-apis/resize-observer": "^3.2.3", "@noble/curves": "^1.4.0", "@noble/hashes": "^1.4.0", "@start9labs/argon2": "^0.2.2", - "@start9labs/start-sdk": "file:../sdk/dist", + "@start9labs/start-sdk": "file:../sdk/baseDist", "@taiga-ui/addon-charts": "4.0.0-rc.7", "@taiga-ui/addon-commerce": "4.0.0-rc.7", "@taiga-ui/addon-mobile": "4.0.0-rc.7", @@ -57,6 +60,7 @@ "ng-qrcode": "^17.0.0", "node-jose": "^2.2.0", "patch-db-client": "file:../patch-db/client", + "path-browserify": "^1.0.1", "pbkdf2": "^3.1.2", "rxjs": "^7.5.6", "swiper": "^8.2.4", @@ -1980,9 +1984,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "../sdk/baseDist": {}, "../sdk/dist": { "name": "@start9labs/start-sdk", "version": "0.3.6-alpha8", + "extraneous": true, "license": "MIT", "dependencies": { "@iarna/toml": "^2.2.5", @@ -1995,8 +2001,10 @@ "yaml": "^2.2.2" }, "devDependencies": { + "@iarna/toml": "^2.2.5", "@types/jest": "^29.4.0", "@types/lodash.merge": "^4.6.2", + "copyfiles": "^2.4.1", "jest": "^29.4.3", "peggy": "^3.0.2", "prettier": "^3.2.5", @@ -2004,7 +2012,8 @@ "ts-node": "^10.9.1", "ts-pegjs": "^4.2.1", "tsx": "^4.7.1", - "typescript": "^5.0.4" + "typescript": "^5.0.4", + "yaml": "^2.2.2" } }, "node_modules/@ampproject/remapping": { @@ -4608,16 +4617,17 @@ } }, "node_modules/@ng-web-apis/common": { - "version": "4.2.0", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/@ng-web-apis/common/-/common-3.2.3.tgz", + "integrity": "sha512-1ts2FkLRw6dE/uTuYFMf9VTbLJ9CS8dpfIXTpxFsPArs13mEuz0Yvpe0rl0tMAhfNoeN4e7V8wVSyqDNgfzgmw==", "license": "Apache-2.0", - "peer": true, "dependencies": { - "tslib": "^2.3.0" + "tslib": "^2.2.0" }, "peerDependencies": { - "@angular/common": ">=16.0.0", - "@angular/core": ">=16.0.0", - "rxjs": ">=7.0.0" + "@angular/common": ">=12.0.0", + "@angular/core": ">=12.0.0", + "rxjs": ">=6.4.0" } }, "node_modules/@ng-web-apis/intersection-observer": { @@ -4633,27 +4643,29 @@ } }, "node_modules/@ng-web-apis/mutation-observer": { - "version": "4.2.0", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/@ng-web-apis/mutation-observer/-/mutation-observer-3.2.3.tgz", + "integrity": "sha512-iFwxut1cw94lTXnloDMBRanqNTvEjbnigWkTowlPH3QY16ysTKuC51JeonRuARW4K3bbDGbXiLUYYZWKQaDfKw==", "license": "Apache-2.0", - "peer": true, "dependencies": { - "tslib": "^2.3.0" + "tslib": "^2.2.0" }, "peerDependencies": { - "@angular/core": ">=16.0.0", - "@ng-web-apis/common": ">=4.1.3" + "@angular/core": ">=12.0.0", + "@ng-web-apis/common": ">=2.0.0" } }, "node_modules/@ng-web-apis/resize-observer": { - "version": "4.2.0", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/@ng-web-apis/resize-observer/-/resize-observer-3.2.3.tgz", + "integrity": "sha512-x3KxBZSragzdQlkbY9tiHY0lVlkOFD7Y34rzXdBJ7PTnIvlq43X/tN31Mmb3R0Np4vsarWqnhO6Y42ljudsWdA==", "license": "Apache-2.0", - "peer": true, "dependencies": { - "tslib": "^2.3.0" + "tslib": "^2.2.0" }, "peerDependencies": { - "@angular/core": ">=16.0.0", - "@ng-web-apis/common": ">=4.1.3" + "@angular/core": ">=12.0.0", + "@ng-web-apis/common": ">=2.0.0" } }, "node_modules/@ngtools/webpack": { @@ -4673,8 +4685,7 @@ }, "node_modules/@noble/curves": { "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.5.0.tgz", - "integrity": "sha512-J5EKamIHnKPyClwVrzmaf5wSdQXgdHcPZIZLu3bwnbeCx8/7NPK5q2ZBWF+5FvYGByjiQQsJYX6jfgB2wDPn3A==", + "license": "MIT", "dependencies": { "@noble/hashes": "1.4.0" }, @@ -4684,8 +4695,7 @@ }, "node_modules/@noble/hashes": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", - "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "license": "MIT", "engines": { "node": ">= 16" }, @@ -5127,12 +5137,10 @@ } }, "node_modules/@start9labs/argon2": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@start9labs/argon2/-/argon2-0.2.2.tgz", - "integrity": "sha512-OEJYDIicwwWg0NgG3d2GSO2Qs65B0LY9dIrlXFIJZJ1mo9vcDIU0kC2Yp8dg4XMt2U16ncsgru98s9I+y5Yuaw==" + "version": "0.2.2" }, "node_modules/@start9labs/start-sdk": { - "resolved": "../sdk/dist", + "resolved": "../sdk/baseDist", "link": true }, "node_modules/@taiga-ui/addon-charts": { @@ -9438,9 +9446,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, "bin": { "mime": "cli.js" @@ -10105,11 +10112,10 @@ }, "node_modules/mime": { "version": "4.0.4", - "resolved": "https://registry.npmjs.org/mime/-/mime-4.0.4.tgz", - "integrity": "sha512-v8yqInVjhXyqP6+Kw4fV3ZzeMRqEW6FotRsKXjRS5VMTNIuXsdRoAvklpoRgSqXm6o9VNH4/C0mgedko9DdLsQ==", "funding": [ "https://github.com/sponsors/broofa" ], + "license": "MIT", "bin": { "mime": "bin/cli.js" }, @@ -11326,6 +11332,12 @@ "resolved": "../patch-db/client", "link": true }, + "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" + }, "node_modules/path-exists": { "version": "4.0.0", "license": "MIT", @@ -12620,9 +12632,8 @@ }, "node_modules/send/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": { "mime": "cli.js" }, @@ -13451,8 +13462,7 @@ }, "node_modules/ts-matches": { "version": "5.5.1", - "resolved": "https://registry.npmjs.org/ts-matches/-/ts-matches-5.5.1.tgz", - "integrity": "sha512-UFYaKgfqlg9FROK7bdpYqFwG1CJvP4kOJdjXuWoqxo9jCmANoDw1GxkSCpJgoTeIiSTaTH5Qr1klSspb8c+ydg==" + "license": "MIT" }, "node_modules/ts-node": { "version": "10.9.2", diff --git a/web/package.json b/web/package.json index 92c8870e1..ab3649f5d 100644 --- a/web/package.json +++ b/web/package.json @@ -1,6 +1,6 @@ { "name": "startos-ui", - "version": "0.3.6-alpha.5", + "version": "0.3.6-alpha.8", "author": "Start9 Labs, Inc", "homepage": "https://start9.com/", "license": "MIT", @@ -44,8 +44,13 @@ "@angular/router": "^17.3.1", "@angular/service-worker": "^17.3.1", "@materia-ui/ngx-monaco-editor": "^6.0.0", + "@ng-web-apis/common": "^3.2.3", + "@ng-web-apis/mutation-observer": "^3.2.3", + "@ng-web-apis/resize-observer": "^3.2.3", + "@noble/curves": "^1.4.0", + "@noble/hashes": "^1.4.0", "@start9labs/argon2": "^0.2.2", - "@start9labs/start-sdk": "file:../sdk/dist", + "@start9labs/start-sdk": "file:../sdk/baseDist", "@taiga-ui/addon-charts": "4.0.0-rc.7", "@taiga-ui/addon-commerce": "4.0.0-rc.7", "@taiga-ui/addon-mobile": "4.0.0-rc.7", @@ -58,8 +63,6 @@ "@taiga-ui/legacy": "4.0.0-rc.7", "@taiga-ui/styles": "4.0.0-rc.7", "@tinkoff/ng-dompurify": "4.0.0", - "@noble/curves": "^1.4.0", - "@noble/hashes": "^1.4.0", "ansi-to-html": "^0.7.2", "base64-js": "^1.5.1", "buffer": "^6.0.3", @@ -80,6 +83,7 @@ "ng-qrcode": "^17.0.0", "node-jose": "^2.2.0", "patch-db-client": "file:../patch-db/client", + "path-browserify": "^1.0.1", "pbkdf2": "^3.1.2", "rxjs": "^7.5.6", "swiper": "^8.2.4", diff --git a/web/patchdb-ui-seed.json b/web/patchdb-ui-seed.json index 221b80a3b..c6b967e29 100644 --- a/web/patchdb-ui-seed.json +++ b/web/patchdb-ui-seed.json @@ -21,5 +21,5 @@ "ackInstructions": {}, "theme": "Dark", "widgets": [], - "ack-welcome": "0.3.6-alpha.5" + "ack-welcome": "0.3.6-alpha.8" } diff --git a/web/projects/setup-wizard/src/app/services/mock-api.service.ts b/web/projects/setup-wizard/src/app/services/mock-api.service.ts index c71cc8ef4..99be80684 100644 --- a/web/projects/setup-wizard/src/app/services/mock-api.service.ts +++ b/web/projects/setup-wizard/src/app/services/mock-api.service.ts @@ -159,6 +159,7 @@ export class MockApiService extends ApiService { return { status: 'complete', torAddress: 'https://asdafsadasdasasdasdfasdfasdf.onion', + hostname: 'adjective-noun', lanAddress: 'https://adjective-noun.local', rootCa: encodeBase64(rootCA), } @@ -313,6 +314,7 @@ export class MockApiService extends ApiService { await pauseFor(1000) return { torAddress: 'https://asdafsadasdasasdasdfasdfasdf.onion', + hostname: 'adjective-noun', lanAddress: 'https://adjective-noun.local', rootCa: encodeBase64(rootCA), } diff --git a/web/projects/shared/src/pipes/unit-conversion/unit-conversion.pipe.ts b/web/projects/shared/src/pipes/unit-conversion/unit-conversion.pipe.ts index 289ce835f..a908b47e4 100644 --- a/web/projects/shared/src/pipes/unit-conversion/unit-conversion.pipe.ts +++ b/web/projects/shared/src/pipes/unit-conversion/unit-conversion.pipe.ts @@ -10,6 +10,15 @@ export class ConvertBytesPipe implements PipeTransform { } } +export function convertBytes(bytes: number): string { + if (bytes === 0) return '0 Bytes' + + const k = 1024 + const i = Math.floor(Math.log(bytes) / Math.log(k)) + + return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i] +} + @Pipe({ name: 'durationToSeconds', }) diff --git a/web/projects/shared/src/services/exver.service.ts b/web/projects/shared/src/services/exver.service.ts index f3a28fae2..516879333 100644 --- a/web/projects/shared/src/services/exver.service.ts +++ b/web/projects/shared/src/services/exver.service.ts @@ -1,5 +1,5 @@ import { Injectable } from '@angular/core' -import { VersionRange, ExtendedVersion, Version } from '@start9labs/start-sdk' +import { ExtendedVersion, VersionRange } from '@start9labs/start-sdk' @Injectable({ providedIn: 'root', @@ -29,12 +29,8 @@ export class Exver { } } - compareOsVersion(current: string, other: string) { - return Version.parse(current).compare(Version.parse(other)) - } - satisfies(version: string, range: string): boolean { - return VersionRange.parse(range).satisfiedBy(ExtendedVersion.parse(version)) + return ExtendedVersion.parse(version).satisfies(VersionRange.parse(range)) } getFlavor(version: string): string | null { diff --git a/web/projects/ui/src/app/pages/apps-routes/app-show/components/app-show-action-requests/app-show-action-requests.component.html b/web/projects/ui/src/app/pages/apps-routes/app-show/components/app-show-action-requests/app-show-action-requests.component.html new file mode 100644 index 000000000..2aee18f05 --- /dev/null +++ b/web/projects/ui/src/app/pages/apps-routes/app-show/components/app-show-action-requests/app-show-action-requests.component.html @@ -0,0 +1,45 @@ + + Required Actions + + + +

{{ request.actionName }}

+

+ Service: + + {{ request.dependency.title }} +

+

+ Reason: + {{ request.reason || 'no reason provided' }} +

+
+
+
+ + + Requested Actions + + + +

{{ request.actionName }}

+

+ Service: + + {{ request.dependency.title }} +

+

+ Reason: + {{ request.reason || 'no reason provided' }} +

+
+
+
diff --git a/web/projects/ui/src/app/pages/apps-routes/app-show/components/app-show-action-requests/app-show-action-requests.component.scss b/web/projects/ui/src/app/pages/apps-routes/app-show/components/app-show-action-requests/app-show-action-requests.component.scss new file mode 100644 index 000000000..c83e6f6a7 --- /dev/null +++ b/web/projects/ui/src/app/pages/apps-routes/app-show/components/app-show-action-requests/app-show-action-requests.component.scss @@ -0,0 +1,16 @@ +.light { + color: var(--ion-color-dark); +} + +.highlighted { + color: var(--ion-color-dark); + font-weight: bold; +} + +.dependency { + display: inline-flex; + img { + max-width: 16px; + margin: 0 2px 0 5px; + } +} \ No newline at end of file diff --git a/web/projects/ui/src/app/pages/apps-routes/app-show/components/app-show-action-requests/app-show-action-requests.component.ts b/web/projects/ui/src/app/pages/apps-routes/app-show/components/app-show-action-requests/app-show-action-requests.component.ts new file mode 100644 index 000000000..0fefe17be --- /dev/null +++ b/web/projects/ui/src/app/pages/apps-routes/app-show/components/app-show-action-requests/app-show-action-requests.component.ts @@ -0,0 +1,94 @@ +import { ChangeDetectionStrategy, Component, Input } from '@angular/core' +import { T } from '@start9labs/start-sdk' +import { ActionService } from 'src/app/services/action.service' +import { getDepDetails } from 'src/app/util/dep-info' + +@Component({ + selector: 'app-show-action-requests', + templateUrl: './app-show-action-requests.component.html', + styleUrls: ['./app-show-action-requests.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class AppShowActionRequestsComponent { + @Input() + allPkgs!: Record + + @Input() + pkg!: T.PackageDataEntry + + @Input() + manifest!: T.Manifest + + get actionRequests() { + const critical: (T.ActionRequest & { + actionName: string + dependency: { + title: string + icon: string + } | null + })[] = [] + const important: (T.ActionRequest & { + actionName: string + dependency: { + title: string + icon: string + } | null + })[] = [] + + Object.values(this.pkg.requestedActions) + .filter(r => r.active) + .forEach(r => { + const self = r.request.packageId === this.manifest.id + const toReturn = { + ...r.request, + actionName: self + ? this.pkg.actions[r.request.actionId].name + : this.allPkgs[r.request.packageId]?.actions[r.request.actionId] + .name || 'Unknown Action', + dependency: self + ? null + : getDepDetails(this.pkg, this.allPkgs, r.request.packageId), + } + + if (r.request.severity === 'critical') { + critical.push(toReturn) + } else { + important.push(toReturn) + } + }) + + return { critical, important } + } + + constructor(private readonly actionService: ActionService) {} + + async handleAction(request: T.ActionRequest) { + const self = request.packageId === this.manifest.id + this.actionService.present({ + pkgInfo: { + id: request.packageId, + title: self + ? this.manifest.title + : getDepDetails(this.pkg, this.allPkgs, request.packageId).title, + mainStatus: self + ? this.pkg.status.main + : this.allPkgs[request.packageId].status.main, + icon: self + ? this.pkg.icon + : getDepDetails(this.pkg, this.allPkgs, request.packageId).icon, + }, + actionInfo: { + id: request.actionId, + metadata: + request.packageId === this.manifest.id + ? this.pkg.actions[request.actionId] + : this.allPkgs[request.packageId].actions[request.actionId], + }, + requestInfo: { + request, + dependentId: + request.packageId === this.manifest.id ? undefined : this.manifest.id, + }, + }) + } +} diff --git a/web/projects/ui/src/app/pages/apps-routes/app-show/components/app-show-error/app-show-error.component.html b/web/projects/ui/src/app/pages/apps-routes/app-show/components/app-show-error/app-show-error.component.html new file mode 100644 index 000000000..c056f2977 --- /dev/null +++ b/web/projects/ui/src/app/pages/apps-routes/app-show/components/app-show-error/app-show-error.component.html @@ -0,0 +1,31 @@ +Message +
+ + {{ error.message }} + +
+ +Actions +
+

+ Rebuild Container + is harmless action that and only takes a few seconds to complete. It will + likely resolve this issue. + Uninstall Service + is a dangerous action that will remove the service from StartOS and wipe all + its data. +

+ + Rebuild Container + + + Uninstall Service + +
+ + + Full Stack Trace +
+ {{ error.message }} +
+
diff --git a/web/projects/ui/src/app/pages/apps-routes/app-show/components/app-show-error/app-show-error.component.ts b/web/projects/ui/src/app/pages/apps-routes/app-show/components/app-show-error/app-show-error.component.ts new file mode 100644 index 000000000..ef689f178 --- /dev/null +++ b/web/projects/ui/src/app/pages/apps-routes/app-show/components/app-show-error/app-show-error.component.ts @@ -0,0 +1,45 @@ +import { ChangeDetectionStrategy, Component, Input } from '@angular/core' +import { ToastController } from '@ionic/angular' +import { copyToClipboard } from '@start9labs/shared' +import { T } from '@start9labs/start-sdk' +import { StandardActionsService } from 'src/app/services/standard-actions.service' + +@Component({ + selector: 'app-show-error', + templateUrl: 'app-show-error.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class AppShowErrorComponent { + @Input() + manifest!: T.Manifest + + @Input() + error!: T.MainStatus & { main: 'error' } + + constructor( + private readonly toastCtrl: ToastController, + private readonly standardActionsService: StandardActionsService, + ) {} + + async copy(text: string): Promise { + const success = await copyToClipboard(text) + const message = success + ? 'Copied to clipboard!' + : 'Failed to copy to clipboard.' + + const toast = await this.toastCtrl.create({ + header: message, + position: 'bottom', + duration: 1000, + }) + await toast.present() + } + + async rebuild() { + return this.standardActionsService.rebuild(this.manifest.id) + } + + async tryUninstall() { + return this.standardActionsService.tryUninstall(this.manifest) + } +} diff --git a/web/projects/ui/src/app/pages/server-routes/sideload/sideload.service.ts b/web/projects/ui/src/app/pages/server-routes/sideload/sideload.service.ts new file mode 100644 index 000000000..79f871bba --- /dev/null +++ b/web/projects/ui/src/app/pages/server-routes/sideload/sideload.service.ts @@ -0,0 +1,32 @@ +import { Injectable } from '@angular/core' +import { T } from '@start9labs/start-sdk' +import { endWith, ReplaySubject, shareReplay, Subject, switchMap } from 'rxjs' +import { ApiService } from 'src/app/services/api/embassy-api.service' + +@Injectable({ + providedIn: 'root', +}) +export class SideloadService { + private readonly guid$ = new Subject() + + readonly websocketConnected$ = new ReplaySubject() + + readonly progress$ = this.guid$.pipe( + switchMap(guid => + this.api + .openWebsocket$(guid, { + openObserver: { + next: () => this.websocketConnected$.next(''), + }, + }) + .pipe(endWith(null)), + ), + shareReplay(1), + ) + + constructor(private readonly api: ApiService) {} + + followProgress(guid: string) { + this.guid$.next(guid) + } +} diff --git a/web/projects/ui/src/app/routes/diagnostic/home/home.page.ts b/web/projects/ui/src/app/routes/diagnostic/home/home.page.ts index 02ee136cb..0eae7e98b 100644 --- a/web/projects/ui/src/app/routes/diagnostic/home/home.page.ts +++ b/web/projects/ui/src/app/routes/diagnostic/home/home.page.ts @@ -5,6 +5,7 @@ import { LoadingService } from '@start9labs/shared' import { TuiDialogService } from '@taiga-ui/core' import { filter } from 'rxjs' import { ApiService } from 'src/app/services/api/embassy-api.service' +import { ConfigService } from 'src/app/services/config.service' @Component({ selector: 'diagnostic-home', @@ -25,6 +26,7 @@ export class HomePage { private readonly api: ApiService, private readonly dialogs: TuiDialogService, @Inject(WA_WINDOW) private readonly window: Window, + readonly config: ConfigService, ) {} async ngOnInit() { diff --git a/web/projects/ui/src/app/routes/portal/components/form.component.ts b/web/projects/ui/src/app/routes/portal/components/form.component.ts index 3d699af5b..c55c6392d 100644 --- a/web/projects/ui/src/app/routes/portal/components/form.component.ts +++ b/web/projects/ui/src/app/routes/portal/components/form.component.ts @@ -8,8 +8,7 @@ import { } from '@angular/core' import { FormGroup, ReactiveFormsModule } from '@angular/forms' import { RouterModule } from '@angular/router' -import { CT } from '@start9labs/start-sdk' - +import { IST } from '@start9labs/start-sdk' import { tuiMarkControlAsTouchedAndValidate, TuiValueChanges, @@ -29,10 +28,10 @@ export interface ActionButton { } export interface FormContext { - spec: CT.InputSpec + spec: IST.InputSpec buttons: ActionButton[] value?: T - patch?: Operation[] + operations?: Operation[] } @Component({ @@ -110,7 +109,7 @@ export class FormComponent> implements OnInit { @Input() spec = this.context?.data.spec || {} @Input() buttons = this.context?.data.buttons || [] - @Input() patch = this.context?.data.patch || [] + @Input() operations = this.context?.data.operations || [] @Input() value?: T = this.context?.data.value form = new FormGroup({}) @@ -118,7 +117,7 @@ export class FormComponent> implements OnInit { ngOnInit() { this.confirmService.markAsPristine() this.form = this.formService.createForm(this.spec, this.value) - this.process(this.patch) + this.process(this.operations) } onReset() { @@ -147,15 +146,16 @@ export class FormComponent> implements OnInit { this.context?.$implicit.complete() } - private process(patch: Operation[]) { - patch.forEach(({ op, path }) => { - const control = this.form.get(path.substring(1).split('/')) + private process(operations: Operation[]) { + operations.forEach(operation => { + const control = this.form.get(operation.path.substring(1).split('/')) if (!control || !control.parent) return - if (op !== 'remove') { + if (operation.op === 'add' || operation.op === 'replace') { control.markAsDirty() control.markAsTouched() + control.setValue(operation.value) } control.parent.markAsDirty() diff --git a/web/projects/ui/src/app/routes/portal/components/form/control.ts b/web/projects/ui/src/app/routes/portal/components/form/control.ts index 476826194..c77c76ecf 100644 --- a/web/projects/ui/src/app/routes/portal/components/form/control.ts +++ b/web/projects/ui/src/app/routes/portal/components/form/control.ts @@ -1,8 +1,8 @@ import { inject } from '@angular/core' import { FormControlComponent } from './form-control/form-control.component' -import { CT } from '@start9labs/start-sdk' +import { IST } from '@start9labs/start-sdk' -export abstract class Control { +export abstract class Control, Value> { private readonly control: FormControlComponent = inject(FormControlComponent) diff --git a/web/projects/ui/src/app/routes/portal/components/form/filter-hidden.pipe.ts b/web/projects/ui/src/app/routes/portal/components/form/filter-hidden.pipe.ts new file mode 100644 index 000000000..84666a2c9 --- /dev/null +++ b/web/projects/ui/src/app/routes/portal/components/form/filter-hidden.pipe.ts @@ -0,0 +1,15 @@ +import { Pipe, PipeTransform } from '@angular/core' +import { IST } from '@start9labs/start-sdk' +import { KeyValue } from '@angular/common' + +@Pipe({ + name: 'filterHidden', +}) +export class FilterHiddenPipe implements PipeTransform { + transform(value: KeyValue[]) { + return value.filter(x => x.value.type !== 'hidden') as KeyValue< + string, + Exclude + >[] + } +} diff --git a/web/projects/ui/src/app/routes/portal/components/form/form-array/form-array.component.ts b/web/projects/ui/src/app/routes/portal/components/form/form-array/form-array.component.ts index 6cf8736fc..3f3526122 100644 --- a/web/projects/ui/src/app/routes/portal/components/form/form-array/form-array.component.ts +++ b/web/projects/ui/src/app/routes/portal/components/form/form-array/form-array.component.ts @@ -18,6 +18,7 @@ import { } from '@taiga-ui/core' import { TUI_CONFIRM } from '@taiga-ui/kit' import { filter } from 'rxjs' +import { IST } from '@start9labs/start-sdk' import { FormService } from 'src/app/services/form.service' import { ERRORS } from '../form-group/form-group.component' @@ -29,7 +30,7 @@ import { ERRORS } from '../form-group/form-group.component' }) export class FormArrayComponent { @Input({ required: true }) - spec!: CT.ValueSpecList + spec!: IST.ValueSpecList @HostBinding('@tuiParentStop') readonly animation = tuiToAnimationOptions(inject(TUI_ANIMATIONS_SPEED)) diff --git a/web/projects/ui/src/app/routes/portal/components/form/form-color/form-color.component.ts b/web/projects/ui/src/app/routes/portal/components/form/form-color/form-color.component.ts index 32a7c1c04..0f65f06ce 100644 --- a/web/projects/ui/src/app/routes/portal/components/form/form-color/form-color.component.ts +++ b/web/projects/ui/src/app/routes/portal/components/form/form-color/form-color.component.ts @@ -1,5 +1,5 @@ import { Component } from '@angular/core' -import { CT } from '@start9labs/start-sdk' +import { IST } from '@start9labs/start-sdk' import { Control } from '../control' import { MaskitoOptions } from '@maskito/core' @@ -8,7 +8,7 @@ import { MaskitoOptions } from '@maskito/core' templateUrl: './form-color.component.html', styleUrls: ['./form-color.component.scss'], }) -export class FormColorComponent extends Control { +export class FormColorComponent extends Control { readonly mask: MaskitoOptions = { mask: ['#', ...Array(6).fill(/[0-9a-f]/i)], } diff --git a/web/projects/ui/src/app/routes/portal/components/form/form-control/form-control.component.html b/web/projects/ui/src/app/routes/portal/components/form/form-control/form-control.component.html index 614aae05c..065d4ff8d 100644 --- a/web/projects/ui/src/app/routes/portal/components/form/form-control/form-control.component.html +++ b/web/projects/ui/src/app/routes/portal/components/form/form-control/form-control.component.html @@ -37,4 +37,4 @@ Accept - + \ No newline at end of file diff --git a/web/projects/ui/src/app/routes/portal/components/form/form-control/form-control.component.ts b/web/projects/ui/src/app/routes/portal/components/form/form-control/form-control.component.ts index 885d2bf4f..4d977d2fc 100644 --- a/web/projects/ui/src/app/routes/portal/components/form/form-control/form-control.component.ts +++ b/web/projects/ui/src/app/routes/portal/components/form/form-control/form-control.component.ts @@ -7,10 +7,10 @@ import { ViewChild, } from '@angular/core' import { takeUntilDestroyed } from '@angular/core/rxjs-interop' -import { CT } from '@start9labs/start-sdk' -import { TuiAlertService, TuiDialogContext } from '@taiga-ui/core' import { AbstractTuiNullableControl } from '@taiga-ui/legacy' import { filter } from 'rxjs' +import { TuiAlertService, TuiDialogContext } from '@taiga-ui/core' +import { IST } from '@start9labs/start-sdk' import { ERRORS } from '../form-group/form-group.component' import { FORM_CONTROL_PROVIDERS } from './form-control.providers' @@ -22,7 +22,7 @@ import { FORM_CONTROL_PROVIDERS } from './form-control.providers' providers: FORM_CONTROL_PROVIDERS, }) export class FormControlComponent< - T extends CT.ValueSpec, + T extends Exclude, V, > extends AbstractTuiNullableControl { @Input({ required: true }) diff --git a/web/projects/ui/src/app/routes/portal/components/form/form-control/form-control.providers.ts b/web/projects/ui/src/app/routes/portal/components/form/form-control/form-control.providers.ts index f065f86cb..62e1ff6aa 100644 --- a/web/projects/ui/src/app/routes/portal/components/form/form-control/form-control.providers.ts +++ b/web/projects/ui/src/app/routes/portal/components/form/form-control/form-control.providers.ts @@ -1,6 +1,6 @@ import { forwardRef, Provider } from '@angular/core' import { TUI_VALIDATION_ERRORS } from '@taiga-ui/kit' -import { CT } from '@start9labs/start-sdk' +import { IST } from '@start9labs/start-sdk' import { FormControlComponent } from './form-control.component' interface ValidatorsPatternError { @@ -12,7 +12,7 @@ export const FORM_CONTROL_PROVIDERS: Provider[] = [ { provide: TUI_VALIDATION_ERRORS, deps: [forwardRef(() => FormControlComponent)], - useFactory: (control: FormControlComponent) => ({ + useFactory: (control: FormControlComponent, string>) => ({ required: 'Required', pattern: ({ requiredPattern }: ValidatorsPatternError) => ('patterns' in control.spec && diff --git a/web/projects/ui/src/app/routes/portal/components/form/form-datetime/form-datetime.component.ts b/web/projects/ui/src/app/routes/portal/components/form/form-datetime/form-datetime.component.ts index e09b22d24..fc3acecd0 100644 --- a/web/projects/ui/src/app/routes/portal/components/form/form-datetime/form-datetime.component.ts +++ b/web/projects/ui/src/app/routes/portal/components/form/form-datetime/form-datetime.component.ts @@ -6,7 +6,7 @@ import { tuiPure, TuiTime, } from '@taiga-ui/cdk' -import { CT } from '@start9labs/start-sdk' +import { IST } from '@start9labs/start-sdk' import { Control } from '../control' @Component({ @@ -14,7 +14,7 @@ import { Control } from '../control' templateUrl: './form-datetime.component.html', }) export class FormDatetimeComponent extends Control< - CT.ValueSpecDatetime, + IST.ValueSpecDatetime, string > { readonly min = TUI_FIRST_DAY diff --git a/web/projects/ui/src/app/routes/portal/components/form/form-group/form-group.component.html b/web/projects/ui/src/app/routes/portal/components/form/form-group/form-group.component.html index ee1a00dbb..c093c0e14 100644 --- a/web/projects/ui/src/app/routes/portal/components/form/form-group/form-group.component.html +++ b/web/projects/ui/src/app/routes/portal/components/form/form-group/form-group.component.html @@ -1,5 +1,5 @@ diff --git a/web/projects/ui/src/app/routes/portal/components/form/form-group/form-group.component.ts b/web/projects/ui/src/app/routes/portal/components/form/form-group/form-group.component.ts index d9d28c8df..456ab1383 100644 --- a/web/projects/ui/src/app/routes/portal/components/form/form-group/form-group.component.ts +++ b/web/projects/ui/src/app/routes/portal/components/form/form-group/form-group.component.ts @@ -4,7 +4,7 @@ import { Input, ViewEncapsulation, } from '@angular/core' -import { CT } from '@start9labs/start-sdk' +import { IST } from '@start9labs/start-sdk' import { FORM_GROUP_PROVIDERS } from './form-group.providers' export const ERRORS = [ @@ -27,7 +27,7 @@ export const ERRORS = [ viewProviders: [FORM_GROUP_PROVIDERS], }) export class FormGroupComponent { - @Input() spec: CT.InputSpec = {} + @Input() spec: IST.InputSpec = {} asIsOrder() { return 0 diff --git a/web/projects/ui/src/app/routes/portal/components/form/form-multiselect/form-multiselect.component.ts b/web/projects/ui/src/app/routes/portal/components/form/form-multiselect/form-multiselect.component.ts index 7134eb1f6..9056e1e0f 100644 --- a/web/projects/ui/src/app/routes/portal/components/form/form-multiselect/form-multiselect.component.ts +++ b/web/projects/ui/src/app/routes/portal/components/form/form-multiselect/form-multiselect.component.ts @@ -1,5 +1,5 @@ import { Component } from '@angular/core' -import { CT } from '@start9labs/start-sdk' +import { IST } from '@start9labs/start-sdk' import { Control } from '../control' import { tuiPure } from '@taiga-ui/cdk' import { invert } from '@start9labs/shared' @@ -9,7 +9,7 @@ import { invert } from '@start9labs/shared' templateUrl: './form-multiselect.component.html', }) export class FormMultiselectComponent extends Control< - CT.ValueSpecMultiselect, + IST.ValueSpecMultiselect, readonly string[] > { private readonly inverted = invert(this.spec.values) diff --git a/web/projects/ui/src/app/routes/portal/components/form/form-number/form-number.component.ts b/web/projects/ui/src/app/routes/portal/components/form/form-number/form-number.component.ts index a930b1614..b07858207 100644 --- a/web/projects/ui/src/app/routes/portal/components/form/form-number/form-number.component.ts +++ b/web/projects/ui/src/app/routes/portal/components/form/form-number/form-number.component.ts @@ -1,11 +1,11 @@ import { Component } from '@angular/core' -import { CT } from '@start9labs/start-sdk' +import { IST } from '@start9labs/start-sdk' import { Control } from '../control' @Component({ selector: 'form-number', templateUrl: './form-number.component.html', }) -export class FormNumberComponent extends Control { +export class FormNumberComponent extends Control { protected readonly Infinity = Infinity } diff --git a/web/projects/ui/src/app/routes/portal/components/form/form-object/form-object.component.ts b/web/projects/ui/src/app/routes/portal/components/form/form-object/form-object.component.ts index d3f5a63cf..17c72223d 100644 --- a/web/projects/ui/src/app/routes/portal/components/form/form-object/form-object.component.ts +++ b/web/projects/ui/src/app/routes/portal/components/form/form-object/form-object.component.ts @@ -7,7 +7,7 @@ import { Output, } from '@angular/core' import { ControlContainer } from '@angular/forms' -import { CT } from '@start9labs/start-sdk' +import { IST } from '@start9labs/start-sdk' @Component({ selector: 'form-object', @@ -17,7 +17,7 @@ import { CT } from '@start9labs/start-sdk' }) export class FormObjectComponent { @Input({ required: true }) - spec!: CT.ValueSpecObject + spec!: IST.ValueSpecObject @Input() open = false diff --git a/web/projects/ui/src/app/routes/portal/components/form/form-select/form-select.component.html b/web/projects/ui/src/app/routes/portal/components/form/form-select/form-select.component.html index fe2b561c7..9149e8844 100644 --- a/web/projects/ui/src/app/routes/portal/components/form/form-select/form-select.component.html +++ b/web/projects/ui/src/app/routes/portal/components/form/form-select/form-select.component.html @@ -2,13 +2,12 @@ [tuiHintContent]="spec | hint" [disabled]="disabled" [readOnly]="readOnly" - [tuiTextfieldCleaner]="!spec.required" + [tuiTextfieldCleaner]="false" [pseudoInvalid]="invalid" [(ngModel)]="selected" (focusedChange)="onFocus($event)" > - {{ spec.name }} - * + {{ spec.name }}*