├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── app.yaml ├── decrypt.go ├── encrypt.go ├── generate.go ├── go.mod ├── go.sum ├── main.go ├── package.json ├── pnpm-lock.yaml ├── src ├── bootstrap-custom.scss ├── index.html ├── main.js └── public │ └── favicon.ico └── vite.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # Dependency directories 15 | /vendor/ 16 | 17 | # (P)NPM 18 | /node_modules/ 19 | 20 | # Output 21 | /dist/ 22 | /static/ 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Marin Basic 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHOHY: import build-wasm npm-install build clean zip deploy-gcp help 2 | 3 | go-sources = go.mod go.sum *.go 4 | web-sources = package.json pnpm-lock.yaml vite.config.js src/* 5 | 6 | GOROOT:=$(shell go env GOROOT) 7 | 8 | # The below code utilizes make's file change tracking 9 | # (i.e. not rebuilding targets unnecessarily) 10 | # while still allowing human-readable target names. 11 | # 12 | # First we set a variable named foo that holds 13 | # all the actual output filenames. 14 | # Then we use $(foo) anywhere we need 15 | # to reference that target as a prerequisite. 16 | # Finally we create a target foo which 17 | # has $(foo) as a prerequisite. 18 | 19 | # make import: copy the required wasm_exec.js file from the Go toolchain (output in vendor/) 20 | 21 | # Variables 22 | IMPORT = vendor/wasm_exec.js 23 | 24 | GO_VERSION := $(shell go env GOVERSION | sed 's/^go//') 25 | GO_MAJOR := $(shell echo $(GO_VERSION) | cut -d. -f1) 26 | GO_MINOR := $(shell echo $(GO_VERSION) | cut -d. -f2) 27 | 28 | ifeq ($(shell [ $(GO_MAJOR) -eq 1 -a $(GO_MINOR) -lt 24 ] && echo yes),yes) 29 | WASM_EXEC_PATH := $(GOROOT)/misc/wasm/wasm_exec.js 30 | else 31 | WASM_EXEC_PATH := $(GOROOT)/lib/wasm/wasm_exec.js 32 | endif 33 | 34 | # Rule to copy wasm_exec.js into vendor 35 | $(IMPORT): $(WASM_EXEC_PATH) 36 | mkdir -p vendor 37 | cp "$(WASM_EXEC_PATH)" vendor/ 38 | 39 | # import target depends on the file 40 | import: $(IMPORT) 41 | 42 | # make build-wasm: build the WebAssembly module (output in vendor/) 43 | build-wasm = vendor/age.wasm 44 | 45 | $(build-wasm): $(go-sources) 46 | mkdir -p vendor 47 | GOOS=js GOARCH=wasm go build -mod=mod -o vendor/age.wasm 48 | 49 | build-wasm: $(build-wasm) 50 | 51 | # make npm-install: installs tools and dependencies from npm (output in node_modules/) 52 | # 53 | # This uses an empty target file to track when it needs to be re-ran 54 | npm-install = node_modules/.make-sentinel 55 | 56 | $(npm-install): package.json pnpm-lock.yaml 57 | pnpm install 58 | touch $(npm-install) 59 | 60 | npm-install: $(npm-install) 61 | 62 | # make build: build the complete static website (output in dist/) 63 | # 64 | # If dist/ doesn't exist $(build) will evaluate to 'dist/*' 65 | # but that's fine here because it means the target will run. 66 | build = dist/* 67 | 68 | $(build): $(import) $(build-wasm) $(npm-install) $(web-sources) 69 | pnpm run build 70 | 71 | build: $(build) 72 | 73 | # make clean: delete all existing build files (deletes vendor/* dist/*) 74 | clean: 75 | rm -rf vendor/ dist/ 76 | 77 | # make zip: create a zip archive with the output static website (outputs agewasm.zip) 78 | zip = agewasm.zip 79 | $(zip): $(build) 80 | cd dist && zip -r ../$(zip) . 81 | zip: $(zip) 82 | 83 | # make deploy-gcp: deploys to google cloud 84 | deploy-gcp: build 85 | gcloud app deploy 86 | 87 | # make help: print this help page 88 | help: 89 | @echo "agewasm Makefile" 90 | @echo "Usage: make " 91 | @echo "" 92 | @echo "Available targets:" 93 | @grep -P '^# make [[:alnum:]_-]+:' Makefile | sed -e 's/^# / /' 94 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Age WASM [app](https://agewasm.marin-basic.com) 2 | 3 | A simple and secure online client-side Age key generator, encryption and decryption tool built using wasm 4 | 5 | View online [here](https://agewasm.marin-basic.com) 6 | 7 | ## Building 8 | 9 | You will need: 10 | 11 | - [Go](https://go.dev/) and `wasm_exec.js` (included with Go) 12 | - [PNPM](https://pnpm.io/) 13 | 14 | Use the provided `Makefile` and execute `make build`. 15 | 16 | See `make help` for descriptions of other targets. 17 | 18 | The final static website will be placed in `dist/` 19 | 20 | ## Usage 21 | 22 | Put the `dist` folder on your favorite web server server or open `index.html`. 23 | There is no binary to run :) 24 | 25 | --- 26 | 27 | **Prebuilt files?** 28 | 29 | You can grab a generated zip file on the [release page](https://github.com/MarinX/agewasm/releases). 30 | 31 | --- 32 | 33 | ## Developement 34 | 35 | You can run a developement Vite server with live-reload using `pnpm run dev` (this will not auto-rebuild the WASM). 36 | 37 | Please format the source files before commiting with `pnpm run format` 38 | 39 | ## License 40 | 41 | This project is licensed under the MIT License. See the LICENSE file for the full license text. 42 | -------------------------------------------------------------------------------- /app.yaml: -------------------------------------------------------------------------------- 1 | runtime: python27 2 | api_version: 1 3 | threadsafe: true 4 | 5 | handlers: 6 | - url: / 7 | static_files: dist/index.html 8 | upload: dist/index.html 9 | 10 | - url: /(.*) 11 | static_files: dist/\1 12 | upload: dist/(.*) 13 | -------------------------------------------------------------------------------- /decrypt.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "fmt" 7 | "io" 8 | "strings" 9 | "syscall/js" 10 | 11 | "filippo.io/age" 12 | "filippo.io/age/armor" 13 | ) 14 | 15 | // Decrypt decrypts a Armored string into a string result 16 | func Decrypt(this js.Value, args []js.Value) interface{} { 17 | output := make(map[string]interface{}) 18 | if len(args) != 2 { 19 | output["error"] = "invalid arguments. expected: identities, input" 20 | return output 21 | } 22 | var identities = args[0].String() 23 | var input = args[1].String() 24 | ids, err := age.ParseIdentities(strings.NewReader(identities)) 25 | if err != nil { 26 | output["error"] = err.Error() 27 | return output 28 | } 29 | buff := bytes.NewBuffer(nil) 30 | err = decrypt(ids, strings.NewReader(input), buff) 31 | if err != nil { 32 | output["error"] = err.Error() 33 | return output 34 | } 35 | output["output"] = buff.String() 36 | return output 37 | } 38 | 39 | // DecryptBinary decrypts binary data (Uint8Array) into a Uint8Array result 40 | func DecryptBinary(this js.Value, args []js.Value) interface{} { 41 | if len(args) != 2 { 42 | return fmt.Errorf("invalid arguments. expected: identities, input") 43 | } 44 | var identities = args[0].String() 45 | 46 | ids, err := age.ParseIdentities(strings.NewReader(identities)) 47 | if err != nil { 48 | return err.Error() 49 | } 50 | 51 | input := make([]byte, args[1].Length()) 52 | js.CopyBytesToGo(input, args[1]) 53 | 54 | buff := bytes.NewBuffer(nil) 55 | err = decrypt(ids, bytes.NewReader(input), buff) 56 | if err != nil { 57 | return err.Error() 58 | } 59 | 60 | result := js.Global().Get("Uint8Array").New(buff.Len()) 61 | js.CopyBytesToJS(result, buff.Bytes()) 62 | return result 63 | } 64 | 65 | // decrypt internal helper 66 | func decrypt(keys []age.Identity, in io.Reader, out io.Writer) error { 67 | rr := bufio.NewReader(in) 68 | if start, _ := rr.Peek(len(armor.Header)); string(start) == armor.Header { 69 | in = armor.NewReader(rr) 70 | } else { 71 | in = rr 72 | } 73 | 74 | r, err := age.Decrypt(in, keys...) 75 | if err != nil { 76 | return err 77 | } 78 | if _, err := io.Copy(out, r); err != nil { 79 | return err 80 | } 81 | return nil 82 | } 83 | -------------------------------------------------------------------------------- /encrypt.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io" 7 | "strings" 8 | "syscall/js" 9 | 10 | "filippo.io/age" 11 | "filippo.io/age/armor" 12 | ) 13 | 14 | func Encrypt(this js.Value, args []js.Value) interface{} { 15 | output := make(map[string]interface{}) 16 | if len(args) != 2 { 17 | output["error"] = "invalid arguments. expected: recipients, input" 18 | return output 19 | } 20 | var recipients = args[0].String() 21 | var input = args[1].String() 22 | buff := bytes.NewBuffer(nil) 23 | ids, err := age.ParseRecipients(strings.NewReader(recipients)) 24 | if err != nil { 25 | output["error"] = err.Error() 26 | return output 27 | } 28 | err = encrypt(ids, strings.NewReader(input), buff, true) 29 | if err != nil { 30 | output["error"] = err.Error() 31 | return output 32 | } 33 | output["output"] = buff.String() 34 | return output 35 | } 36 | 37 | func EncryptBinary(this js.Value, args []js.Value) interface{} { 38 | if len(args) != 2 { 39 | return fmt.Errorf("invalid arguments. expected: recipients, input") 40 | } 41 | 42 | var recipients = args[0].String() 43 | ids, err := age.ParseRecipients(strings.NewReader(recipients)) 44 | if err != nil { 45 | return err.Error() 46 | } 47 | 48 | input := make([]byte, args[1].Length()) 49 | js.CopyBytesToGo(input, args[1]) 50 | 51 | buff := bytes.NewBuffer(nil) 52 | err = encrypt(ids, bytes.NewReader(input), buff, false) 53 | if err != nil { 54 | return err.Error() 55 | } 56 | 57 | result := js.Global().Get("Uint8Array").New(buff.Len()) 58 | js.CopyBytesToJS(result, buff.Bytes()) 59 | return result 60 | } 61 | 62 | // encrypt internal helper 63 | func encrypt(recipients []age.Recipient, in io.Reader, out io.Writer, withArmor bool) error { 64 | var a io.WriteCloser 65 | if withArmor { 66 | a = armor.NewWriter(out) 67 | out = a 68 | } 69 | w, err := age.Encrypt(out, recipients...) 70 | if err != nil { 71 | return err 72 | } 73 | if _, err := io.Copy(w, in); err != nil { 74 | return err 75 | } 76 | if err := w.Close(); err != nil { 77 | return err 78 | } 79 | if a != nil { 80 | if err := a.Close(); err != nil { 81 | return err 82 | } 83 | } 84 | return nil 85 | } 86 | -------------------------------------------------------------------------------- /generate.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "syscall/js" 5 | 6 | "filippo.io/age" 7 | ) 8 | 9 | // GenerateX25519Identity randomly generates a new X25519Identity. 10 | func GenerateX25519Identity(this js.Value, args []js.Value) interface{} { 11 | output := make(map[string]interface{}) 12 | identity, err := age.GenerateX25519Identity() 13 | if err != nil { 14 | output["error"] = err.Error() 15 | return output 16 | } 17 | output["privateKey"] = identity.String() 18 | output["publicKey"] = identity.Recipient().String() 19 | return output 20 | } 21 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/marinx/agewasm 2 | 3 | go 1.18 4 | 5 | require filippo.io/age v1.0.0 6 | 7 | require ( 8 | golang.org/x/crypto v0.3.0 // indirect 9 | golang.org/x/sys v0.2.0 // indirect 10 | ) 11 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | filippo.io/age v1.0.0 h1:V6q14n0mqYU3qKFkZ6oOaF9oXneOviS3ubXsSVBRSzc= 2 | filippo.io/age v1.0.0/go.mod h1:PaX+Si/Sd5G8LgfCwldsSba3H1DDQZhIhFGkhbHaBq8= 3 | golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A= 4 | golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= 5 | golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= 6 | golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 7 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "syscall/js" 4 | 5 | func main() { 6 | done := make(chan struct{}) 7 | 8 | js.Global().Set("generateX25519Identity", js.FuncOf(GenerateX25519Identity)) 9 | js.Global().Set("encrypt", js.FuncOf(Encrypt)) 10 | js.Global().Set("encryptBinary", js.FuncOf(EncryptBinary)) 11 | js.Global().Set("decrypt", js.FuncOf(Decrypt)) 12 | js.Global().Set("decryptBinary", js.FuncOf(DecryptBinary)) 13 | 14 | <-done 15 | } 16 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "agewasm", 3 | "version": "1.1.0", 4 | "description": "A simple and secure online client-side Age key generator, encryption and decryption tool built using wasm.", 5 | "scripts": { 6 | "dev": "vite", 7 | "build": "vite build --emptyOutDir", 8 | "preview": "vite preview", 9 | "format": "prettier --write src/*.html src/*.js src/*.scss" 10 | }, 11 | "keywords": [ 12 | "encryption", 13 | "age-encryption" 14 | ], 15 | "author": "Marin Basic (marin-basic.com)", 16 | "license": "MIT", 17 | "dependencies": { 18 | "@popperjs/core": "^2.11.8", 19 | "bootstrap": "^5.3.3" 20 | }, 21 | "devDependencies": { 22 | "prettier": "^3.5.0", 23 | "sass-embedded": "^1.83.4", 24 | "vite": "^6.1.0" 25 | } 26 | } -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '9.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | importers: 8 | 9 | .: 10 | dependencies: 11 | '@popperjs/core': 12 | specifier: ^2.11.8 13 | version: 2.11.8 14 | bootstrap: 15 | specifier: ^5.3.3 16 | version: 5.3.3(@popperjs/core@2.11.8) 17 | devDependencies: 18 | prettier: 19 | specifier: ^3.5.0 20 | version: 3.5.0 21 | sass-embedded: 22 | specifier: ^1.83.4 23 | version: 1.83.4 24 | vite: 25 | specifier: ^6.1.0 26 | version: 6.1.0(sass-embedded@1.83.4)(sass@1.84.0) 27 | 28 | packages: 29 | 30 | '@bufbuild/protobuf@2.2.3': 31 | resolution: {integrity: sha512-tFQoXHJdkEOSwj5tRIZSPNUuXK3RaR7T1nUrPgbYX1pUbvqqaaZAsfo+NXBPsz5rZMSKVFrgK1WL8Q/MSLvprg==} 32 | 33 | '@esbuild/aix-ppc64@0.24.2': 34 | resolution: {integrity: sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==} 35 | engines: {node: '>=18'} 36 | cpu: [ppc64] 37 | os: [aix] 38 | 39 | '@esbuild/android-arm64@0.24.2': 40 | resolution: {integrity: sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==} 41 | engines: {node: '>=18'} 42 | cpu: [arm64] 43 | os: [android] 44 | 45 | '@esbuild/android-arm@0.24.2': 46 | resolution: {integrity: sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==} 47 | engines: {node: '>=18'} 48 | cpu: [arm] 49 | os: [android] 50 | 51 | '@esbuild/android-x64@0.24.2': 52 | resolution: {integrity: sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==} 53 | engines: {node: '>=18'} 54 | cpu: [x64] 55 | os: [android] 56 | 57 | '@esbuild/darwin-arm64@0.24.2': 58 | resolution: {integrity: sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==} 59 | engines: {node: '>=18'} 60 | cpu: [arm64] 61 | os: [darwin] 62 | 63 | '@esbuild/darwin-x64@0.24.2': 64 | resolution: {integrity: sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==} 65 | engines: {node: '>=18'} 66 | cpu: [x64] 67 | os: [darwin] 68 | 69 | '@esbuild/freebsd-arm64@0.24.2': 70 | resolution: {integrity: sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==} 71 | engines: {node: '>=18'} 72 | cpu: [arm64] 73 | os: [freebsd] 74 | 75 | '@esbuild/freebsd-x64@0.24.2': 76 | resolution: {integrity: sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==} 77 | engines: {node: '>=18'} 78 | cpu: [x64] 79 | os: [freebsd] 80 | 81 | '@esbuild/linux-arm64@0.24.2': 82 | resolution: {integrity: sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==} 83 | engines: {node: '>=18'} 84 | cpu: [arm64] 85 | os: [linux] 86 | 87 | '@esbuild/linux-arm@0.24.2': 88 | resolution: {integrity: sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==} 89 | engines: {node: '>=18'} 90 | cpu: [arm] 91 | os: [linux] 92 | 93 | '@esbuild/linux-ia32@0.24.2': 94 | resolution: {integrity: sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==} 95 | engines: {node: '>=18'} 96 | cpu: [ia32] 97 | os: [linux] 98 | 99 | '@esbuild/linux-loong64@0.24.2': 100 | resolution: {integrity: sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==} 101 | engines: {node: '>=18'} 102 | cpu: [loong64] 103 | os: [linux] 104 | 105 | '@esbuild/linux-mips64el@0.24.2': 106 | resolution: {integrity: sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==} 107 | engines: {node: '>=18'} 108 | cpu: [mips64el] 109 | os: [linux] 110 | 111 | '@esbuild/linux-ppc64@0.24.2': 112 | resolution: {integrity: sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==} 113 | engines: {node: '>=18'} 114 | cpu: [ppc64] 115 | os: [linux] 116 | 117 | '@esbuild/linux-riscv64@0.24.2': 118 | resolution: {integrity: sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==} 119 | engines: {node: '>=18'} 120 | cpu: [riscv64] 121 | os: [linux] 122 | 123 | '@esbuild/linux-s390x@0.24.2': 124 | resolution: {integrity: sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==} 125 | engines: {node: '>=18'} 126 | cpu: [s390x] 127 | os: [linux] 128 | 129 | '@esbuild/linux-x64@0.24.2': 130 | resolution: {integrity: sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==} 131 | engines: {node: '>=18'} 132 | cpu: [x64] 133 | os: [linux] 134 | 135 | '@esbuild/netbsd-arm64@0.24.2': 136 | resolution: {integrity: sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==} 137 | engines: {node: '>=18'} 138 | cpu: [arm64] 139 | os: [netbsd] 140 | 141 | '@esbuild/netbsd-x64@0.24.2': 142 | resolution: {integrity: sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==} 143 | engines: {node: '>=18'} 144 | cpu: [x64] 145 | os: [netbsd] 146 | 147 | '@esbuild/openbsd-arm64@0.24.2': 148 | resolution: {integrity: sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==} 149 | engines: {node: '>=18'} 150 | cpu: [arm64] 151 | os: [openbsd] 152 | 153 | '@esbuild/openbsd-x64@0.24.2': 154 | resolution: {integrity: sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==} 155 | engines: {node: '>=18'} 156 | cpu: [x64] 157 | os: [openbsd] 158 | 159 | '@esbuild/sunos-x64@0.24.2': 160 | resolution: {integrity: sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==} 161 | engines: {node: '>=18'} 162 | cpu: [x64] 163 | os: [sunos] 164 | 165 | '@esbuild/win32-arm64@0.24.2': 166 | resolution: {integrity: sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==} 167 | engines: {node: '>=18'} 168 | cpu: [arm64] 169 | os: [win32] 170 | 171 | '@esbuild/win32-ia32@0.24.2': 172 | resolution: {integrity: sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==} 173 | engines: {node: '>=18'} 174 | cpu: [ia32] 175 | os: [win32] 176 | 177 | '@esbuild/win32-x64@0.24.2': 178 | resolution: {integrity: sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==} 179 | engines: {node: '>=18'} 180 | cpu: [x64] 181 | os: [win32] 182 | 183 | '@parcel/watcher-android-arm64@2.5.1': 184 | resolution: {integrity: sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==} 185 | engines: {node: '>= 10.0.0'} 186 | cpu: [arm64] 187 | os: [android] 188 | 189 | '@parcel/watcher-darwin-arm64@2.5.1': 190 | resolution: {integrity: sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==} 191 | engines: {node: '>= 10.0.0'} 192 | cpu: [arm64] 193 | os: [darwin] 194 | 195 | '@parcel/watcher-darwin-x64@2.5.1': 196 | resolution: {integrity: sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==} 197 | engines: {node: '>= 10.0.0'} 198 | cpu: [x64] 199 | os: [darwin] 200 | 201 | '@parcel/watcher-freebsd-x64@2.5.1': 202 | resolution: {integrity: sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==} 203 | engines: {node: '>= 10.0.0'} 204 | cpu: [x64] 205 | os: [freebsd] 206 | 207 | '@parcel/watcher-linux-arm-glibc@2.5.1': 208 | resolution: {integrity: sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==} 209 | engines: {node: '>= 10.0.0'} 210 | cpu: [arm] 211 | os: [linux] 212 | 213 | '@parcel/watcher-linux-arm-musl@2.5.1': 214 | resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==} 215 | engines: {node: '>= 10.0.0'} 216 | cpu: [arm] 217 | os: [linux] 218 | 219 | '@parcel/watcher-linux-arm64-glibc@2.5.1': 220 | resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==} 221 | engines: {node: '>= 10.0.0'} 222 | cpu: [arm64] 223 | os: [linux] 224 | 225 | '@parcel/watcher-linux-arm64-musl@2.5.1': 226 | resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==} 227 | engines: {node: '>= 10.0.0'} 228 | cpu: [arm64] 229 | os: [linux] 230 | 231 | '@parcel/watcher-linux-x64-glibc@2.5.1': 232 | resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==} 233 | engines: {node: '>= 10.0.0'} 234 | cpu: [x64] 235 | os: [linux] 236 | 237 | '@parcel/watcher-linux-x64-musl@2.5.1': 238 | resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==} 239 | engines: {node: '>= 10.0.0'} 240 | cpu: [x64] 241 | os: [linux] 242 | 243 | '@parcel/watcher-win32-arm64@2.5.1': 244 | resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==} 245 | engines: {node: '>= 10.0.0'} 246 | cpu: [arm64] 247 | os: [win32] 248 | 249 | '@parcel/watcher-win32-ia32@2.5.1': 250 | resolution: {integrity: sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==} 251 | engines: {node: '>= 10.0.0'} 252 | cpu: [ia32] 253 | os: [win32] 254 | 255 | '@parcel/watcher-win32-x64@2.5.1': 256 | resolution: {integrity: sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==} 257 | engines: {node: '>= 10.0.0'} 258 | cpu: [x64] 259 | os: [win32] 260 | 261 | '@parcel/watcher@2.5.1': 262 | resolution: {integrity: sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==} 263 | engines: {node: '>= 10.0.0'} 264 | 265 | '@popperjs/core@2.11.8': 266 | resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} 267 | 268 | '@rollup/rollup-android-arm-eabi@4.34.6': 269 | resolution: {integrity: sha512-+GcCXtOQoWuC7hhX1P00LqjjIiS/iOouHXhMdiDSnq/1DGTox4SpUvO52Xm+div6+106r+TcvOeo/cxvyEyTgg==} 270 | cpu: [arm] 271 | os: [android] 272 | 273 | '@rollup/rollup-android-arm64@4.34.6': 274 | resolution: {integrity: sha512-E8+2qCIjciYUnCa1AiVF1BkRgqIGW9KzJeesQqVfyRITGQN+dFuoivO0hnro1DjT74wXLRZ7QF8MIbz+luGaJA==} 275 | cpu: [arm64] 276 | os: [android] 277 | 278 | '@rollup/rollup-darwin-arm64@4.34.6': 279 | resolution: {integrity: sha512-z9Ib+OzqN3DZEjX7PDQMHEhtF+t6Mi2z/ueChQPLS/qUMKY7Ybn5A2ggFoKRNRh1q1T03YTQfBTQCJZiepESAg==} 280 | cpu: [arm64] 281 | os: [darwin] 282 | 283 | '@rollup/rollup-darwin-x64@4.34.6': 284 | resolution: {integrity: sha512-PShKVY4u0FDAR7jskyFIYVyHEPCPnIQY8s5OcXkdU8mz3Y7eXDJPdyM/ZWjkYdR2m0izD9HHWA8sGcXn+Qrsyg==} 285 | cpu: [x64] 286 | os: [darwin] 287 | 288 | '@rollup/rollup-freebsd-arm64@4.34.6': 289 | resolution: {integrity: sha512-YSwyOqlDAdKqs0iKuqvRHLN4SrD2TiswfoLfvYXseKbL47ht1grQpq46MSiQAx6rQEN8o8URtpXARCpqabqxGQ==} 290 | cpu: [arm64] 291 | os: [freebsd] 292 | 293 | '@rollup/rollup-freebsd-x64@4.34.6': 294 | resolution: {integrity: sha512-HEP4CgPAY1RxXwwL5sPFv6BBM3tVeLnshF03HMhJYCNc6kvSqBgTMmsEjb72RkZBAWIqiPUyF1JpEBv5XT9wKQ==} 295 | cpu: [x64] 296 | os: [freebsd] 297 | 298 | '@rollup/rollup-linux-arm-gnueabihf@4.34.6': 299 | resolution: {integrity: sha512-88fSzjC5xeH9S2Vg3rPgXJULkHcLYMkh8faix8DX4h4TIAL65ekwuQMA/g2CXq8W+NJC43V6fUpYZNjaX3+IIg==} 300 | cpu: [arm] 301 | os: [linux] 302 | 303 | '@rollup/rollup-linux-arm-musleabihf@4.34.6': 304 | resolution: {integrity: sha512-wM4ztnutBqYFyvNeR7Av+reWI/enK9tDOTKNF+6Kk2Q96k9bwhDDOlnCUNRPvromlVXo04riSliMBs/Z7RteEg==} 305 | cpu: [arm] 306 | os: [linux] 307 | 308 | '@rollup/rollup-linux-arm64-gnu@4.34.6': 309 | resolution: {integrity: sha512-9RyprECbRa9zEjXLtvvshhw4CMrRa3K+0wcp3KME0zmBe1ILmvcVHnypZ/aIDXpRyfhSYSuN4EPdCCj5Du8FIA==} 310 | cpu: [arm64] 311 | os: [linux] 312 | 313 | '@rollup/rollup-linux-arm64-musl@4.34.6': 314 | resolution: {integrity: sha512-qTmklhCTyaJSB05S+iSovfo++EwnIEZxHkzv5dep4qoszUMX5Ca4WM4zAVUMbfdviLgCSQOu5oU8YoGk1s6M9Q==} 315 | cpu: [arm64] 316 | os: [linux] 317 | 318 | '@rollup/rollup-linux-loongarch64-gnu@4.34.6': 319 | resolution: {integrity: sha512-4Qmkaps9yqmpjY5pvpkfOerYgKNUGzQpFxV6rnS7c/JfYbDSU0y6WpbbredB5cCpLFGJEqYX40WUmxMkwhWCjw==} 320 | cpu: [loong64] 321 | os: [linux] 322 | 323 | '@rollup/rollup-linux-powerpc64le-gnu@4.34.6': 324 | resolution: {integrity: sha512-Zsrtux3PuaxuBTX/zHdLaFmcofWGzaWW1scwLU3ZbW/X+hSsFbz9wDIp6XvnT7pzYRl9MezWqEqKy7ssmDEnuQ==} 325 | cpu: [ppc64] 326 | os: [linux] 327 | 328 | '@rollup/rollup-linux-riscv64-gnu@4.34.6': 329 | resolution: {integrity: sha512-aK+Zp+CRM55iPrlyKiU3/zyhgzWBxLVrw2mwiQSYJRobCURb781+XstzvA8Gkjg/hbdQFuDw44aUOxVQFycrAg==} 330 | cpu: [riscv64] 331 | os: [linux] 332 | 333 | '@rollup/rollup-linux-s390x-gnu@4.34.6': 334 | resolution: {integrity: sha512-WoKLVrY9ogmaYPXwTH326+ErlCIgMmsoRSx6bO+l68YgJnlOXhygDYSZe/qbUJCSiCiZAQ+tKm88NcWuUXqOzw==} 335 | cpu: [s390x] 336 | os: [linux] 337 | 338 | '@rollup/rollup-linux-x64-gnu@4.34.6': 339 | resolution: {integrity: sha512-Sht4aFvmA4ToHd2vFzwMFaQCiYm2lDFho5rPcvPBT5pCdC+GwHG6CMch4GQfmWTQ1SwRKS0dhDYb54khSrjDWw==} 340 | cpu: [x64] 341 | os: [linux] 342 | 343 | '@rollup/rollup-linux-x64-musl@4.34.6': 344 | resolution: {integrity: sha512-zmmpOQh8vXc2QITsnCiODCDGXFC8LMi64+/oPpPx5qz3pqv0s6x46ps4xoycfUiVZps5PFn1gksZzo4RGTKT+A==} 345 | cpu: [x64] 346 | os: [linux] 347 | 348 | '@rollup/rollup-win32-arm64-msvc@4.34.6': 349 | resolution: {integrity: sha512-3/q1qUsO/tLqGBaD4uXsB6coVGB3usxw3qyeVb59aArCgedSF66MPdgRStUd7vbZOsko/CgVaY5fo2vkvPLWiA==} 350 | cpu: [arm64] 351 | os: [win32] 352 | 353 | '@rollup/rollup-win32-ia32-msvc@4.34.6': 354 | resolution: {integrity: sha512-oLHxuyywc6efdKVTxvc0135zPrRdtYVjtVD5GUm55I3ODxhU/PwkQFD97z16Xzxa1Fz0AEe4W/2hzRtd+IfpOA==} 355 | cpu: [ia32] 356 | os: [win32] 357 | 358 | '@rollup/rollup-win32-x64-msvc@4.34.6': 359 | resolution: {integrity: sha512-0PVwmgzZ8+TZ9oGBmdZoQVXflbvuwzN/HRclujpl4N/q3i+y0lqLw8n1bXA8ru3sApDjlmONaNAuYr38y1Kr9w==} 360 | cpu: [x64] 361 | os: [win32] 362 | 363 | '@types/estree@1.0.6': 364 | resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} 365 | 366 | bootstrap@5.3.3: 367 | resolution: {integrity: sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==} 368 | peerDependencies: 369 | '@popperjs/core': ^2.11.8 370 | 371 | braces@3.0.3: 372 | resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} 373 | engines: {node: '>=8'} 374 | 375 | buffer-builder@0.2.0: 376 | resolution: {integrity: sha512-7VPMEPuYznPSoR21NE1zvd2Xna6c/CloiZCfcMXR1Jny6PjX0N4Nsa38zcBFo/FMK+BlA+FLKbJCQ0i2yxp+Xg==} 377 | 378 | chokidar@4.0.3: 379 | resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} 380 | engines: {node: '>= 14.16.0'} 381 | 382 | colorjs.io@0.5.2: 383 | resolution: {integrity: sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw==} 384 | 385 | detect-libc@1.0.3: 386 | resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==} 387 | engines: {node: '>=0.10'} 388 | hasBin: true 389 | 390 | esbuild@0.24.2: 391 | resolution: {integrity: sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==} 392 | engines: {node: '>=18'} 393 | hasBin: true 394 | 395 | fill-range@7.1.1: 396 | resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} 397 | engines: {node: '>=8'} 398 | 399 | fsevents@2.3.3: 400 | resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} 401 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 402 | os: [darwin] 403 | 404 | has-flag@4.0.0: 405 | resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} 406 | engines: {node: '>=8'} 407 | 408 | immutable@5.0.3: 409 | resolution: {integrity: sha512-P8IdPQHq3lA1xVeBRi5VPqUm5HDgKnx0Ru51wZz5mjxHr5n3RWhjIpOFU7ybkUxfB+5IToy+OLaHYDBIWsv+uw==} 410 | 411 | is-extglob@2.1.1: 412 | resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} 413 | engines: {node: '>=0.10.0'} 414 | 415 | is-glob@4.0.3: 416 | resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} 417 | engines: {node: '>=0.10.0'} 418 | 419 | is-number@7.0.0: 420 | resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} 421 | engines: {node: '>=0.12.0'} 422 | 423 | micromatch@4.0.8: 424 | resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} 425 | engines: {node: '>=8.6'} 426 | 427 | nanoid@3.3.8: 428 | resolution: {integrity: sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==} 429 | engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} 430 | hasBin: true 431 | 432 | node-addon-api@7.1.1: 433 | resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} 434 | 435 | picocolors@1.1.1: 436 | resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} 437 | 438 | picomatch@2.3.1: 439 | resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} 440 | engines: {node: '>=8.6'} 441 | 442 | postcss@8.5.1: 443 | resolution: {integrity: sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==} 444 | engines: {node: ^10 || ^12 || >=14} 445 | 446 | prettier@3.5.0: 447 | resolution: {integrity: sha512-quyMrVt6svPS7CjQ9gKb3GLEX/rl3BCL2oa/QkNcXv4YNVBC9olt3s+H7ukto06q7B1Qz46PbrKLO34PR6vXcA==} 448 | engines: {node: '>=14'} 449 | hasBin: true 450 | 451 | readdirp@4.1.1: 452 | resolution: {integrity: sha512-h80JrZu/MHUZCyHu5ciuoI0+WxsCxzxJTILn6Fs8rxSnFPh+UVHYfeIxK1nVGugMqkfC4vJcBOYbkfkwYK0+gw==} 453 | engines: {node: '>= 14.18.0'} 454 | 455 | rollup@4.34.6: 456 | resolution: {integrity: sha512-wc2cBWqJgkU3Iz5oztRkQbfVkbxoz5EhnCGOrnJvnLnQ7O0WhQUYyv18qQI79O8L7DdHrrlJNeCHd4VGpnaXKQ==} 457 | engines: {node: '>=18.0.0', npm: '>=8.0.0'} 458 | hasBin: true 459 | 460 | rxjs@7.8.1: 461 | resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} 462 | 463 | sass-embedded-android-arm64@1.83.4: 464 | resolution: {integrity: sha512-tgX4FzmbVqnQmD67ZxQDvI+qFNABrboOQgwsG05E5bA/US42zGajW9AxpECJYiMXVOHmg+d81ICbjb0fsVHskw==} 465 | engines: {node: '>=14.0.0'} 466 | cpu: [arm64] 467 | os: [android] 468 | 469 | sass-embedded-android-arm@1.83.4: 470 | resolution: {integrity: sha512-9Z4pJAOgEkXa3VDY/o+U6l5XvV0mZTJcSl0l/mSPHihjAHSpLYnOW6+KOWeM8dxqrsqTYcd6COzhanI/a++5Gw==} 471 | engines: {node: '>=14.0.0'} 472 | cpu: [arm] 473 | os: [android] 474 | 475 | sass-embedded-android-ia32@1.83.4: 476 | resolution: {integrity: sha512-RsFOziFqPcfZXdFRULC4Ayzy9aK6R6FwQ411broCjlOBX+b0gurjRadkue3cfUEUR5mmy0KeCbp7zVKPLTK+5Q==} 477 | engines: {node: '>=14.0.0'} 478 | cpu: [ia32] 479 | os: [android] 480 | 481 | sass-embedded-android-riscv64@1.83.4: 482 | resolution: {integrity: sha512-EHwh0nmQarBBrMRU928eTZkFGx19k/XW2YwbPR4gBVdWLkbTgCA5aGe8hTE6/1zStyx++3nDGvTZ78+b/VvvLg==} 483 | engines: {node: '>=14.0.0'} 484 | cpu: [riscv64] 485 | os: [android] 486 | 487 | sass-embedded-android-x64@1.83.4: 488 | resolution: {integrity: sha512-0PgQNuPWYy1jEOEPDVsV89KfqOsMLIp9CSbjBY7jRcwRhyVAcigqrUG6bDeNtojHUYKA1kU+Eh/85WxOHUOgBw==} 489 | engines: {node: '>=14.0.0'} 490 | cpu: [x64] 491 | os: [android] 492 | 493 | sass-embedded-darwin-arm64@1.83.4: 494 | resolution: {integrity: sha512-rp2ywymWc3nymnSnAFG5R/8hvxWCsuhK3wOnD10IDlmNB7o4rzKby1c+2ZfpQGowlYGWsWWTgz8FW2qzmZsQRw==} 495 | engines: {node: '>=14.0.0'} 496 | cpu: [arm64] 497 | os: [darwin] 498 | 499 | sass-embedded-darwin-x64@1.83.4: 500 | resolution: {integrity: sha512-kLkN2lXz9PCgGfDS8Ev5YVcl/V2173L6379en/CaFuJJi7WiyPgBymW7hOmfCt4uO4R1y7CP2Uc08DRtZsBlAA==} 501 | engines: {node: '>=14.0.0'} 502 | cpu: [x64] 503 | os: [darwin] 504 | 505 | sass-embedded-linux-arm64@1.83.4: 506 | resolution: {integrity: sha512-E0zjsZX2HgESwyqw31EHtI39DKa7RgK7nvIhIRco1d0QEw227WnoR9pjH3M/ZQy4gQj3GKilOFHM5Krs/omeIA==} 507 | engines: {node: '>=14.0.0'} 508 | cpu: [arm64] 509 | os: [linux] 510 | 511 | sass-embedded-linux-arm@1.83.4: 512 | resolution: {integrity: sha512-nL90ryxX2lNmFucr9jYUyHHx21AoAgdCL1O5Ltx2rKg2xTdytAGHYo2MT5S0LIeKLa/yKP/hjuSvrbICYNDvtA==} 513 | engines: {node: '>=14.0.0'} 514 | cpu: [arm] 515 | os: [linux] 516 | 517 | sass-embedded-linux-ia32@1.83.4: 518 | resolution: {integrity: sha512-ew5HpchSzgAYbQoriRh8QhlWn5Kw2nQ2jHoV9YLwGKe3fwwOWA0KDedssvDv7FWnY/FCqXyymhLd6Bxae4Xquw==} 519 | engines: {node: '>=14.0.0'} 520 | cpu: [ia32] 521 | os: [linux] 522 | 523 | sass-embedded-linux-musl-arm64@1.83.4: 524 | resolution: {integrity: sha512-IzMgalf6MZOxgp4AVCgsaWAFDP/IVWOrgVXxkyhw29fyAEoSWBJH4k87wyPhEtxSuzVHLxKNbc8k3UzdWmlBFg==} 525 | engines: {node: '>=14.0.0'} 526 | cpu: [arm64] 527 | os: [linux] 528 | 529 | sass-embedded-linux-musl-arm@1.83.4: 530 | resolution: {integrity: sha512-0RrJRwMrmm+gG0VOB5b5Cjs7Sd+lhqpQJa6EJNEaZHljJokEfpE5GejZsGMRMIQLxEvVphZnnxl6sonCGFE/QQ==} 531 | engines: {node: '>=14.0.0'} 532 | cpu: [arm] 533 | os: [linux] 534 | 535 | sass-embedded-linux-musl-ia32@1.83.4: 536 | resolution: {integrity: sha512-LLb4lYbcxPzX4UaJymYXC+WwokxUlfTJEFUv5VF0OTuSsHAGNRs/rslPtzVBTvMeG9TtlOQDhku1F7G6iaDotA==} 537 | engines: {node: '>=14.0.0'} 538 | cpu: [ia32] 539 | os: [linux] 540 | 541 | sass-embedded-linux-musl-riscv64@1.83.4: 542 | resolution: {integrity: sha512-zoKlPzD5Z13HKin1UGR74QkEy+kZEk2AkGX5RelRG494mi+IWwRuWCppXIovor9+BQb9eDWPYPoMVahwN5F7VA==} 543 | engines: {node: '>=14.0.0'} 544 | cpu: [riscv64] 545 | os: [linux] 546 | 547 | sass-embedded-linux-musl-x64@1.83.4: 548 | resolution: {integrity: sha512-hB8+/PYhfEf2zTIcidO5Bpof9trK6WJjZ4T8g2MrxQh8REVtdPcgIkoxczRynqybf9+fbqbUwzXtiUao2GV+vQ==} 549 | engines: {node: '>=14.0.0'} 550 | cpu: [x64] 551 | os: [linux] 552 | 553 | sass-embedded-linux-riscv64@1.83.4: 554 | resolution: {integrity: sha512-83fL4n+oeDJ0Y4KjASmZ9jHS1Vl9ESVQYHMhJE0i4xDi/P3BNarm2rsKljq/QtrwGpbqwn8ujzOu7DsNCMDSHA==} 555 | engines: {node: '>=14.0.0'} 556 | cpu: [riscv64] 557 | os: [linux] 558 | 559 | sass-embedded-linux-x64@1.83.4: 560 | resolution: {integrity: sha512-NlnGdvCmTD5PK+LKXlK3sAuxOgbRIEoZfnHvxd157imCm/s2SYF/R28D0DAAjEViyI8DovIWghgbcqwuertXsA==} 561 | engines: {node: '>=14.0.0'} 562 | cpu: [x64] 563 | os: [linux] 564 | 565 | sass-embedded-win32-arm64@1.83.4: 566 | resolution: {integrity: sha512-J2BFKrEaeSrVazU2qTjyQdAk+MvbzJeTuCET0uAJEXSKtvQ3AzxvzndS7LqkDPbF32eXAHLw8GVpwcBwKbB3Uw==} 567 | engines: {node: '>=14.0.0'} 568 | cpu: [arm64] 569 | os: [win32] 570 | 571 | sass-embedded-win32-ia32@1.83.4: 572 | resolution: {integrity: sha512-uPAe9T/5sANFhJS5dcfAOhOJy8/l2TRYG4r+UO3Wp4yhqbN7bggPvY9c7zMYS0OC8tU/bCvfYUDFHYMCl91FgA==} 573 | engines: {node: '>=14.0.0'} 574 | cpu: [ia32] 575 | os: [win32] 576 | 577 | sass-embedded-win32-x64@1.83.4: 578 | resolution: {integrity: sha512-C9fkDY0jKITdJFij4UbfPFswxoXN9O/Dr79v17fJnstVwtUojzVJWKHUXvF0Zg2LIR7TCc4ju3adejKFxj7ueA==} 579 | engines: {node: '>=14.0.0'} 580 | cpu: [x64] 581 | os: [win32] 582 | 583 | sass-embedded@1.83.4: 584 | resolution: {integrity: sha512-Hf2burRA/y5PGxsg6jB9UpoK/xZ6g/pgrkOcdl6j+rRg1Zj8XhGKZ1MTysZGtTPUUmiiErqzkP5+Kzp95yv9GQ==} 585 | engines: {node: '>=16.0.0'} 586 | hasBin: true 587 | 588 | sass@1.84.0: 589 | resolution: {integrity: sha512-XDAbhEPJRxi7H0SxrnOpiXFQoUJHwkR2u3Zc4el+fK/Tt5Hpzw5kkQ59qVDfvdaUq6gCrEZIbySFBM2T9DNKHg==} 590 | engines: {node: '>=14.0.0'} 591 | hasBin: true 592 | 593 | source-map-js@1.2.1: 594 | resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} 595 | engines: {node: '>=0.10.0'} 596 | 597 | supports-color@8.1.1: 598 | resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} 599 | engines: {node: '>=10'} 600 | 601 | sync-child-process@1.0.2: 602 | resolution: {integrity: sha512-8lD+t2KrrScJ/7KXCSyfhT3/hRq78rC0wBFqNJXv3mZyn6hW2ypM05JmlSvtqRbeq6jqA94oHbxAr2vYsJ8vDA==} 603 | engines: {node: '>=16.0.0'} 604 | 605 | sync-message-port@1.1.3: 606 | resolution: {integrity: sha512-GTt8rSKje5FilG+wEdfCkOcLL7LWqpMlr2c3LRuKt/YXxcJ52aGSbGBAdI4L3aaqfrBt6y711El53ItyH1NWzg==} 607 | engines: {node: '>=16.0.0'} 608 | 609 | to-regex-range@5.0.1: 610 | resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} 611 | engines: {node: '>=8.0'} 612 | 613 | tslib@2.8.1: 614 | resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} 615 | 616 | varint@6.0.0: 617 | resolution: {integrity: sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==} 618 | 619 | vite@6.1.0: 620 | resolution: {integrity: sha512-RjjMipCKVoR4hVfPY6GQTgveinjNuyLw+qruksLDvA5ktI1150VmcMBKmQaEWJhg/j6Uaf6dNCNA0AfdzUb/hQ==} 621 | engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} 622 | hasBin: true 623 | peerDependencies: 624 | '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 625 | jiti: '>=1.21.0' 626 | less: '*' 627 | lightningcss: ^1.21.0 628 | sass: '*' 629 | sass-embedded: '*' 630 | stylus: '*' 631 | sugarss: '*' 632 | terser: ^5.16.0 633 | tsx: ^4.8.1 634 | yaml: ^2.4.2 635 | peerDependenciesMeta: 636 | '@types/node': 637 | optional: true 638 | jiti: 639 | optional: true 640 | less: 641 | optional: true 642 | lightningcss: 643 | optional: true 644 | sass: 645 | optional: true 646 | sass-embedded: 647 | optional: true 648 | stylus: 649 | optional: true 650 | sugarss: 651 | optional: true 652 | terser: 653 | optional: true 654 | tsx: 655 | optional: true 656 | yaml: 657 | optional: true 658 | 659 | snapshots: 660 | 661 | '@bufbuild/protobuf@2.2.3': {} 662 | 663 | '@esbuild/aix-ppc64@0.24.2': 664 | optional: true 665 | 666 | '@esbuild/android-arm64@0.24.2': 667 | optional: true 668 | 669 | '@esbuild/android-arm@0.24.2': 670 | optional: true 671 | 672 | '@esbuild/android-x64@0.24.2': 673 | optional: true 674 | 675 | '@esbuild/darwin-arm64@0.24.2': 676 | optional: true 677 | 678 | '@esbuild/darwin-x64@0.24.2': 679 | optional: true 680 | 681 | '@esbuild/freebsd-arm64@0.24.2': 682 | optional: true 683 | 684 | '@esbuild/freebsd-x64@0.24.2': 685 | optional: true 686 | 687 | '@esbuild/linux-arm64@0.24.2': 688 | optional: true 689 | 690 | '@esbuild/linux-arm@0.24.2': 691 | optional: true 692 | 693 | '@esbuild/linux-ia32@0.24.2': 694 | optional: true 695 | 696 | '@esbuild/linux-loong64@0.24.2': 697 | optional: true 698 | 699 | '@esbuild/linux-mips64el@0.24.2': 700 | optional: true 701 | 702 | '@esbuild/linux-ppc64@0.24.2': 703 | optional: true 704 | 705 | '@esbuild/linux-riscv64@0.24.2': 706 | optional: true 707 | 708 | '@esbuild/linux-s390x@0.24.2': 709 | optional: true 710 | 711 | '@esbuild/linux-x64@0.24.2': 712 | optional: true 713 | 714 | '@esbuild/netbsd-arm64@0.24.2': 715 | optional: true 716 | 717 | '@esbuild/netbsd-x64@0.24.2': 718 | optional: true 719 | 720 | '@esbuild/openbsd-arm64@0.24.2': 721 | optional: true 722 | 723 | '@esbuild/openbsd-x64@0.24.2': 724 | optional: true 725 | 726 | '@esbuild/sunos-x64@0.24.2': 727 | optional: true 728 | 729 | '@esbuild/win32-arm64@0.24.2': 730 | optional: true 731 | 732 | '@esbuild/win32-ia32@0.24.2': 733 | optional: true 734 | 735 | '@esbuild/win32-x64@0.24.2': 736 | optional: true 737 | 738 | '@parcel/watcher-android-arm64@2.5.1': 739 | optional: true 740 | 741 | '@parcel/watcher-darwin-arm64@2.5.1': 742 | optional: true 743 | 744 | '@parcel/watcher-darwin-x64@2.5.1': 745 | optional: true 746 | 747 | '@parcel/watcher-freebsd-x64@2.5.1': 748 | optional: true 749 | 750 | '@parcel/watcher-linux-arm-glibc@2.5.1': 751 | optional: true 752 | 753 | '@parcel/watcher-linux-arm-musl@2.5.1': 754 | optional: true 755 | 756 | '@parcel/watcher-linux-arm64-glibc@2.5.1': 757 | optional: true 758 | 759 | '@parcel/watcher-linux-arm64-musl@2.5.1': 760 | optional: true 761 | 762 | '@parcel/watcher-linux-x64-glibc@2.5.1': 763 | optional: true 764 | 765 | '@parcel/watcher-linux-x64-musl@2.5.1': 766 | optional: true 767 | 768 | '@parcel/watcher-win32-arm64@2.5.1': 769 | optional: true 770 | 771 | '@parcel/watcher-win32-ia32@2.5.1': 772 | optional: true 773 | 774 | '@parcel/watcher-win32-x64@2.5.1': 775 | optional: true 776 | 777 | '@parcel/watcher@2.5.1': 778 | dependencies: 779 | detect-libc: 1.0.3 780 | is-glob: 4.0.3 781 | micromatch: 4.0.8 782 | node-addon-api: 7.1.1 783 | optionalDependencies: 784 | '@parcel/watcher-android-arm64': 2.5.1 785 | '@parcel/watcher-darwin-arm64': 2.5.1 786 | '@parcel/watcher-darwin-x64': 2.5.1 787 | '@parcel/watcher-freebsd-x64': 2.5.1 788 | '@parcel/watcher-linux-arm-glibc': 2.5.1 789 | '@parcel/watcher-linux-arm-musl': 2.5.1 790 | '@parcel/watcher-linux-arm64-glibc': 2.5.1 791 | '@parcel/watcher-linux-arm64-musl': 2.5.1 792 | '@parcel/watcher-linux-x64-glibc': 2.5.1 793 | '@parcel/watcher-linux-x64-musl': 2.5.1 794 | '@parcel/watcher-win32-arm64': 2.5.1 795 | '@parcel/watcher-win32-ia32': 2.5.1 796 | '@parcel/watcher-win32-x64': 2.5.1 797 | optional: true 798 | 799 | '@popperjs/core@2.11.8': {} 800 | 801 | '@rollup/rollup-android-arm-eabi@4.34.6': 802 | optional: true 803 | 804 | '@rollup/rollup-android-arm64@4.34.6': 805 | optional: true 806 | 807 | '@rollup/rollup-darwin-arm64@4.34.6': 808 | optional: true 809 | 810 | '@rollup/rollup-darwin-x64@4.34.6': 811 | optional: true 812 | 813 | '@rollup/rollup-freebsd-arm64@4.34.6': 814 | optional: true 815 | 816 | '@rollup/rollup-freebsd-x64@4.34.6': 817 | optional: true 818 | 819 | '@rollup/rollup-linux-arm-gnueabihf@4.34.6': 820 | optional: true 821 | 822 | '@rollup/rollup-linux-arm-musleabihf@4.34.6': 823 | optional: true 824 | 825 | '@rollup/rollup-linux-arm64-gnu@4.34.6': 826 | optional: true 827 | 828 | '@rollup/rollup-linux-arm64-musl@4.34.6': 829 | optional: true 830 | 831 | '@rollup/rollup-linux-loongarch64-gnu@4.34.6': 832 | optional: true 833 | 834 | '@rollup/rollup-linux-powerpc64le-gnu@4.34.6': 835 | optional: true 836 | 837 | '@rollup/rollup-linux-riscv64-gnu@4.34.6': 838 | optional: true 839 | 840 | '@rollup/rollup-linux-s390x-gnu@4.34.6': 841 | optional: true 842 | 843 | '@rollup/rollup-linux-x64-gnu@4.34.6': 844 | optional: true 845 | 846 | '@rollup/rollup-linux-x64-musl@4.34.6': 847 | optional: true 848 | 849 | '@rollup/rollup-win32-arm64-msvc@4.34.6': 850 | optional: true 851 | 852 | '@rollup/rollup-win32-ia32-msvc@4.34.6': 853 | optional: true 854 | 855 | '@rollup/rollup-win32-x64-msvc@4.34.6': 856 | optional: true 857 | 858 | '@types/estree@1.0.6': {} 859 | 860 | bootstrap@5.3.3(@popperjs/core@2.11.8): 861 | dependencies: 862 | '@popperjs/core': 2.11.8 863 | 864 | braces@3.0.3: 865 | dependencies: 866 | fill-range: 7.1.1 867 | optional: true 868 | 869 | buffer-builder@0.2.0: {} 870 | 871 | chokidar@4.0.3: 872 | dependencies: 873 | readdirp: 4.1.1 874 | optional: true 875 | 876 | colorjs.io@0.5.2: {} 877 | 878 | detect-libc@1.0.3: 879 | optional: true 880 | 881 | esbuild@0.24.2: 882 | optionalDependencies: 883 | '@esbuild/aix-ppc64': 0.24.2 884 | '@esbuild/android-arm': 0.24.2 885 | '@esbuild/android-arm64': 0.24.2 886 | '@esbuild/android-x64': 0.24.2 887 | '@esbuild/darwin-arm64': 0.24.2 888 | '@esbuild/darwin-x64': 0.24.2 889 | '@esbuild/freebsd-arm64': 0.24.2 890 | '@esbuild/freebsd-x64': 0.24.2 891 | '@esbuild/linux-arm': 0.24.2 892 | '@esbuild/linux-arm64': 0.24.2 893 | '@esbuild/linux-ia32': 0.24.2 894 | '@esbuild/linux-loong64': 0.24.2 895 | '@esbuild/linux-mips64el': 0.24.2 896 | '@esbuild/linux-ppc64': 0.24.2 897 | '@esbuild/linux-riscv64': 0.24.2 898 | '@esbuild/linux-s390x': 0.24.2 899 | '@esbuild/linux-x64': 0.24.2 900 | '@esbuild/netbsd-arm64': 0.24.2 901 | '@esbuild/netbsd-x64': 0.24.2 902 | '@esbuild/openbsd-arm64': 0.24.2 903 | '@esbuild/openbsd-x64': 0.24.2 904 | '@esbuild/sunos-x64': 0.24.2 905 | '@esbuild/win32-arm64': 0.24.2 906 | '@esbuild/win32-ia32': 0.24.2 907 | '@esbuild/win32-x64': 0.24.2 908 | 909 | fill-range@7.1.1: 910 | dependencies: 911 | to-regex-range: 5.0.1 912 | optional: true 913 | 914 | fsevents@2.3.3: 915 | optional: true 916 | 917 | has-flag@4.0.0: {} 918 | 919 | immutable@5.0.3: {} 920 | 921 | is-extglob@2.1.1: 922 | optional: true 923 | 924 | is-glob@4.0.3: 925 | dependencies: 926 | is-extglob: 2.1.1 927 | optional: true 928 | 929 | is-number@7.0.0: 930 | optional: true 931 | 932 | micromatch@4.0.8: 933 | dependencies: 934 | braces: 3.0.3 935 | picomatch: 2.3.1 936 | optional: true 937 | 938 | nanoid@3.3.8: {} 939 | 940 | node-addon-api@7.1.1: 941 | optional: true 942 | 943 | picocolors@1.1.1: {} 944 | 945 | picomatch@2.3.1: 946 | optional: true 947 | 948 | postcss@8.5.1: 949 | dependencies: 950 | nanoid: 3.3.8 951 | picocolors: 1.1.1 952 | source-map-js: 1.2.1 953 | 954 | prettier@3.5.0: {} 955 | 956 | readdirp@4.1.1: 957 | optional: true 958 | 959 | rollup@4.34.6: 960 | dependencies: 961 | '@types/estree': 1.0.6 962 | optionalDependencies: 963 | '@rollup/rollup-android-arm-eabi': 4.34.6 964 | '@rollup/rollup-android-arm64': 4.34.6 965 | '@rollup/rollup-darwin-arm64': 4.34.6 966 | '@rollup/rollup-darwin-x64': 4.34.6 967 | '@rollup/rollup-freebsd-arm64': 4.34.6 968 | '@rollup/rollup-freebsd-x64': 4.34.6 969 | '@rollup/rollup-linux-arm-gnueabihf': 4.34.6 970 | '@rollup/rollup-linux-arm-musleabihf': 4.34.6 971 | '@rollup/rollup-linux-arm64-gnu': 4.34.6 972 | '@rollup/rollup-linux-arm64-musl': 4.34.6 973 | '@rollup/rollup-linux-loongarch64-gnu': 4.34.6 974 | '@rollup/rollup-linux-powerpc64le-gnu': 4.34.6 975 | '@rollup/rollup-linux-riscv64-gnu': 4.34.6 976 | '@rollup/rollup-linux-s390x-gnu': 4.34.6 977 | '@rollup/rollup-linux-x64-gnu': 4.34.6 978 | '@rollup/rollup-linux-x64-musl': 4.34.6 979 | '@rollup/rollup-win32-arm64-msvc': 4.34.6 980 | '@rollup/rollup-win32-ia32-msvc': 4.34.6 981 | '@rollup/rollup-win32-x64-msvc': 4.34.6 982 | fsevents: 2.3.3 983 | 984 | rxjs@7.8.1: 985 | dependencies: 986 | tslib: 2.8.1 987 | 988 | sass-embedded-android-arm64@1.83.4: 989 | optional: true 990 | 991 | sass-embedded-android-arm@1.83.4: 992 | optional: true 993 | 994 | sass-embedded-android-ia32@1.83.4: 995 | optional: true 996 | 997 | sass-embedded-android-riscv64@1.83.4: 998 | optional: true 999 | 1000 | sass-embedded-android-x64@1.83.4: 1001 | optional: true 1002 | 1003 | sass-embedded-darwin-arm64@1.83.4: 1004 | optional: true 1005 | 1006 | sass-embedded-darwin-x64@1.83.4: 1007 | optional: true 1008 | 1009 | sass-embedded-linux-arm64@1.83.4: 1010 | optional: true 1011 | 1012 | sass-embedded-linux-arm@1.83.4: 1013 | optional: true 1014 | 1015 | sass-embedded-linux-ia32@1.83.4: 1016 | optional: true 1017 | 1018 | sass-embedded-linux-musl-arm64@1.83.4: 1019 | optional: true 1020 | 1021 | sass-embedded-linux-musl-arm@1.83.4: 1022 | optional: true 1023 | 1024 | sass-embedded-linux-musl-ia32@1.83.4: 1025 | optional: true 1026 | 1027 | sass-embedded-linux-musl-riscv64@1.83.4: 1028 | optional: true 1029 | 1030 | sass-embedded-linux-musl-x64@1.83.4: 1031 | optional: true 1032 | 1033 | sass-embedded-linux-riscv64@1.83.4: 1034 | optional: true 1035 | 1036 | sass-embedded-linux-x64@1.83.4: 1037 | optional: true 1038 | 1039 | sass-embedded-win32-arm64@1.83.4: 1040 | optional: true 1041 | 1042 | sass-embedded-win32-ia32@1.83.4: 1043 | optional: true 1044 | 1045 | sass-embedded-win32-x64@1.83.4: 1046 | optional: true 1047 | 1048 | sass-embedded@1.83.4: 1049 | dependencies: 1050 | '@bufbuild/protobuf': 2.2.3 1051 | buffer-builder: 0.2.0 1052 | colorjs.io: 0.5.2 1053 | immutable: 5.0.3 1054 | rxjs: 7.8.1 1055 | supports-color: 8.1.1 1056 | sync-child-process: 1.0.2 1057 | varint: 6.0.0 1058 | optionalDependencies: 1059 | sass-embedded-android-arm: 1.83.4 1060 | sass-embedded-android-arm64: 1.83.4 1061 | sass-embedded-android-ia32: 1.83.4 1062 | sass-embedded-android-riscv64: 1.83.4 1063 | sass-embedded-android-x64: 1.83.4 1064 | sass-embedded-darwin-arm64: 1.83.4 1065 | sass-embedded-darwin-x64: 1.83.4 1066 | sass-embedded-linux-arm: 1.83.4 1067 | sass-embedded-linux-arm64: 1.83.4 1068 | sass-embedded-linux-ia32: 1.83.4 1069 | sass-embedded-linux-musl-arm: 1.83.4 1070 | sass-embedded-linux-musl-arm64: 1.83.4 1071 | sass-embedded-linux-musl-ia32: 1.83.4 1072 | sass-embedded-linux-musl-riscv64: 1.83.4 1073 | sass-embedded-linux-musl-x64: 1.83.4 1074 | sass-embedded-linux-riscv64: 1.83.4 1075 | sass-embedded-linux-x64: 1.83.4 1076 | sass-embedded-win32-arm64: 1.83.4 1077 | sass-embedded-win32-ia32: 1.83.4 1078 | sass-embedded-win32-x64: 1.83.4 1079 | 1080 | sass@1.84.0: 1081 | dependencies: 1082 | chokidar: 4.0.3 1083 | immutable: 5.0.3 1084 | source-map-js: 1.2.1 1085 | optionalDependencies: 1086 | '@parcel/watcher': 2.5.1 1087 | optional: true 1088 | 1089 | source-map-js@1.2.1: {} 1090 | 1091 | supports-color@8.1.1: 1092 | dependencies: 1093 | has-flag: 4.0.0 1094 | 1095 | sync-child-process@1.0.2: 1096 | dependencies: 1097 | sync-message-port: 1.1.3 1098 | 1099 | sync-message-port@1.1.3: {} 1100 | 1101 | to-regex-range@5.0.1: 1102 | dependencies: 1103 | is-number: 7.0.0 1104 | optional: true 1105 | 1106 | tslib@2.8.1: {} 1107 | 1108 | varint@6.0.0: {} 1109 | 1110 | vite@6.1.0(sass-embedded@1.83.4)(sass@1.84.0): 1111 | dependencies: 1112 | esbuild: 0.24.2 1113 | postcss: 8.5.1 1114 | rollup: 4.34.6 1115 | optionalDependencies: 1116 | fsevents: 2.3.3 1117 | sass: 1.84.0 1118 | sass-embedded: 1.83.4 1119 | -------------------------------------------------------------------------------- /src/bootstrap-custom.scss: -------------------------------------------------------------------------------- 1 | @use "bootstrap/scss/bootstrap" with ( 2 | $color-mode-type: media-query 3 | ); 4 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 13 | 14 | 15 | 16 | Age Tool - Online Age Key Generator Encryption Decryption Tool 17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 |
25 |
26 |
27 |

Age Tool

28 |

29 | A simple and secure online client-side Age key generator, 30 | encryption and decryption tool. 31 |

32 |

33 |
34 |
35 |
36 | 37 |
38 |
39 |
40 | 126 |
127 |
134 |
135 |
136 |
Private key
137 |
138 | 146 |
147 |
148 | 149 |
150 |
Public key
151 |
152 | 160 |
161 |
162 | 163 |
164 | 165 |
166 | 169 |
170 |
171 |
172 |
179 |
180 |
181 |
Public keys
182 |
183 | 191 |
192 |
193 | 194 |
195 |
Message
196 |
197 | 205 |
206 |
207 | 208 |
209 |
Output
210 |
211 | 219 |
220 |
221 | 222 |
223 | 224 |
225 | 228 |
229 |
230 |
231 | 232 |
239 |
240 |
241 |
Public keys
242 |
243 | 251 |
252 |
253 | 254 |
255 |
Files
256 |
257 | 264 |
265 |
266 | 267 |
268 |
Output
269 |
270 |

The encrypted files will be downloaded

271 |
272 |
273 | 274 |
275 | 276 |
277 | 286 |
287 |
288 |
289 | 290 |
297 |
298 |
299 |
Private keys
300 |
301 | 309 |
310 |
311 | 312 |
313 |
Encrypted Text
314 |
315 | 323 |
324 |
325 | 326 |
327 |
Output
328 |
329 | 337 |
338 |
339 | 340 |
341 | 342 |
343 | 346 |
347 |
348 |
349 | 350 |
357 |
358 |
359 |
Private keys
360 |
361 | 369 |
370 |
371 | 372 |
373 |
Encrypted Files
374 |
375 | 383 |
384 |
385 | 386 |
387 |
Output
388 |
389 |

The decrypted files will be downloaded

390 |
391 |
392 | 393 |
394 | 395 |
396 | 405 |
406 |
407 |
408 |
415 |

416 | This site provides a simple and easy-to-use open source Age 417 | tool for people to generate new Age keys online, encrypt or 418 | decrypt messages. 419 |

420 | 421 |

422 | Built using Go and WebAssembly. The Go library 423 | Age 426 | is wrapped in a WebAssembly module and all actions are done in 427 | browser. 428 |

429 | 430 | There is no backend or API calls. Everything is generated on 432 | client(browser) side 434 | 435 |

436 | This site is Open Source and the source code is available on 437 | GitHub. 440 |

441 |
442 |
443 |
444 |
445 |
446 |
447 | 448 | 449 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import "./bootstrap-custom.scss"; 2 | 3 | import "bootstrap"; 4 | 5 | import "../vendor/wasm_exec.js"; 6 | import ageWasmUrl from "../vendor/age.wasm?url"; 7 | const go = new Go(); 8 | WebAssembly.instantiateStreaming(fetch(ageWasmUrl), go.importObject).then( 9 | (result) => { 10 | go.run(result.instance); 11 | }, 12 | ); 13 | 14 | const alert = (alertPlaceholder, message, type) => { 15 | const wrapper = document.createElement("div"); 16 | wrapper.innerHTML = [ 17 | `", 21 | ].join(""); 22 | 23 | alertPlaceholder.append(wrapper); 24 | }; 25 | 26 | const downloadURL = (data, fileName) => { 27 | const a = document.createElement("a"); 28 | a.href = data; 29 | a.download = fileName; 30 | document.body.appendChild(a); 31 | a.style.display = "none"; 32 | a.click(); 33 | a.remove(); 34 | }; 35 | 36 | const downloadBlob = (data, fileName) => { 37 | const blob = new Blob([data], { 38 | type: "application/octet-stream", 39 | }); 40 | const url = window.URL.createObjectURL(blob); 41 | downloadURL(url, fileName); 42 | setTimeout(() => window.URL.revokeObjectURL(url), 1000); 43 | }; 44 | 45 | const showWorking = (element) => { 46 | element.classList.add("disabled"); 47 | if (element.firstElementChild) { 48 | element.firstElementChild.removeAttribute("hidden"); 49 | } 50 | }; 51 | 52 | const hideWorking = (element) => { 53 | element.classList.remove("disabled"); 54 | if (element.firstElementChild) { 55 | element.firstElementChild.setAttribute("hidden", true); 56 | } 57 | }; 58 | 59 | document 60 | .getElementById("generateKeysForm") 61 | .addEventListener("submit", function (e) { 62 | e.preventDefault(); 63 | let pubkey = document.getElementById("pubkey"); 64 | let privkey = document.getElementById("privkey"); 65 | const keys = generateX25519Identity(); 66 | pubkey.value = keys.publicKey; 67 | privkey.value = keys.privateKey; 68 | }); 69 | 70 | document.getElementById("encryptForm").addEventListener("submit", function (e) { 71 | e.preventDefault(); 72 | const recipients = document.getElementById("recipients").value; 73 | const message = document.getElementById("message").value; 74 | let output = document.getElementById("encryptedOutput"); 75 | output.value = ""; 76 | 77 | const result = encrypt(recipients, message); 78 | 79 | if (result.error) { 80 | alert(document.getElementById("errorEncrypt"), result.error, "danger"); 81 | } else { 82 | output.value = result.output; 83 | } 84 | }); 85 | 86 | document 87 | .getElementById("encryptBinaryForm") 88 | .addEventListener("submit", function (e) { 89 | e.preventDefault(); 90 | const recipients = document.getElementById("recipients-binary").value; 91 | const file = document.getElementById("filesEncrypt"); 92 | if (file.files.length == 0) { 93 | alert( 94 | document.getElementById("errorEncryptBinary"), 95 | "Please select a file", 96 | "danger", 97 | ); 98 | return; 99 | } 100 | for (const f of file.files) { 101 | console.log(`Processing ${f.name}...`); 102 | showWorking(e.submitter); 103 | const reader = new FileReader(); 104 | reader.onload = function () { 105 | const buffer = new Uint8Array(reader.result); 106 | const result = encryptBinary(recipients, buffer); 107 | if (typeof result === "string") { 108 | alert( 109 | document.getElementById("errorEncryptBinary"), 110 | result, 111 | "danger", 112 | ); 113 | } else { 114 | const fileName = f.name + ".age"; 115 | console.log(`Encrypted ${fileName}`); 116 | downloadBlob(result, `${fileName}`); 117 | } 118 | hideWorking(e.submitter); 119 | }; 120 | reader.readAsArrayBuffer(f); 121 | } 122 | }); 123 | 124 | document.getElementById("decryptForm").addEventListener("submit", function (e) { 125 | e.preventDefault(); 126 | const identities = document.getElementById("identities").value; 127 | const encryptedText = document.getElementById("encryptedText").value; 128 | let output = document.getElementById("decryptedOutput"); 129 | output.value = ""; 130 | 131 | const result = decrypt(identities, encryptedText); 132 | if (result.error) { 133 | alert(document.getElementById("errorDecrypt"), result.error, "danger"); 134 | } else { 135 | output.value = result.output; 136 | } 137 | }); 138 | 139 | document 140 | .getElementById("decryptBinaryForm") 141 | .addEventListener("submit", function (e) { 142 | e.preventDefault(); 143 | const identities = document.getElementById("identities-binary").value; 144 | const file = document.getElementById("filesDecrypt"); 145 | if (file.files.length == 0) { 146 | alert( 147 | document.getElementById("errorDecryptBinary"), 148 | "Please select a file", 149 | "danger", 150 | ); 151 | return; 152 | } 153 | for (const f of file.files) { 154 | console.log(`Processing ${f.name}...`); 155 | const reader = new FileReader(); 156 | reader.onload = function () { 157 | showWorking(e.submitter); 158 | 159 | const buffer = new Uint8Array(reader.result); 160 | const result = decryptBinary(identities, buffer); 161 | if (typeof result === "string") { 162 | alert( 163 | document.getElementById("errorDecryptBinary"), 164 | result, 165 | "danger", 166 | ); 167 | return; 168 | } else { 169 | const fileName = f.name.replace(".age", ""); 170 | console.log(`Decrypted ${fileName}`); 171 | downloadBlob(result, `${fileName}`); 172 | } 173 | hideWorking(e.submitter); 174 | }; 175 | reader.readAsArrayBuffer(f); 176 | } 177 | }); 178 | -------------------------------------------------------------------------------- /src/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MarinX/agewasm/6d292d99156f44100db6e40bb757931fcbbf67b1/src/public/favicon.ico -------------------------------------------------------------------------------- /vite.config.js: -------------------------------------------------------------------------------- 1 | import { resolve } from 'path' 2 | 3 | export default { 4 | root: resolve(__dirname, 'src'), 5 | build: { 6 | outDir: '../dist' 7 | }, 8 | server: { 9 | port: 8080 10 | }, 11 | css: { 12 | preprocessorOptions: { 13 | scss: { 14 | quietDeps: true 15 | } 16 | } 17 | } 18 | } 19 | 20 | --------------------------------------------------------------------------------