From 1a924b77c4357a79fa61dfa0e1e3b07ffca69f7c Mon Sep 17 00:00:00 2001 From: neonphog Date: Tue, 18 Jun 2024 14:49:47 -0600 Subject: [PATCH 01/36] direct port of cf server PoC from tx5 repo --- .github/workflows/static.yml | 7 + .github/workflows/test.yml | 7 + Makefile | 5 + ts/sbd-server/.gitignore | 172 ++ ts/sbd-server/.prettierrc | 6 + ts/sbd-server/package-lock.json | 2775 ++++++++++++++++++++++++++ ts/sbd-server/package.json | 28 + ts/sbd-server/src/b64.ts | 12 + ts/sbd-server/src/ed.ts | 4 + ts/sbd-server/src/err.ts | 11 + ts/sbd-server/src/index.test.ts | 149 ++ ts/sbd-server/src/index.ts | 272 +++ ts/sbd-server/src/msg.test.ts | 30 + ts/sbd-server/src/msg.ts | 47 + ts/sbd-server/src/rate-limit.test.ts | 24 + ts/sbd-server/src/rate-limit.ts | 16 + ts/sbd-server/tsconfig.json | 21 + ts/sbd-server/wrangler.toml | 15 + 18 files changed, 3601 insertions(+) create mode 100644 ts/sbd-server/.gitignore create mode 100644 ts/sbd-server/.prettierrc create mode 100644 ts/sbd-server/package-lock.json create mode 100644 ts/sbd-server/package.json create mode 100644 ts/sbd-server/src/b64.ts create mode 100644 ts/sbd-server/src/ed.ts create mode 100644 ts/sbd-server/src/err.ts create mode 100644 ts/sbd-server/src/index.test.ts create mode 100644 ts/sbd-server/src/index.ts create mode 100644 ts/sbd-server/src/msg.test.ts create mode 100644 ts/sbd-server/src/msg.ts create mode 100644 ts/sbd-server/src/rate-limit.test.ts create mode 100644 ts/sbd-server/src/rate-limit.ts create mode 100644 ts/sbd-server/tsconfig.json create mode 100644 ts/sbd-server/wrangler.toml diff --git a/.github/workflows/static.yml b/.github/workflows/static.yml index 7c1c69b..2f1ebef 100644 --- a/.github/workflows/static.yml +++ b/.github/workflows/static.yml @@ -30,6 +30,13 @@ jobs: rustup component add rustfmt --toolchain ${{ matrix.toolchain }} rustup component add clippy --toolchain ${{ matrix.toolchain }} + - name: NodeJS Setup + uses: actions/setup-node@v4 + with: + node-version: latest + cache: 'npm' + cache-dependency-path: ts/sbd-server/package-lock.json + - name: Rust Cache uses: Swatinem/rust-cache@v2 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9dbf190..73535a4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -30,6 +30,13 @@ jobs: rustup toolchain install ${{ matrix.toolchain }} --profile minimal --no-self-update rustup default ${{ matrix.toolchain }} + - name: NodeJS Setup + uses: actions/setup-node@v4 + with: + node-version: latest + cache: 'npm' + cache-dependency-path: ts/sbd-server/package-lock.json + - name: Rust Cache uses: Swatinem/rust-cache@v2 diff --git a/Makefile b/Makefile index 9f5342e..b456e1d 100644 --- a/Makefile +++ b/Makefile @@ -56,8 +56,13 @@ bump: test: static cargo build --all-targets RUST_BACKTRACE=1 cargo test + cd ts/sbd-server && npm ci + cd ts/sbd-server && npm run test:unit static: cargo fmt -- --check cargo clippy -- -Dwarnings + cd ts/sbd-server && npm ci + cd ts/sbd-server && npm run test:fmt + cd ts/sbd-server && npm run test:type @if [ "${CI}x" != "x" ]; then git diff --exit-code; fi diff --git a/ts/sbd-server/.gitignore b/ts/sbd-server/.gitignore new file mode 100644 index 0000000..3b0fe33 --- /dev/null +++ b/ts/sbd-server/.gitignore @@ -0,0 +1,172 @@ +# Logs + +logs +_.log +npm-debug.log_ +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) + +report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json + +# Runtime data + +pids +_.pid +_.seed +\*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover + +lib-cov + +# Coverage directory used by tools like istanbul + +coverage +\*.lcov + +# nyc test coverage + +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) + +.grunt + +# Bower dependency directory (https://bower.io/) + +bower_components + +# node-waf configuration + +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) + +build/Release + +# Dependency directories + +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) + +web_modules/ + +# TypeScript cache + +\*.tsbuildinfo + +# Optional npm cache directory + +.npm + +# Optional eslint cache + +.eslintcache + +# Optional stylelint cache + +.stylelintcache + +# Microbundle cache + +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history + +.node_repl_history + +# Output of 'npm pack' + +\*.tgz + +# Yarn Integrity file + +.yarn-integrity + +# dotenv environment variable files + +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) + +.cache +.parcel-cache + +# Next.js build output + +.next +out + +# Nuxt.js build / generate output + +.nuxt +dist + +# Gatsby files + +.cache/ + +# Comment in the public line in if your project uses Gatsby and not Next.js + +# https://nextjs.org/blog/next-9-1#public-directory-support + +# public + +# vuepress build output + +.vuepress/dist + +# vuepress v2.x temp and cache directory + +.temp +.cache + +# Docusaurus cache and generated files + +.docusaurus + +# Serverless directories + +.serverless/ + +# FuseBox cache + +.fusebox/ + +# DynamoDB Local files + +.dynamodb/ + +# TernJS port file + +.tern-port + +# Stores VSCode versions used for testing VSCode extensions + +.vscode-test + +# yarn v2 + +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.\* + +# wrangler project + +.dev.vars +.wrangler/ diff --git a/ts/sbd-server/.prettierrc b/ts/sbd-server/.prettierrc new file mode 100644 index 0000000..f4a9871 --- /dev/null +++ b/ts/sbd-server/.prettierrc @@ -0,0 +1,6 @@ +{ + "printWidth": 80, + "singleQuote": true, + "semi": true, + "useTabs": false +} diff --git a/ts/sbd-server/package-lock.json b/ts/sbd-server/package-lock.json new file mode 100644 index 0000000..9d32b3f --- /dev/null +++ b/ts/sbd-server/package-lock.json @@ -0,0 +1,2775 @@ +{ + "name": "tx5-signal-cf", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "tx5-signal-cf", + "version": "0.0.0", + "dependencies": { + "@noble/ed25519": "^2.0.0", + "@noble/hashes": "^1.4.0", + "js-base64": "^3.7.7" + }, + "devDependencies": { + "@cloudflare/workers-types": "^4.20240312.0", + "@types/ws": "^8.5.10", + "prettier": "^3.2.5", + "typescript": "^5.0.4", + "vitest": "^1.3.1", + "wrangler": "^3.36.0", + "ws": "^8.16.0" + } + }, + "node_modules/@cloudflare/kv-asset-handler": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.3.1.tgz", + "integrity": "sha512-lKN2XCfKCmpKb86a1tl4GIwsJYDy9TGuwjhDELLmpKygQhw8X2xR4dusgpC5Tg7q1pB96Eb0rBo81kxSILQMwA==", + "dev": true, + "dependencies": { + "mime": "^3.0.0" + } + }, + "node_modules/@cloudflare/workerd-darwin-64": { + "version": "1.20240314.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20240314.0.tgz", + "integrity": "sha512-19xW64AmkjGnp9ZSwa5RPMTBJ0eqadY/oLs3RcdC8J+R8vT766U2bgxyuf3VATlOf+T7t28aGYzW/QcBRls9eg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@cloudflare/workerd-darwin-arm64": { + "version": "1.20240314.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20240314.0.tgz", + "integrity": "sha512-gq78D30GlNSg55YRzCzNHPuLp87L7xmYCYa5hIuIE7xpqhqGN6FV/mRtp2TQ5VoDXiuq1F+VdEZDwQFvrNAvtg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@cloudflare/workerd-linux-64": { + "version": "1.20240314.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20240314.0.tgz", + "integrity": "sha512-1PYddg+lGGOUkXNt3LEHB0GvIBWjilTNwmbacGyyVRm+zaWGKqt2bS3bW/TY6cHJ1lxFe/fDMrQOgnSBB7jGIw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@cloudflare/workerd-linux-arm64": { + "version": "1.20240314.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20240314.0.tgz", + "integrity": "sha512-GIyyO+TKYQ7TsM/DgpoHP2uQrJuPEc/cpRaXYeOzHerGAdQRej6iS2+LAnTJgLTXgOC4DE622mKBL3tnZvuKVQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@cloudflare/workerd-windows-64": { + "version": "1.20240314.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20240314.0.tgz", + "integrity": "sha512-NWZeVXEXJfPuLAXfMTiFusJNOMnsHkBae0C4hlqzwIzYiQ0PYnQ+BEWFS5eWy5dZihhFrsW3VRYqnTbgESIkzw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@cloudflare/workers-types": { + "version": "4.20240312.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20240312.0.tgz", + "integrity": "sha512-tpBNfijiXR/DSZkcUZHxP+80nIvKUWbGO2u4FBLudmJLGPhzgfoQ3tql+FeIhxYslSituMcVQNnJmWTF7FjURg==", + "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/@esbuild-plugins/node-globals-polyfill": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@esbuild-plugins/node-globals-polyfill/-/node-globals-polyfill-0.2.3.tgz", + "integrity": "sha512-r3MIryXDeXDOZh7ih1l/yE9ZLORCd5e8vWg02azWRGj5SPTuoh69A2AIyn0Z31V/kHBfZ4HgWJ+OK3GTTwLmnw==", + "dev": true, + "peerDependencies": { + "esbuild": "*" + } + }, + "node_modules/@esbuild-plugins/node-modules-polyfill": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@esbuild-plugins/node-modules-polyfill/-/node-modules-polyfill-0.2.2.tgz", + "integrity": "sha512-LXV7QsWJxRuMYvKbiznh+U1ilIop3g2TeKRzUxOG5X3YITc8JyyTa90BmLwqqv0YnX4v32CSlG+vsziZp9dMvA==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^4.0.0", + "rollup-plugin-node-polyfills": "^0.2.1" + }, + "peerDependencies": { + "esbuild": "*" + } + }, + "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/@esbuild/android-arm": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", + "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", + "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", + "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", + "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", + "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", + "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", + "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", + "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", + "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", + "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", + "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", + "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", + "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", + "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", + "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", + "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", + "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", + "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", + "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", + "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", + "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", + "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@fastify/busboy": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", + "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "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, + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "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, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "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/@noble/ed25519": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@noble/ed25519/-/ed25519-2.0.0.tgz", + "integrity": "sha512-/extjhkwFupyopDrt80OMWKdLgP429qLZj+z6sYJz90rF2Iz0gjZh2ArMKPImUl13Kx+0EXI2hN9T/KJV0/Zng==", + "funding": [ + { + "type": "individual", + "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/@rollup/rollup-android-arm-eabi": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.13.0.tgz", + "integrity": "sha512-5ZYPOuaAqEH/W3gYsRkxQATBW3Ii1MfaT4EQstTnLKViLi2gLSQmlmtTpGucNP3sXEpOiI5tdGhjdE111ekyEg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.13.0.tgz", + "integrity": "sha512-BSbaCmn8ZadK3UAQdlauSvtaJjhlDEjS5hEVVIN3A4bbl3X+otyf/kOJV08bYiRxfejP3DXFzO2jz3G20107+Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.13.0.tgz", + "integrity": "sha512-Ovf2evVaP6sW5Ut0GHyUSOqA6tVKfrTHddtmxGQc1CTQa1Cw3/KMCDEEICZBbyppcwnhMwcDce9ZRxdWRpVd6g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.13.0.tgz", + "integrity": "sha512-U+Jcxm89UTK592vZ2J9st9ajRv/hrwHdnvyuJpa5A2ngGSVHypigidkQJP+YiGL6JODiUeMzkqQzbCG3At81Gg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.13.0.tgz", + "integrity": "sha512-8wZidaUJUTIR5T4vRS22VkSMOVooG0F4N+JSwQXWSRiC6yfEsFMLTYRFHvby5mFFuExHa/yAp9juSphQQJAijQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.13.0.tgz", + "integrity": "sha512-Iu0Kno1vrD7zHQDxOmvweqLkAzjxEVqNhUIXBsZ8hu8Oak7/5VTPrxOEZXYC1nmrBVJp0ZcL2E7lSuuOVaE3+w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.13.0.tgz", + "integrity": "sha512-C31QrW47llgVyrRjIwiOwsHFcaIwmkKi3PCroQY5aVq4H0A5v/vVVAtFsI1nfBngtoRpeREvZOkIhmRwUKkAdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.13.0.tgz", + "integrity": "sha512-Oq90dtMHvthFOPMl7pt7KmxzX7E71AfyIhh+cPhLY9oko97Zf2C9tt/XJD4RgxhaGeAraAXDtqxvKE1y/j35lA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.13.0.tgz", + "integrity": "sha512-yUD/8wMffnTKuiIsl6xU+4IA8UNhQ/f1sAnQebmE/lyQ8abjsVyDkyRkWop0kdMhKMprpNIhPmYlCxgHrPoXoA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.13.0.tgz", + "integrity": "sha512-9RyNqoFNdF0vu/qqX63fKotBh43fJQeYC98hCaf89DYQpv+xu0D8QFSOS0biA7cGuqJFOc1bJ+m2rhhsKcw1hw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.13.0.tgz", + "integrity": "sha512-46ue8ymtm/5PUU6pCvjlic0z82qWkxv54GTJZgHrQUuZnVH+tvvSP0LsozIDsCBFO4VjJ13N68wqrKSeScUKdA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.13.0.tgz", + "integrity": "sha512-P5/MqLdLSlqxbeuJ3YDeX37srC8mCflSyTrUsgbU1c/U9j6l2g2GiIdYaGD9QjdMQPMSgYm7hgg0551wHyIluw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.13.0.tgz", + "integrity": "sha512-UKXUQNbO3DOhzLRwHSpa0HnhhCgNODvfoPWv2FCXme8N/ANFfhIPMGuOT+QuKd16+B5yxZ0HdpNlqPvTMS1qfw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "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 + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.11.27", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.27.tgz", + "integrity": "sha512-qyUZfMnCg1KEz57r7pzFtSGt49f6RPkPBis3Vo4PbS7roQEDn22hiHzl/Lo1q4i4hDEgBJmBF/NTNg2XR0HbFg==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/node-forge": { + "version": "1.3.11", + "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", + "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/ws": { + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", + "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@vitest/expect": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.3.1.tgz", + "integrity": "sha512-xofQFwIzfdmLLlHa6ag0dPV8YsnKOCP1KdAeVVh34vSjN2dcUiXYCD9htu/9eM7t8Xln4v03U9HLxLpPlsXdZw==", + "dev": true, + "dependencies": { + "@vitest/spy": "1.3.1", + "@vitest/utils": "1.3.1", + "chai": "^4.3.10" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.3.1.tgz", + "integrity": "sha512-5FzF9c3jG/z5bgCnjr8j9LNq/9OxV2uEBAITOXfoe3rdZJTdO7jzThth7FXv/6b+kdY65tpRQB7WaKhNZwX+Kg==", + "dev": true, + "dependencies": { + "@vitest/utils": "1.3.1", + "p-limit": "^5.0.0", + "pathe": "^1.1.1" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.3.1.tgz", + "integrity": "sha512-EF++BZbt6RZmOlE3SuTPu/NfwBF6q4ABS37HHXzs2LUVPBLx2QoY/K0fKpRChSo8eLiuxcbCVfqKgx/dplCDuQ==", + "dev": true, + "dependencies": { + "magic-string": "^0.30.5", + "pathe": "^1.1.1", + "pretty-format": "^29.7.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot/node_modules/magic-string": { + "version": "0.30.8", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz", + "integrity": "sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@vitest/spy": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.3.1.tgz", + "integrity": "sha512-xAcW+S099ylC9VLU7eZfdT9myV67Nor9w9zhf0mGCYJSO+zM2839tOeROTdikOi/8Qeusffvxb/MyBSOja1Uig==", + "dev": true, + "dependencies": { + "tinyspy": "^2.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.3.1.tgz", + "integrity": "sha512-d3Waie/299qqRyHTm2DjADeTaNdNSVsnwHPWrs20JMpjh6eiVq7ggggweO8rc4arhf6rRkWuHKwvxGvejUXZZQ==", + "dev": true, + "dependencies": { + "diff-sequences": "^29.6.3", + "estree-walker": "^3.0.3", + "loupe": "^2.3.7", + "pretty-format": "^29.7.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils/node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", + "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "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/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/as-table": { + "version": "1.0.55", + "resolved": "https://registry.npmjs.org/as-table/-/as-table-1.0.55.tgz", + "integrity": "sha512-xvsWESUJn0JN421Xb9MQw6AsMHRCUknCe0Wjlxvjud80mU4E6hQf1A6NzQKcYNmYw62MfzEtXc+badstZP3JpQ==", + "dev": true, + "dependencies": { + "printable-characters": "^1.0.42" + } + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/blake3-wasm": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/blake3-wasm/-/blake3-wasm-2.1.5.tgz", + "integrity": "sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==", + "dev": true + }, + "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/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/capnp-ts": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/capnp-ts/-/capnp-ts-0.7.0.tgz", + "integrity": "sha512-XKxXAC3HVPv7r674zP0VC3RTXz+/JKhfyw94ljvF80yynK6VkTnqE3jMuN8b3dUVmmc43TjyxjW4KTsmB3c86g==", + "dev": true, + "dependencies": { + "debug": "^4.3.1", + "tslib": "^2.2.0" + } + }, + "node_modules/chai": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz", + "integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==", + "dev": true, + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", + "pathval": "^1.1.1", + "type-detect": "^4.0.8" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/check-error": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "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/data-uri-to-buffer": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-2.0.2.tgz", + "integrity": "sha512-ND9qDTLc6diwj+Xe5cdAgVTbLVdXbtxTJRXRhli8Mowuaan+0EJOtdqJ0QCHNSSPyoXGx9HX2/VMnKeC34AChA==", + "dev": true + }, + "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/deep-eql": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "dev": true, + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "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, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/esbuild": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz", + "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.17.19", + "@esbuild/android-arm64": "0.17.19", + "@esbuild/android-x64": "0.17.19", + "@esbuild/darwin-arm64": "0.17.19", + "@esbuild/darwin-x64": "0.17.19", + "@esbuild/freebsd-arm64": "0.17.19", + "@esbuild/freebsd-x64": "0.17.19", + "@esbuild/linux-arm": "0.17.19", + "@esbuild/linux-arm64": "0.17.19", + "@esbuild/linux-ia32": "0.17.19", + "@esbuild/linux-loong64": "0.17.19", + "@esbuild/linux-mips64el": "0.17.19", + "@esbuild/linux-ppc64": "0.17.19", + "@esbuild/linux-riscv64": "0.17.19", + "@esbuild/linux-s390x": "0.17.19", + "@esbuild/linux-x64": "0.17.19", + "@esbuild/netbsd-x64": "0.17.19", + "@esbuild/openbsd-x64": "0.17.19", + "@esbuild/sunos-x64": "0.17.19", + "@esbuild/win32-arm64": "0.17.19", + "@esbuild/win32-ia32": "0.17.19", + "@esbuild/win32-x64": "0.17.19" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/estree-walker": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", + "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", + "dev": true + }, + "node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit-hook": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-2.2.1.tgz", + "integrity": "sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/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.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-func-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/get-source": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/get-source/-/get-source-2.0.12.tgz", + "integrity": "sha512-X5+4+iD+HoSeEED+uwrQ07BOQr0kEDFMVqqpBuI+RaZBpBpHCuXxo70bjar6f0b0u/DQJsJ7ssurpP0V60Az+w==", + "dev": true, + "dependencies": { + "data-uri-to-buffer": "^2.0.0", + "source-map": "^0.6.1" + } + }, + "node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "dev": true, + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "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-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": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "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/js-base64": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.7.tgz", + "integrity": "sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==" + }, + "node_modules/js-tokens": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-8.0.3.tgz", + "integrity": "sha512-UfJMcSJc+SEXEl9lH/VLHSZbThQyLpw1vLO1Lb+j4RWDvG3N2f7yj3PVQA3cmkTBNldJ9eFnM+xEXxHIXrYiJw==", + "dev": true + }, + "node_modules/jsonc-parser": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", + "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==", + "dev": true + }, + "node_modules/local-pkg": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.0.tgz", + "integrity": "sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==", + "dev": true, + "dependencies": { + "mlly": "^1.4.2", + "pkg-types": "^1.0.3" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/loupe": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.1" + } + }, + "node_modules/magic-string": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", + "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "dev": true, + "dependencies": { + "sourcemap-codec": "^1.4.8" + } + }, + "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/mime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/miniflare": { + "version": "3.20240314.0", + "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-3.20240314.0.tgz", + "integrity": "sha512-vjjiCEgNy4rfE8VP2C9xngT3eQY4HQg5eiXL+I845voM+6m67a7sZaGl2MspANNHXAKVi71m5bAzFgPcb2Jw9w==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "0.8.1", + "acorn": "^8.8.0", + "acorn-walk": "^8.2.0", + "capnp-ts": "^0.7.0", + "exit-hook": "^2.2.1", + "glob-to-regexp": "^0.4.1", + "stoppable": "^1.1.0", + "undici": "^5.28.2", + "workerd": "1.20240314.0", + "ws": "^8.11.0", + "youch": "^3.2.2", + "zod": "^3.20.6" + }, + "bin": { + "miniflare": "bootstrap.js" + }, + "engines": { + "node": ">=16.13" + } + }, + "node_modules/mlly": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.6.1.tgz", + "integrity": "sha512-vLgaHvaeunuOXHSmEbZ9izxPx3USsk8KCQ8iC+aTlp5sKRSoZvwhHh5L9VbKSaVC6sJDqbyohIS76E2VmHIPAA==", + "dev": true, + "dependencies": { + "acorn": "^8.11.3", + "pathe": "^1.1.2", + "pkg-types": "^1.0.3", + "ufo": "^1.3.2" + } + }, + "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/mustache": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", + "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", + "dev": true, + "bin": { + "mustache": "bin/mustache" + } + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "dev": true, + "engines": { + "node": ">= 6.13.0" + } + }, + "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": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", + "dev": true, + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-limit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-5.0.0.tgz", + "integrity": "sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/path-to-regexp": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz", + "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==", + "dev": true + }, + "node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "dev": true + }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "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/pkg-types": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.3.tgz", + "integrity": "sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==", + "dev": true, + "dependencies": { + "jsonc-parser": "^3.2.0", + "mlly": "^1.2.0", + "pathe": "^1.1.0" + } + }, + "node_modules/postcss": { + "version": "8.4.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz", + "integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "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.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/printable-characters": { + "version": "1.0.42", + "resolved": "https://registry.npmjs.org/printable-characters/-/printable-characters-1.0.42.tgz", + "integrity": "sha512-dKp+C4iXWK4vVYZmYSd0KBH5F/h1HoZRsbJ82AVKRO3PEo8L4lBS/vLwhVtpwwuYcoIsVY+1JYKR268yn480uQ==", + "dev": true + }, + "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/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.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, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/rollup": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.13.0.tgz", + "integrity": "sha512-3YegKemjoQnYKmsBlOHfMLVPPA5xLkQ8MHLLSw/fBrFaVkEayL51DilPpNNLq1exr98F2B1TzrV0FUlN3gWRPg==", + "dev": true, + "dependencies": { + "@types/estree": "1.0.5" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.13.0", + "@rollup/rollup-android-arm64": "4.13.0", + "@rollup/rollup-darwin-arm64": "4.13.0", + "@rollup/rollup-darwin-x64": "4.13.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.13.0", + "@rollup/rollup-linux-arm64-gnu": "4.13.0", + "@rollup/rollup-linux-arm64-musl": "4.13.0", + "@rollup/rollup-linux-riscv64-gnu": "4.13.0", + "@rollup/rollup-linux-x64-gnu": "4.13.0", + "@rollup/rollup-linux-x64-musl": "4.13.0", + "@rollup/rollup-win32-arm64-msvc": "4.13.0", + "@rollup/rollup-win32-ia32-msvc": "4.13.0", + "@rollup/rollup-win32-x64-msvc": "4.13.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/rollup-plugin-inject": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rollup-plugin-inject/-/rollup-plugin-inject-3.0.2.tgz", + "integrity": "sha512-ptg9PQwzs3orn4jkgXJ74bfs5vYz1NCZlSQMBUA0wKcGp5i5pA1AO3fOUEte8enhGUC+iapTCzEWw2jEFFUO/w==", + "deprecated": "This package has been deprecated and is no longer maintained. Please use @rollup/plugin-inject.", + "dev": true, + "dependencies": { + "estree-walker": "^0.6.1", + "magic-string": "^0.25.3", + "rollup-pluginutils": "^2.8.1" + } + }, + "node_modules/rollup-plugin-node-polyfills": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/rollup-plugin-node-polyfills/-/rollup-plugin-node-polyfills-0.2.1.tgz", + "integrity": "sha512-4kCrKPTJ6sK4/gLL/U5QzVT8cxJcofO0OU74tnB19F40cmuAKSzH5/siithxlofFEjwvw1YAhPmbvGNA6jEroA==", + "dev": true, + "dependencies": { + "rollup-plugin-inject": "^3.0.0" + } + }, + "node_modules/rollup-pluginutils": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", + "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", + "dev": true, + "dependencies": { + "estree-walker": "^0.6.1" + } + }, + "node_modules/selfsigned": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", + "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", + "dev": true, + "dependencies": { + "@types/node-forge": "^1.3.0", + "node-forge": "^1" + }, + "engines": { + "node": ">=10" + } + }, + "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/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "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-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "deprecated": "Please use @jridgewell/sourcemap-codec instead", + "dev": true + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true + }, + "node_modules/stacktracey": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/stacktracey/-/stacktracey-2.1.8.tgz", + "integrity": "sha512-Kpij9riA+UNg7TnphqjH7/CzctQ/owJGNbFkfEeve4Z4uxT5+JapVLFXcsurIfN34gnTWZNJ/f7NMG0E8JDzTw==", + "dev": true, + "dependencies": { + "as-table": "^1.0.36", + "get-source": "^2.0.12" + } + }, + "node_modules/std-env": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.7.0.tgz", + "integrity": "sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==", + "dev": true + }, + "node_modules/stoppable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stoppable/-/stoppable-1.1.0.tgz", + "integrity": "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==", + "dev": true, + "engines": { + "node": ">=4", + "npm": ">=6" + } + }, + "node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-literal": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-2.0.0.tgz", + "integrity": "sha512-f9vHgsCWBq2ugHAkGMiiYY+AYG0D/cbloKKg0nhaaaSNsujdGIpVXCNsrJpCKr5M0f4aI31mr13UjY6GAuXCKA==", + "dev": true, + "dependencies": { + "js-tokens": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "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/tinybench": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.6.0.tgz", + "integrity": "sha512-N8hW3PG/3aOoZAN5V/NSAEDz0ZixDSSt5b/a05iqtpgfLWMSVuCo7w0k2vVvEjdrIoeGqZzweX2WlyioNIHchA==", + "dev": true + }, + "node_modules/tinypool": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.8.2.tgz", + "integrity": "sha512-SUszKYe5wgsxnNOVlBYO6IC+8VGWdVGZWAqUxp3UErNBtptZvWbwyUOyzNL59zigz2rCA92QiL3wvG+JDSdJdQ==", + "dev": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.2.1.tgz", + "integrity": "sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==", + "dev": true, + "engines": { + "node": ">=14.0.0" + } + }, + "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/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, + "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/typescript": { + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz", + "integrity": "sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/ufo": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.4.0.tgz", + "integrity": "sha512-Hhy+BhRBleFjpJ2vchUNN40qgkh0366FWJGqVLYBHev0vpHTrXSA0ryT+74UiW6KWsldNurQMKGqCm1M2zBciQ==", + "dev": true + }, + "node_modules/undici": { + "version": "5.28.3", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.3.tgz", + "integrity": "sha512-3ItfzbrhDlINjaP0duwnNsKpDQk3acHI3gVJ1z4fmwMK31k5G9OVIAMLSIaP6w4FaGkaAkN6zaQO9LUvZ1t7VA==", + "dev": true, + "dependencies": { + "@fastify/busboy": "^2.0.0" + }, + "engines": { + "node": ">=14.0" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/vite": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.1.6.tgz", + "integrity": "sha512-yYIAZs9nVfRJ/AiOLCA91zzhjsHUgMjB+EigzFb6W2XTLO8JixBCKCjvhKZaye+NKYHCrkv3Oh50dH9EdLU2RA==", + "dev": true, + "dependencies": { + "esbuild": "^0.19.3", + "postcss": "^8.4.35", + "rollup": "^4.2.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vite-node": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.3.1.tgz", + "integrity": "sha512-azbRrqRxlWTJEVbzInZCTchx0X69M/XPTCz4H+TLvlTcR/xH/3hkRqhOakT41fMJCMzXTu4UvegkZiEoJAWvng==", + "dev": true, + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.3.4", + "pathe": "^1.1.1", + "picocolors": "^1.0.0", + "vite": "^5.0.0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vite/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/vite/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/vite/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/vite/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/vite/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/vite/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/vite/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/vite/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/vite/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/vite/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/vite/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/vite/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/vite/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/vite/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/vite/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/vite/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/vite/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/vite/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/vite/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/vite/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/vite/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/vite/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/vite/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/vitest": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.3.1.tgz", + "integrity": "sha512-/1QJqXs8YbCrfv/GPQ05wAZf2eakUPLPa18vkJAKE7RXOKfVHqMZZ1WlTjiwl6Gcn65M5vpNUB6EFLnEdRdEXQ==", + "dev": true, + "dependencies": { + "@vitest/expect": "1.3.1", + "@vitest/runner": "1.3.1", + "@vitest/snapshot": "1.3.1", + "@vitest/spy": "1.3.1", + "@vitest/utils": "1.3.1", + "acorn-walk": "^8.3.2", + "chai": "^4.3.10", + "debug": "^4.3.4", + "execa": "^8.0.1", + "local-pkg": "^0.5.0", + "magic-string": "^0.30.5", + "pathe": "^1.1.1", + "picocolors": "^1.0.0", + "std-env": "^3.5.0", + "strip-literal": "^2.0.0", + "tinybench": "^2.5.1", + "tinypool": "^0.8.2", + "vite": "^5.0.0", + "vite-node": "1.3.1", + "why-is-node-running": "^2.2.2" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/node": "^18.0.0 || >=20.0.0", + "@vitest/browser": "1.3.1", + "@vitest/ui": "1.3.1", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/vitest/node_modules/magic-string": { + "version": "0.30.8", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz", + "integrity": "sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + }, + "engines": { + "node": ">=12" + } + }, + "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/why-is-node-running": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.2.2.tgz", + "integrity": "sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==", + "dev": true, + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/workerd": { + "version": "1.20240314.0", + "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20240314.0.tgz", + "integrity": "sha512-5vXqDe6vJTMpfPVW8Vtcy2zcVIBnOIMv0D+Z0gVPMPq++KwEyQWzCIVLpIyc28EUc5bW3gEO49E8BN1PQebgfw==", + "dev": true, + "hasInstallScript": true, + "bin": { + "workerd": "bin/workerd" + }, + "engines": { + "node": ">=16" + }, + "optionalDependencies": { + "@cloudflare/workerd-darwin-64": "1.20240314.0", + "@cloudflare/workerd-darwin-arm64": "1.20240314.0", + "@cloudflare/workerd-linux-64": "1.20240314.0", + "@cloudflare/workerd-linux-arm64": "1.20240314.0", + "@cloudflare/workerd-windows-64": "1.20240314.0" + } + }, + "node_modules/wrangler": { + "version": "3.36.0", + "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-3.36.0.tgz", + "integrity": "sha512-Fywf9RGAePIuIDcsSg4BW+lDUZX1jh2jN+TtmZOwG5Ewdr9dJGP3dxoFa85eQQZP1VLvY4lsqrKy67JqOuP9Gw==", + "dev": true, + "dependencies": { + "@cloudflare/kv-asset-handler": "0.3.1", + "@esbuild-plugins/node-globals-polyfill": "^0.2.3", + "@esbuild-plugins/node-modules-polyfill": "^0.2.2", + "blake3-wasm": "^2.1.5", + "chokidar": "^3.5.3", + "esbuild": "0.17.19", + "miniflare": "3.20240314.0", + "nanoid": "^3.3.3", + "path-to-regexp": "^6.2.0", + "resolve": "^1.22.8", + "resolve.exports": "^2.0.2", + "selfsigned": "^2.0.1", + "source-map": "0.6.1", + "xxhash-wasm": "^1.0.1" + }, + "bin": { + "wrangler": "bin/wrangler.js", + "wrangler2": "bin/wrangler.js" + }, + "engines": { + "node": ">=16.17.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + }, + "peerDependencies": { + "@cloudflare/workers-types": "^4.20230914.0" + }, + "peerDependenciesMeta": { + "@cloudflare/workers-types": { + "optional": true + } + } + }, + "node_modules/ws": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", + "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xxhash-wasm": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/xxhash-wasm/-/xxhash-wasm-1.0.2.tgz", + "integrity": "sha512-ibF0Or+FivM9lNrg+HGJfVX8WJqgo+kCLDc4vx6xMeTce7Aj+DLttKbxxRR/gNLSAelRc1omAPlJ77N/Jem07A==", + "dev": true + }, + "node_modules/yocto-queue": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", + "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", + "dev": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/youch": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/youch/-/youch-3.3.3.tgz", + "integrity": "sha512-qSFXUk3UZBLfggAW3dJKg0BMblG5biqSF8M34E06o5CSsZtH92u9Hqmj2RzGiHDi64fhe83+4tENFP2DB6t6ZA==", + "dev": true, + "dependencies": { + "cookie": "^0.5.0", + "mustache": "^4.2.0", + "stacktracey": "^2.1.8" + } + }, + "node_modules/zod": { + "version": "3.22.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz", + "integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + } +} diff --git a/ts/sbd-server/package.json b/ts/sbd-server/package.json new file mode 100644 index 0000000..8ecf136 --- /dev/null +++ b/ts/sbd-server/package.json @@ -0,0 +1,28 @@ +{ + "name": "tx5-signal-cf", + "version": "0.0.0", + "private": true, + "scripts": { + "deploy": "wrangler deploy", + "dev": "wrangler dev", + "start": "wrangler dev", + "test:fmt": "prettier -w src", + "test:type": "tsc --noEmit", + "test:unit": "vitest run", + "test": "npm run test:fmt && npm run test:type && npm run test:unit" + }, + "devDependencies": { + "@cloudflare/workers-types": "^4.20240312.0", + "@types/ws": "^8.5.10", + "prettier": "^3.2.5", + "typescript": "^5.0.4", + "vitest": "^1.3.1", + "wrangler": "^3.36.0", + "ws": "^8.16.0" + }, + "dependencies": { + "@noble/ed25519": "^2.0.0", + "@noble/hashes": "^1.4.0", + "js-base64": "^3.7.7" + } +} diff --git a/ts/sbd-server/src/b64.ts b/ts/sbd-server/src/b64.ts new file mode 100644 index 0000000..5dfb4a0 --- /dev/null +++ b/ts/sbd-server/src/b64.ts @@ -0,0 +1,12 @@ +import { fromUint8Array, toUint8Array } from 'js-base64'; + +export function toB64Url(s: Uint8Array): string { + return fromUint8Array(s) + .replace(/\=/g, '') + .replace(/\+/g, '-') + .replace(/\//g, '_'); +} + +export function fromB64Url(s: string): Uint8Array { + return toUint8Array(s.replace(/\-/g, '+').replace(/\_/g, '/')); +} diff --git a/ts/sbd-server/src/ed.ts b/ts/sbd-server/src/ed.ts new file mode 100644 index 0000000..2883b1b --- /dev/null +++ b/ts/sbd-server/src/ed.ts @@ -0,0 +1,4 @@ +import * as ed from '@noble/ed25519'; +import { sha512 } from '@noble/hashes/sha512'; +ed.etc.sha512Sync = (...m) => sha512(ed.etc.concatBytes(...m)); +export { ed }; diff --git a/ts/sbd-server/src/err.ts b/ts/sbd-server/src/err.ts new file mode 100644 index 0000000..bed0dbc --- /dev/null +++ b/ts/sbd-server/src/err.ts @@ -0,0 +1,11 @@ +interface AddStatus { + status: number; +} + +type StatusError = Error & AddStatus; + +export function err(e: string, s?: number): StatusError { + const out: any = new Error(e); + out.status = s || 500; + return out; +} diff --git a/ts/sbd-server/src/index.test.ts b/ts/sbd-server/src/index.test.ts new file mode 100644 index 0000000..887fb9f --- /dev/null +++ b/ts/sbd-server/src/index.test.ts @@ -0,0 +1,149 @@ +import { unstable_dev } from 'wrangler'; +import type { UnstableDevWorker } from 'wrangler'; +import { describe, expect, assert, it, beforeAll, afterAll } from 'vitest'; +import WebSocket from 'ws'; +import { ed } from './ed.ts'; +import { encodeQuery, encodeSignedQuery } from './msg.ts'; + +type RecvFunction = (msg: Array) => void; + +// helper class for client websocket testing +class C { + ws: WebSocket; + sk: Uint8Array; + pk: Uint8Array; + pend: Array; + res: RecvFunction | null; + closing: boolean; + + constructor(sk: Uint8Array, pk: Uint8Array, ws: WebSocket) { + this.sk = sk; + this.pk = pk; + this.ws = ws; + this.pend = []; + this.res = null; + this.closing = false; + } + + static connect(addr: string): Promise { + return new Promise((res, _) => { + const sk = ed.utils.randomPrivateKey(); + const pk = ed.getPublicKey(sk); + const q = encodeQuery({ + nodePubKey: pk, + nonce: Date.now(), + }); + const s = ed.sign(new TextEncoder().encode(q), sk); + const sq = encodeSignedQuery(s, q); + + const ws = new WebSocket(`ws://${addr}/?${sq}`); + const out = new C(sk, pk, ws); + + ws.on('error', (err) => { + console.error(`error: ${err}`); + throw err; + }); + ws.on('open', async () => { + const list = await out.recv(); + if (list.length !== 1) { + throw new Error('invalid recv length'); + } + const nonce = list[0]; + const handshake = ed.sign(nonce, out.sk); + await out._send(handshake); + res(out); + }); + ws.on('close', (code, reason) => { + if (!out.closing) { + const v = `close code ${code} reason ${reason}`; + console.error(v); + throw new Error(v); + } + }); + ws.on('message', (msg) => { + if (!(msg instanceof Uint8Array)) { + throw new Error('invalid rcv message type'); + } + out.pend.push(msg); + if (out.res) { + const res = out.res; + out.res = null; + res(out.pend.splice(0)); + } + }); + }); + } + + close() { + this.closing = true; + this.ws.close(); + } + + pubKey(): Uint8Array { + return this.pk; + } + + _send(data: Uint8Array): Promise { + return new Promise((res, _) => { + this.ws.send(data, {}, (e: any) => { + if (e) { + throw e; + } + res(null); + }); + }); + } + + async send(peer: Uint8Array, data: string) { + const enc = new TextEncoder().encode(data); + const out = new Uint8Array(peer.byteLength + enc.byteLength); + out.set(peer); + out.set(enc, peer.byteLength); + await this.ws.send(out); + } + + recv(): Promise> { + if (this.pend.length) { + return Promise.resolve(this.pend.splice(0)); + } + return new Promise((res, _) => { + this.res = res; + }); + } +} + +describe('Worker', () => { + let worker: UnstableDevWorker; + let addr: string; + + beforeAll(async () => { + worker = await unstable_dev('src/index.ts'); + addr = worker.address + ':' + worker.port; + }); + + afterAll(async () => { + await worker.stop(); + }); + + it('now', async () => { + const res = await worker.fetch('http://' + addr + '/now'); + const json = (await res.json()) as { now: number }; + expect(json.now).to.be.above(Date.now() - 5000); + expect(json.now).to.be.below(Date.now() + 5000); + }); + + it('websocket', async () => { + const wsA = await C.connect(addr); + const wsB = await C.connect(addr); + + const recvPromiseA = wsA.recv(); + await wsB.send(wsA.pubKey(), 'test'); + const result = (await recvPromiseA)[0]; + + wsA.close(); + wsB.close(); + + expect(new Uint8Array(result).subarray(0, 32)).toEqual(wsB.pubKey()); + expect(new TextDecoder().decode(result.subarray(32))).toEqual('test'); + }); +}); diff --git a/ts/sbd-server/src/index.ts b/ts/sbd-server/src/index.ts new file mode 100644 index 0000000..8d2b97d --- /dev/null +++ b/ts/sbd-server/src/index.ts @@ -0,0 +1,272 @@ +/** + * This is currently a PoC, but working towards something production ready. + * + * What we need to do: + * + * - batching: clients should batch requests for a number of milliseconds, + * sending within say 5ms if no additional messages are received, but never + * more than 20ms after the first received message. one batch should not + * exceed some byte count... 4096? + * - signing: nodes will be identified by an ed25519 pub key, messages + * will be individually signed, like: + * `["sig-base64","[\"fwd\",42,\"dest-base64\",\"msg-content\"]"]` + * - websocket hello: to verify the client can sign with that pubkey + * must be received within some milliseconds of establishing the ws connection + * set a DO "alarm"? + * `["sig-base64","[\"hello\",0]"]` + * - error if multiple websockets connected to one pubkey do + * - ratelimit messages within a single do instance + * - ratelimit messages (at larger rate) for an ip + * - nonce/message id must be zero for the hello message + * - nonce/message id must start at 1 for each peer communicated with + * and increment by exactly 1 for each additional message sent. + * we will need to maintain a map of these peer message ids that + * must be reset/cleared if the websocket is closed. + */ + +import { RateLimit } from './rate-limit.ts'; +import { verifySignedQuery, verifySignedHandshake } from './msg.ts'; +import { err } from './err.ts'; +import { toB64Url, fromB64Url } from './b64.ts'; + +export interface Env { + SIGNAL: DurableObjectNamespace; + RATE_LIMIT: DurableObjectNamespace; +} + +async function ipRateLimit(env: Env, ip: string) { + try { + const ipId = env.RATE_LIMIT.idFromName(ip); + const ipStub = env.RATE_LIMIT.get(ipId); + const res = await ipStub.fetch(new Request(`http://do`)); + if (res.status !== 200) { + throw err(`limit bad status ${res.status}`, 429); + } + const { limit } = (await res.json()) as { limit: number }; + if (limit > 0) { + throw err(`limit ${limit}`, 429); + } + } catch (e) { + throw err(`limit ${e}`, 429); + } +} + +function checkNonce(nonce: number) { + const now = Date.now(); + if (nonce < now - 5000) { + throw err('nonce older than 5 sec, update clock, or call /now', 400); + } + if (nonce > now + 5000) { + throw err('nonce newer than 5 sec, update clock, or call /now', 400); + } +} + +export default { + async fetch( + request: Request, + env: Env, + ctx: ExecutionContext, + ): Promise { + try { + const ip = request.headers.get('cf-connecting-ip') || 'no-ip'; + + await ipRateLimit(env, ip); + + const method = request.method; + const url = new URL(request.url); + + // @ts-expect-error // cf typescript bug // + const path: string = url.pathname; + + // TODO - check headers for content-length / chunked encoding and reject? + + if (method !== 'GET') { + throw err('expected GET', 400); + } + + if (path === '/now') { + return Response.json({ now: Date.now() }); + } + + if (path !== '/') { + throw err('expected root path ("/")', 400); + } + + // @ts-expect-error // cf typescript bug // + const nodeId: string = url.searchParams.get('k'); + // @ts-expect-error // cf typescript bug // + const n: string = url.searchParams.get('n'); + // @ts-expect-error // cf typescript bug // + const s: string = url.searchParams.get('s'); + + const q = verifySignedQuery(nodeId, n, s); + checkNonce(q.nonce); + + // DO instanced by our nodeId + const id = env.SIGNAL.idFromName(nodeId); + const stub = env.SIGNAL.get(id); + + // just forward the full request / response + return await stub.fetch(request); + } catch (e: any) { + return new Response(JSON.stringify({ err: e.toString() }), { + status: e.status || 500, + }); + } + }, +}; + +export class DoRateLimit implements DurableObject { + state: DurableObjectState; + env: Env; + rl: RateLimit; + + constructor(state: DurableObjectState, env: Env) { + this.state = state; + this.env = env; + this.rl = new RateLimit(5000); + } + + async fetch(request: Request): Promise { + return Response.json({ limit: this.rl.trackRequest(Date.now(), 1) }); + } +} + +export class DoSignal implements DurableObject { + state: DurableObjectState; + env: Env; + rl: RateLimit; + + constructor(state: DurableObjectState, env: Env) { + this.state = state; + this.env = env; + this.rl = new RateLimit(5000); + } + + async fetch(request: Request): Promise { + return await this.state.blockConcurrencyWhile(async () => { + try { + const ip = request.headers.get('cf-connecting-ip') || 'no-ip'; + const url = new URL(request.url); + // @ts-expect-error // cf typescript bug // + const path: string = url.pathname; + + if (path === '/fwd') { + const message = await request.arrayBuffer(); + for (const ws of this.state.getWebSockets()) { + ws.send(message); + } + return new Response('ok'); + } else if (path === '/') { + if (this.state.getWebSockets().length > 0) { + throw err('websocket already connected', 400); + } + if (request.headers.get('Upgrade') !== 'websocket') { + throw err('expected websocket', 426); + } + + const [client, server] = Object.values(new WebSocketPair()); + + this.state.acceptWebSocket(server); + + const nonce = new Uint8Array(32); + crypto.getRandomValues(nonce); + + // @ts-expect-error // cf typescript bug // + const nodeId = fromB64Url(url.searchParams.get('k')); + + server.serializeAttachment({ + nodeId, + ip, + nonce, + valid: false, + }); + + server.send(nonce); + + return new Response(null, { status: 101, webSocket: client }); + } else { + throw err('invalid path', 400); + } + } catch (e: any) { + return new Response(JSON.stringify({ err: e.toString() }), { + status: e.status || 500, + }); + } + }); + } + + // handle incoming websocket messages + async webSocketMessage(ws: WebSocket, message: ArrayBuffer | string) { + await this.state.blockConcurrencyWhile(async () => { + try { + const { nodeId, ip, nonce, valid } = ws.deserializeAttachment(); + if (!nodeId) { + throw err('no associated nodeId'); + } + if (!ip) { + throw err('no associated ip'); + } + + await ipRateLimit(this.env, ip); + + if (this.rl.trackRequest(Date.now(), 20) > 0) { + throw err('rate limit', 429); + } + + // convert strings into binary + let msg: Uint8Array; + if (message instanceof ArrayBuffer) { + msg = new Uint8Array(message); + } else { + const enc = new TextEncoder(); + msg = enc.encode(message); + } + + if (!valid) { + if (!nonce) { + throw err('no associated nonce'); + } + verifySignedHandshake(nodeId, nonce, msg); + ws.serializeAttachment({ + nodeId, + ip, + nonce: true, // don't need to keep the actual nonce anymore + valid: true, + }); + } else { + if (msg.byteLength < 32) { + throw err('invalid destination', 400); + } + + const dest = new Uint8Array(32); + dest.set(msg.subarray(0, 32)); + msg.set(nodeId); + + const req = new Request('http://do/fwd', { + method: 'POST', + body: msg, + }); + + const id = this.env.SIGNAL.idFromName(toB64Url(dest)); + const stub = this.env.SIGNAL.get(id); + + // intentionally ignore errors here + await stub.fetch(req); + } + } catch (e: any) { + ws.close(4000 + (e.status || 500), e.toString()); + } + }); + } + + // if the websocket is closed... close the websocket?? + async webSocketClose( + ws: WebSocket, + code: number, + reason: string, + wasClean: boolean, + ) { + ws.close(code, reason); + } +} diff --git a/ts/sbd-server/src/msg.test.ts b/ts/sbd-server/src/msg.test.ts new file mode 100644 index 0000000..3952176 --- /dev/null +++ b/ts/sbd-server/src/msg.test.ts @@ -0,0 +1,30 @@ +import { describe, expect, assert, it, beforeAll, afterAll } from 'vitest'; +import { encodeQuery, encodeSignedQuery, verifySignedQuery } from './msg.ts'; +import { ed } from './ed.ts'; + +describe('Msg', () => { + it('query safe', async () => { + for (let i = 0; i < 100; ++i) { + const sk = ed.utils.randomPrivateKey(); + const pk = ed.getPublicKey(sk); + + const q = encodeQuery({ + nodePubKey: pk, + nonce: Date.now(), + }); + + const s = ed.sign(new TextEncoder().encode(q), sk); + + const sq = new URL('none:?' + encodeSignedQuery(s, q)); + + // @ts-expect-error // cf typescript bug // + const ddk: string = sq.searchParams.get('k'); + // @ts-expect-error // cf typescript bug // + const ddn: string = sq.searchParams.get('n'); + // @ts-expect-error // cf typescript bug // + const dds: string = sq.searchParams.get('s'); + + verifySignedQuery(ddk, ddn, dds); + } + }); +}); diff --git a/ts/sbd-server/src/msg.ts b/ts/sbd-server/src/msg.ts new file mode 100644 index 0000000..c615831 --- /dev/null +++ b/ts/sbd-server/src/msg.ts @@ -0,0 +1,47 @@ +import { ed } from './ed.ts'; +import { err } from './err.ts'; +import { toB64Url, fromB64Url } from './b64.ts'; + +interface Query { + nodePubKey: Uint8Array; + nonce: number; +} + +export function encodeQuery(query: Query): string { + const k = toB64Url(query.nodePubKey); + return `k=${k}&n=${query.nonce}`; +} + +export function encodeSignedQuery( + signature: Uint8Array, + query: string, +): string { + const s = toB64Url(signature); + return `${query}&s=${s}`; +} + +export function verifySignedQuery(k: string, n: string, s: string): Query { + const query = { + nodePubKey: fromB64Url(k), + nonce: parseFloat(n), + }; + const enc = new TextEncoder().encode(encodeQuery(query)); + const sig = fromB64Url(s); + if (!ed.verify(sig, enc, query.nodePubKey)) { + throw err('invalid query signature', 400); + } + return query; +} + +export function verifySignedHandshake( + pk: Uint8Array, + nonce: Uint8Array, + sig: Uint8Array, +) { + if (sig.byteLength !== 64) { + throw err(`invalid signature length ${sig.byteLength}`, 400); + } + if (!ed.verify(sig, nonce, pk)) { + throw err('invalid handshake signature', 400); + } +} diff --git a/ts/sbd-server/src/rate-limit.test.ts b/ts/sbd-server/src/rate-limit.test.ts new file mode 100644 index 0000000..206def9 --- /dev/null +++ b/ts/sbd-server/src/rate-limit.test.ts @@ -0,0 +1,24 @@ +import { describe, expect, assert, it, beforeAll, afterAll } from 'vitest'; +import { RateLimit } from './rate-limit.ts'; + +describe('RateLimit', () => { + it('allows steady rate', async () => { + const rl = new RateLimit(10); + for (let now = 0; now < 1000; ++now) { + expect(rl.trackRequest(now, 1)).toEqual(0); + } + }); + + it('burst', async () => { + let now = 100; + const rl = new RateLimit(10); + for (let i = 0; i < 10; ++i) { + expect(rl.trackRequest(now, 1)).toEqual(0); + } + expect(rl.trackRequest(now, 1)).toEqual(1); + now += 1; + expect(rl.trackRequest(now, 1)).toEqual(1); + now += 2; + expect(rl.trackRequest(now, 1)).toEqual(0); + }); +}); diff --git a/ts/sbd-server/src/rate-limit.ts b/ts/sbd-server/src/rate-limit.ts new file mode 100644 index 0000000..80f360c --- /dev/null +++ b/ts/sbd-server/src/rate-limit.ts @@ -0,0 +1,16 @@ +export class RateLimit { + gracePeriodMs: number; + nextAllowedTime: number; + + constructor(gracePeriodMs: number) { + this.gracePeriodMs = gracePeriodMs; + this.nextAllowedTime = 0; + } + + trackRequest(now: number, reqWeightMs: number): number { + this.nextAllowedTime = Math.max(now, this.nextAllowedTime); + this.nextAllowedTime += reqWeightMs; + + return Math.max(0, this.nextAllowedTime - now - this.gracePeriodMs); + } +} diff --git a/ts/sbd-server/tsconfig.json b/ts/sbd-server/tsconfig.json new file mode 100644 index 0000000..38f988f --- /dev/null +++ b/ts/sbd-server/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "es2021", + "lib": ["es2021"], + "module": "es2022", + "moduleResolution": "node", + "types": [ + "@cloudflare/workers-types/2023-07-01" + ], + "resolveJsonModule": true, + "allowImportingTsExtensions": true, + "allowJs": true, + "checkJs": false, + "noEmit": true, + "isolatedModules": true, + "allowSyntheticDefaultImports": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true + } +} diff --git a/ts/sbd-server/wrangler.toml b/ts/sbd-server/wrangler.toml new file mode 100644 index 0000000..d412c9f --- /dev/null +++ b/ts/sbd-server/wrangler.toml @@ -0,0 +1,15 @@ +name = "tx5-signal-cf" +main = "src/index.ts" +compatibility_date = "2024-03-12" + +[[durable_objects.bindings]] +name = "SIGNAL" +class_name = "DoSignal" + +[[durable_objects.bindings]] +name = "RATE_LIMIT" +class_name = "DoRateLimit" + +[[migrations]] +tag = "v1" +new_classes = ["DoSignal", "DoRateLimit"] From 3d29dd906b16d95c725a6162ce35d27de7b77d20 Mon Sep 17 00:00:00 2001 From: neonphog Date: Tue, 18 Jun 2024 14:55:55 -0600 Subject: [PATCH 02/36] make test --- .github/workflows/test.yml | 8 ++++---- Makefile | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 73535a4..970ccc1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -50,16 +50,16 @@ jobs: manifest-dir: ${{ github.workspace }}/.github/manifest github-binarycache: true - - name: Cargo Test Windows + - name: Test Windows if: matrix.os == 'windows-latest' env: RUST_BACKTRACE: 1 run: |- $env:SODIUM_LIB_DIR="$(pwd)\vcpkg\packages\libsodium_x64-windows-release\lib" - cargo build --all-targets && cargo test -- --nocapture + make test - - name: Cargo Test + - name: Test if: matrix.os != 'windows-latest' env: RUST_BACKTRACE: 1 - run: cargo build --all-targets && cargo test -- --nocapture + run: make test diff --git a/Makefile b/Makefile index b456e1d..5f2cf7d 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,10 @@ # sbd Makefile -.PHONY: all publish-all publish bump test static +.PHONY: default publish-all publish bump test static SHELL = /usr/bin/env sh -eu -all: test +default: static test publish-all: $(MAKE) publish crate=sbd-client @@ -53,7 +53,7 @@ bump: fi sed -i 's/^\(sbd[^=]*= { \|\)version = "[^"]*"/\1version = "$(ver)"/g' $$(find . -name Cargo.toml) -test: static +test: cargo build --all-targets RUST_BACKTRACE=1 cargo test cd ts/sbd-server && npm ci From 79f9174194475564975029c0e48ce03e5d59008d Mon Sep 17 00:00:00 2001 From: neonphog Date: Tue, 18 Jun 2024 15:08:15 -0600 Subject: [PATCH 03/36] update deps --- ts/sbd-server/package-lock.json | 664 ++++++++++++++++++-------------- ts/sbd-server/package.json | 14 +- ts/sbd-server/src/index.ts | 2 - ts/sbd-server/wrangler.toml | 2 +- 4 files changed, 378 insertions(+), 304 deletions(-) diff --git a/ts/sbd-server/package-lock.json b/ts/sbd-server/package-lock.json index 9d32b3f..dd01631 100644 --- a/ts/sbd-server/package-lock.json +++ b/ts/sbd-server/package-lock.json @@ -8,33 +8,36 @@ "name": "tx5-signal-cf", "version": "0.0.0", "dependencies": { - "@noble/ed25519": "^2.0.0", + "@noble/ed25519": "^2.1.0", "@noble/hashes": "^1.4.0", "js-base64": "^3.7.7" }, "devDependencies": { - "@cloudflare/workers-types": "^4.20240312.0", + "@cloudflare/workers-types": "^4.20240614.0", "@types/ws": "^8.5.10", - "prettier": "^3.2.5", - "typescript": "^5.0.4", - "vitest": "^1.3.1", - "wrangler": "^3.36.0", - "ws": "^8.16.0" + "prettier": "^3.3.2", + "typescript": "^5.4.5", + "vitest": "^1.6.0", + "wrangler": "^3.61.0", + "ws": "^8.17.1" } }, "node_modules/@cloudflare/kv-asset-handler": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.3.1.tgz", - "integrity": "sha512-lKN2XCfKCmpKb86a1tl4GIwsJYDy9TGuwjhDELLmpKygQhw8X2xR4dusgpC5Tg7q1pB96Eb0rBo81kxSILQMwA==", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.3.3.tgz", + "integrity": "sha512-wpE+WiWW2kUNwNE0xyl4CtTAs+STjGtouHGiZPGRaisGB7eXXdbvfZdOrQJQVKgTxZiNAgVgmc7fj0sUmd8zyA==", "dev": true, "dependencies": { "mime": "^3.0.0" + }, + "engines": { + "node": ">=16.13" } }, "node_modules/@cloudflare/workerd-darwin-64": { - "version": "1.20240314.0", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20240314.0.tgz", - "integrity": "sha512-19xW64AmkjGnp9ZSwa5RPMTBJ0eqadY/oLs3RcdC8J+R8vT766U2bgxyuf3VATlOf+T7t28aGYzW/QcBRls9eg==", + "version": "1.20240610.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20240610.1.tgz", + "integrity": "sha512-YanZ1iXgMGaUWlleB5cswSE6qbzyjQ8O7ENWZcPAcZZ6BfuL7q3CWi0t9iM1cv2qx92rRztsRTyjcfq099++XQ==", "cpu": [ "x64" ], @@ -48,9 +51,9 @@ } }, "node_modules/@cloudflare/workerd-darwin-arm64": { - "version": "1.20240314.0", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20240314.0.tgz", - "integrity": "sha512-gq78D30GlNSg55YRzCzNHPuLp87L7xmYCYa5hIuIE7xpqhqGN6FV/mRtp2TQ5VoDXiuq1F+VdEZDwQFvrNAvtg==", + "version": "1.20240610.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20240610.1.tgz", + "integrity": "sha512-bRe/y/LKjIgp3L2EHjc+CvoCzfHhf4aFTtOBkv2zW+VToNJ4KlXridndf7LvR9urfsFRRo9r4TXCssuKaU+ypQ==", "cpu": [ "arm64" ], @@ -64,9 +67,9 @@ } }, "node_modules/@cloudflare/workerd-linux-64": { - "version": "1.20240314.0", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20240314.0.tgz", - "integrity": "sha512-1PYddg+lGGOUkXNt3LEHB0GvIBWjilTNwmbacGyyVRm+zaWGKqt2bS3bW/TY6cHJ1lxFe/fDMrQOgnSBB7jGIw==", + "version": "1.20240610.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20240610.1.tgz", + "integrity": "sha512-2zDcadR7+Gs9SjcMXmwsMji2Xs+yASGNA2cEHDuFc4NMUup+eL1mkzxc/QzvFjyBck98e92rBjMZt2dVscpGKg==", "cpu": [ "x64" ], @@ -80,9 +83,9 @@ } }, "node_modules/@cloudflare/workerd-linux-arm64": { - "version": "1.20240314.0", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20240314.0.tgz", - "integrity": "sha512-GIyyO+TKYQ7TsM/DgpoHP2uQrJuPEc/cpRaXYeOzHerGAdQRej6iS2+LAnTJgLTXgOC4DE622mKBL3tnZvuKVQ==", + "version": "1.20240610.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20240610.1.tgz", + "integrity": "sha512-7y41rPi5xmIYJN8CY+t3RHnjLL0xx/WYmaTd/j552k1qSr02eTE2o/TGyWZmGUC+lWnwdPQJla0mXbvdqgRdQg==", "cpu": [ "arm64" ], @@ -96,9 +99,9 @@ } }, "node_modules/@cloudflare/workerd-windows-64": { - "version": "1.20240314.0", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20240314.0.tgz", - "integrity": "sha512-NWZeVXEXJfPuLAXfMTiFusJNOMnsHkBae0C4hlqzwIzYiQ0PYnQ+BEWFS5eWy5dZihhFrsW3VRYqnTbgESIkzw==", + "version": "1.20240610.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20240610.1.tgz", + "integrity": "sha512-B0LyT3DB6rXHWNptnntYHPaoJIy0rXnGfeDBM3nEVV8JIsQrx8MEFn2F2jYioH1FkUVavsaqKO/zUosY3tZXVA==", "cpu": [ "x64" ], @@ -112,9 +115,9 @@ } }, "node_modules/@cloudflare/workers-types": { - "version": "4.20240312.0", - "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20240312.0.tgz", - "integrity": "sha512-tpBNfijiXR/DSZkcUZHxP+80nIvKUWbGO2u4FBLudmJLGPhzgfoQ3tql+FeIhxYslSituMcVQNnJmWTF7FjURg==", + "version": "4.20240614.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20240614.0.tgz", + "integrity": "sha512-fnV3uXD1Hpq5EWnY7XYb+smPcjzIoUFiZpTSV/Tk8qKL3H+w6IqcngZwXQBZ/2U/DwYkDilXHW3FfPhnyD7FZA==", "dev": true }, "node_modules/@cspotcode/source-map-support": { @@ -152,9 +155,9 @@ } }, "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==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", "cpu": [ "ppc64" ], @@ -566,15 +569,12 @@ } }, "node_modules/@noble/ed25519": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@noble/ed25519/-/ed25519-2.0.0.tgz", - "integrity": "sha512-/extjhkwFupyopDrt80OMWKdLgP429qLZj+z6sYJz90rF2Iz0gjZh2ArMKPImUl13Kx+0EXI2hN9T/KJV0/Zng==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ] + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@noble/ed25519/-/ed25519-2.1.0.tgz", + "integrity": "sha512-KM4qTyXPinyCgMzeYJH/UudpdL+paJXtY3CHtHYZQtBkS8MZoPr4rOikZllIutJe0d06QDQKisyn02gxZ8TcQA==", + "funding": { + "url": "https://paulmillr.com/funding/" + } }, "node_modules/@noble/hashes": { "version": "1.4.0", @@ -588,9 +588,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.13.0.tgz", - "integrity": "sha512-5ZYPOuaAqEH/W3gYsRkxQATBW3Ii1MfaT4EQstTnLKViLi2gLSQmlmtTpGucNP3sXEpOiI5tdGhjdE111ekyEg==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.0.tgz", + "integrity": "sha512-Tya6xypR10giZV1XzxmH5wr25VcZSncG0pZIjfePT0OVBvqNEurzValetGNarVrGiq66EBVAFn15iYX4w6FKgQ==", "cpu": [ "arm" ], @@ -601,9 +601,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.13.0.tgz", - "integrity": "sha512-BSbaCmn8ZadK3UAQdlauSvtaJjhlDEjS5hEVVIN3A4bbl3X+otyf/kOJV08bYiRxfejP3DXFzO2jz3G20107+Q==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.18.0.tgz", + "integrity": "sha512-avCea0RAP03lTsDhEyfy+hpfr85KfyTctMADqHVhLAF3MlIkq83CP8UfAHUssgXTYd+6er6PaAhx/QGv4L1EiA==", "cpu": [ "arm64" ], @@ -614,9 +614,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.13.0.tgz", - "integrity": "sha512-Ovf2evVaP6sW5Ut0GHyUSOqA6tVKfrTHddtmxGQc1CTQa1Cw3/KMCDEEICZBbyppcwnhMwcDce9ZRxdWRpVd6g==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.18.0.tgz", + "integrity": "sha512-IWfdwU7KDSm07Ty0PuA/W2JYoZ4iTj3TUQjkVsO/6U+4I1jN5lcR71ZEvRh52sDOERdnNhhHU57UITXz5jC1/w==", "cpu": [ "arm64" ], @@ -627,9 +627,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.13.0.tgz", - "integrity": "sha512-U+Jcxm89UTK592vZ2J9st9ajRv/hrwHdnvyuJpa5A2ngGSVHypigidkQJP+YiGL6JODiUeMzkqQzbCG3At81Gg==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.18.0.tgz", + "integrity": "sha512-n2LMsUz7Ynu7DoQrSQkBf8iNrjOGyPLrdSg802vk6XT3FtsgX6JbE8IHRvposskFm9SNxzkLYGSq9QdpLYpRNA==", "cpu": [ "x64" ], @@ -640,9 +640,22 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.13.0.tgz", - "integrity": "sha512-8wZidaUJUTIR5T4vRS22VkSMOVooG0F4N+JSwQXWSRiC6yfEsFMLTYRFHvby5mFFuExHa/yAp9juSphQQJAijQ==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.18.0.tgz", + "integrity": "sha512-C/zbRYRXFjWvz9Z4haRxcTdnkPt1BtCkz+7RtBSuNmKzMzp3ZxdM28Mpccn6pt28/UWUCTXa+b0Mx1k3g6NOMA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.18.0.tgz", + "integrity": "sha512-l3m9ewPgjQSXrUMHg93vt0hYCGnrMOcUpTz6FLtbwljo2HluS4zTXFy2571YQbisTnfTKPZ01u/ukJdQTLGh9A==", "cpu": [ "arm" ], @@ -653,9 +666,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.13.0.tgz", - "integrity": "sha512-Iu0Kno1vrD7zHQDxOmvweqLkAzjxEVqNhUIXBsZ8hu8Oak7/5VTPrxOEZXYC1nmrBVJp0ZcL2E7lSuuOVaE3+w==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.18.0.tgz", + "integrity": "sha512-rJ5D47d8WD7J+7STKdCUAgmQk49xuFrRi9pZkWoRD1UeSMakbcepWXPF8ycChBoAqs1pb2wzvbY6Q33WmN2ftw==", "cpu": [ "arm64" ], @@ -666,9 +679,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.13.0.tgz", - "integrity": "sha512-C31QrW47llgVyrRjIwiOwsHFcaIwmkKi3PCroQY5aVq4H0A5v/vVVAtFsI1nfBngtoRpeREvZOkIhmRwUKkAdw==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.18.0.tgz", + "integrity": "sha512-be6Yx37b24ZwxQ+wOQXXLZqpq4jTckJhtGlWGZs68TgdKXJgw54lUUoFYrg6Zs/kjzAQwEwYbp8JxZVzZLRepQ==", "cpu": [ "arm64" ], @@ -678,10 +691,23 @@ "linux" ] }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.18.0.tgz", + "integrity": "sha512-hNVMQK+qrA9Todu9+wqrXOHxFiD5YmdEi3paj6vP02Kx1hjd2LLYR2eaN7DsEshg09+9uzWi2W18MJDlG0cxJA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.13.0.tgz", - "integrity": "sha512-Oq90dtMHvthFOPMl7pt7KmxzX7E71AfyIhh+cPhLY9oko97Zf2C9tt/XJD4RgxhaGeAraAXDtqxvKE1y/j35lA==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.18.0.tgz", + "integrity": "sha512-ROCM7i+m1NfdrsmvwSzoxp9HFtmKGHEqu5NNDiZWQtXLA8S5HBCkVvKAxJ8U+CVctHwV2Gb5VUaK7UAkzhDjlg==", "cpu": [ "riscv64" ], @@ -691,10 +717,23 @@ "linux" ] }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.18.0.tgz", + "integrity": "sha512-0UyyRHyDN42QL+NbqevXIIUnKA47A+45WyasO+y2bGJ1mhQrfrtXUpTxCOrfxCR4esV3/RLYyucGVPiUsO8xjg==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.13.0.tgz", - "integrity": "sha512-yUD/8wMffnTKuiIsl6xU+4IA8UNhQ/f1sAnQebmE/lyQ8abjsVyDkyRkWop0kdMhKMprpNIhPmYlCxgHrPoXoA==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.18.0.tgz", + "integrity": "sha512-xuglR2rBVHA5UsI8h8UbX4VJ470PtGCf5Vpswh7p2ukaqBGFTnsfzxUBetoWBWymHMxbIG0Cmx7Y9qDZzr648w==", "cpu": [ "x64" ], @@ -705,9 +744,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.13.0.tgz", - "integrity": "sha512-9RyNqoFNdF0vu/qqX63fKotBh43fJQeYC98hCaf89DYQpv+xu0D8QFSOS0biA7cGuqJFOc1bJ+m2rhhsKcw1hw==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.18.0.tgz", + "integrity": "sha512-LKaqQL9osY/ir2geuLVvRRs+utWUNilzdE90TpyoX0eNqPzWjRm14oMEE+YLve4k/NAqCdPkGYDaDF5Sw+xBfg==", "cpu": [ "x64" ], @@ -718,9 +757,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.13.0.tgz", - "integrity": "sha512-46ue8ymtm/5PUU6pCvjlic0z82qWkxv54GTJZgHrQUuZnVH+tvvSP0LsozIDsCBFO4VjJ13N68wqrKSeScUKdA==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.18.0.tgz", + "integrity": "sha512-7J6TkZQFGo9qBKH0pk2cEVSRhJbL6MtfWxth7Y5YmZs57Pi+4x6c2dStAUvaQkHQLnEQv1jzBUW43GvZW8OFqA==", "cpu": [ "arm64" ], @@ -731,9 +770,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.13.0.tgz", - "integrity": "sha512-P5/MqLdLSlqxbeuJ3YDeX37srC8mCflSyTrUsgbU1c/U9j6l2g2GiIdYaGD9QjdMQPMSgYm7hgg0551wHyIluw==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.18.0.tgz", + "integrity": "sha512-Txjh+IxBPbkUB9+SXZMpv+b/vnTEtFyfWZgJ6iyCmt2tdx0OF5WhFowLmnh8ENGNpfUlUZkdI//4IEmhwPieNg==", "cpu": [ "ia32" ], @@ -744,9 +783,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.13.0.tgz", - "integrity": "sha512-UKXUQNbO3DOhzLRwHSpa0HnhhCgNODvfoPWv2FCXme8N/ANFfhIPMGuOT+QuKd16+B5yxZ0HdpNlqPvTMS1qfw==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.18.0.tgz", + "integrity": "sha512-UOo5FdvOL0+eIVTgS4tIdbW+TtnBLWg1YBCcU2KWM7nuNwRz9bksDX1bekJJCpu25N1DVWaCwnT39dVQxzqS8g==", "cpu": [ "x64" ], @@ -796,13 +835,13 @@ } }, "node_modules/@vitest/expect": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.3.1.tgz", - "integrity": "sha512-xofQFwIzfdmLLlHa6ag0dPV8YsnKOCP1KdAeVVh34vSjN2dcUiXYCD9htu/9eM7t8Xln4v03U9HLxLpPlsXdZw==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.6.0.tgz", + "integrity": "sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ==", "dev": true, "dependencies": { - "@vitest/spy": "1.3.1", - "@vitest/utils": "1.3.1", + "@vitest/spy": "1.6.0", + "@vitest/utils": "1.6.0", "chai": "^4.3.10" }, "funding": { @@ -810,12 +849,12 @@ } }, "node_modules/@vitest/runner": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.3.1.tgz", - "integrity": "sha512-5FzF9c3jG/z5bgCnjr8j9LNq/9OxV2uEBAITOXfoe3rdZJTdO7jzThth7FXv/6b+kdY65tpRQB7WaKhNZwX+Kg==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.6.0.tgz", + "integrity": "sha512-P4xgwPjwesuBiHisAVz/LSSZtDjOTPYZVmNAnpHHSR6ONrf8eCJOFRvUwdHn30F5M1fxhqtl7QZQUk2dprIXAg==", "dev": true, "dependencies": { - "@vitest/utils": "1.3.1", + "@vitest/utils": "1.6.0", "p-limit": "^5.0.0", "pathe": "^1.1.1" }, @@ -824,9 +863,9 @@ } }, "node_modules/@vitest/snapshot": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.3.1.tgz", - "integrity": "sha512-EF++BZbt6RZmOlE3SuTPu/NfwBF6q4ABS37HHXzs2LUVPBLx2QoY/K0fKpRChSo8eLiuxcbCVfqKgx/dplCDuQ==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.6.0.tgz", + "integrity": "sha512-+Hx43f8Chus+DCmygqqfetcAZrDJwvTj0ymqjQq4CvmpKFSTVteEOBzCusu1x2tt4OJcvBflyHUE0DZSLgEMtQ==", "dev": true, "dependencies": { "magic-string": "^0.30.5", @@ -838,21 +877,18 @@ } }, "node_modules/@vitest/snapshot/node_modules/magic-string": { - "version": "0.30.8", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz", - "integrity": "sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==", + "version": "0.30.10", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", + "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", "dev": true, "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" - }, - "engines": { - "node": ">=12" } }, "node_modules/@vitest/spy": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.3.1.tgz", - "integrity": "sha512-xAcW+S099ylC9VLU7eZfdT9myV67Nor9w9zhf0mGCYJSO+zM2839tOeROTdikOi/8Qeusffvxb/MyBSOja1Uig==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.6.0.tgz", + "integrity": "sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw==", "dev": true, "dependencies": { "tinyspy": "^2.2.0" @@ -862,9 +898,9 @@ } }, "node_modules/@vitest/utils": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.3.1.tgz", - "integrity": "sha512-d3Waie/299qqRyHTm2DjADeTaNdNSVsnwHPWrs20JMpjh6eiVq7ggggweO8rc4arhf6rRkWuHKwvxGvejUXZZQ==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.6.0.tgz", + "integrity": "sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw==", "dev": true, "dependencies": { "diff-sequences": "^29.6.3", @@ -1049,6 +1085,15 @@ "fsevents": "~2.3.2" } }, + "node_modules/consola": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.2.3.tgz", + "integrity": "sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==", + "dev": true, + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, "node_modules/cookie": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", @@ -1096,9 +1141,9 @@ } }, "node_modules/deep-eql": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", - "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", + "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", "dev": true, "dependencies": { "type-detect": "^4.0.0" @@ -1107,6 +1152,12 @@ "node": ">=6" } }, + "node_modules/defu": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", + "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", + "dev": true + }, "node_modules/diff-sequences": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", @@ -1465,9 +1516,9 @@ } }, "node_modules/miniflare": { - "version": "3.20240314.0", - "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-3.20240314.0.tgz", - "integrity": "sha512-vjjiCEgNy4rfE8VP2C9xngT3eQY4HQg5eiXL+I845voM+6m67a7sZaGl2MspANNHXAKVi71m5bAzFgPcb2Jw9w==", + "version": "3.20240610.1", + "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-3.20240610.1.tgz", + "integrity": "sha512-ZkfSpBmX3nJW00yYhvF2kGvjb6f77TOimRR6+2GQvsArbwo6e0iYqLGM9aB/cnJzgFjLMvOv1qj4756iynSxJQ==", "dev": true, "dependencies": { "@cspotcode/source-map-support": "0.8.1", @@ -1477,11 +1528,11 @@ "exit-hook": "^2.2.1", "glob-to-regexp": "^0.4.1", "stoppable": "^1.1.0", - "undici": "^5.28.2", - "workerd": "1.20240314.0", - "ws": "^8.11.0", + "undici": "^5.28.4", + "workerd": "1.20240610.1", + "ws": "^8.14.2", "youch": "^3.2.2", - "zod": "^3.20.6" + "zod": "^3.22.3" }, "bin": { "miniflare": "bootstrap.js" @@ -1535,6 +1586,12 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/node-fetch-native": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.4.tgz", + "integrity": "sha512-IhOigYzAKHd244OC0JIMIUrjzctirCmPkaIfhDeGcEETWof5zKYUW7e7MYvChGWh/4CJeXEgsRyGzuF334rOOQ==", + "dev": true + }, "node_modules/node-forge": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", @@ -1647,9 +1704,9 @@ } }, "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", "dev": true }, "node_modules/picomatch": { @@ -1676,9 +1733,9 @@ } }, "node_modules/postcss": { - "version": "8.4.35", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz", - "integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==", + "version": "8.4.38", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", + "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", "dev": true, "funding": [ { @@ -1697,16 +1754,16 @@ "dependencies": { "nanoid": "^3.3.7", "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" + "source-map-js": "^1.2.0" }, "engines": { "node": "^10 || ^12 || >=14" } }, "node_modules/prettier": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", - "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz", + "integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==", "dev": true, "bin": { "prettier": "bin/prettier.cjs" @@ -1739,9 +1796,9 @@ "dev": true }, "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==", + "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 }, "node_modules/readdirp": { @@ -1783,9 +1840,9 @@ } }, "node_modules/rollup": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.13.0.tgz", - "integrity": "sha512-3YegKemjoQnYKmsBlOHfMLVPPA5xLkQ8MHLLSw/fBrFaVkEayL51DilPpNNLq1exr98F2B1TzrV0FUlN3gWRPg==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.18.0.tgz", + "integrity": "sha512-QmJz14PX3rzbJCN1SG4Xe/bAAX2a6NpCP8ab2vfu2GiUr8AQcr2nCV/oEO3yneFarB67zk8ShlIyWb2LGTb3Sg==", "dev": true, "dependencies": { "@types/estree": "1.0.5" @@ -1798,19 +1855,22 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.13.0", - "@rollup/rollup-android-arm64": "4.13.0", - "@rollup/rollup-darwin-arm64": "4.13.0", - "@rollup/rollup-darwin-x64": "4.13.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.13.0", - "@rollup/rollup-linux-arm64-gnu": "4.13.0", - "@rollup/rollup-linux-arm64-musl": "4.13.0", - "@rollup/rollup-linux-riscv64-gnu": "4.13.0", - "@rollup/rollup-linux-x64-gnu": "4.13.0", - "@rollup/rollup-linux-x64-musl": "4.13.0", - "@rollup/rollup-win32-arm64-msvc": "4.13.0", - "@rollup/rollup-win32-ia32-msvc": "4.13.0", - "@rollup/rollup-win32-x64-msvc": "4.13.0", + "@rollup/rollup-android-arm-eabi": "4.18.0", + "@rollup/rollup-android-arm64": "4.18.0", + "@rollup/rollup-darwin-arm64": "4.18.0", + "@rollup/rollup-darwin-x64": "4.18.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.18.0", + "@rollup/rollup-linux-arm-musleabihf": "4.18.0", + "@rollup/rollup-linux-arm64-gnu": "4.18.0", + "@rollup/rollup-linux-arm64-musl": "4.18.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.18.0", + "@rollup/rollup-linux-riscv64-gnu": "4.18.0", + "@rollup/rollup-linux-s390x-gnu": "4.18.0", + "@rollup/rollup-linux-x64-gnu": "4.18.0", + "@rollup/rollup-linux-x64-musl": "4.18.0", + "@rollup/rollup-win32-arm64-msvc": "4.18.0", + "@rollup/rollup-win32-ia32-msvc": "4.18.0", + "@rollup/rollup-win32-x64-msvc": "4.18.0", "fsevents": "~2.3.2" } }, @@ -1906,9 +1966,9 @@ } }, "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", "dev": true, "engines": { "node": ">=0.10.0" @@ -1996,9 +2056,9 @@ "dev": true }, "node_modules/tinypool": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.8.2.tgz", - "integrity": "sha512-SUszKYe5wgsxnNOVlBYO6IC+8VGWdVGZWAqUxp3UErNBtptZvWbwyUOyzNL59zigz2rCA92QiL3wvG+JDSdJdQ==", + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.8.4.tgz", + "integrity": "sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ==", "dev": true, "engines": { "node": ">=14.0.0" @@ -2026,9 +2086,9 @@ } }, "node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", "dev": true }, "node_modules/type-detect": { @@ -2041,9 +2101,9 @@ } }, "node_modules/typescript": { - "version": "5.4.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz", - "integrity": "sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==", + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -2054,15 +2114,15 @@ } }, "node_modules/ufo": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.4.0.tgz", - "integrity": "sha512-Hhy+BhRBleFjpJ2vchUNN40qgkh0366FWJGqVLYBHev0vpHTrXSA0ryT+74UiW6KWsldNurQMKGqCm1M2zBciQ==", + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.3.tgz", + "integrity": "sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw==", "dev": true }, "node_modules/undici": { - "version": "5.28.3", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.3.tgz", - "integrity": "sha512-3ItfzbrhDlINjaP0duwnNsKpDQk3acHI3gVJ1z4fmwMK31k5G9OVIAMLSIaP6w4FaGkaAkN6zaQO9LUvZ1t7VA==", + "version": "5.28.4", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.4.tgz", + "integrity": "sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==", "dev": true, "dependencies": { "@fastify/busboy": "^2.0.0" @@ -2077,15 +2137,30 @@ "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", "dev": true }, + "node_modules/unenv": { + "name": "unenv-nightly", + "version": "1.10.0-1717606461.a117952", + "resolved": "https://registry.npmjs.org/unenv-nightly/-/unenv-nightly-1.10.0-1717606461.a117952.tgz", + "integrity": "sha512-u3TfBX02WzbHTpaEfWEKwDijDSFAHcgXkayUZ+MVDrjhLFvgAJzFGTSTmwlEhwWi2exyRQey23ah9wELMM6etg==", + "dev": true, + "dependencies": { + "consola": "^3.2.3", + "defu": "^6.1.4", + "mime": "^3.0.0", + "node-fetch-native": "^1.6.4", + "pathe": "^1.1.2", + "ufo": "^1.5.3" + } + }, "node_modules/vite": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.1.6.tgz", - "integrity": "sha512-yYIAZs9nVfRJ/AiOLCA91zzhjsHUgMjB+EigzFb6W2XTLO8JixBCKCjvhKZaye+NKYHCrkv3Oh50dH9EdLU2RA==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.3.1.tgz", + "integrity": "sha512-XBmSKRLXLxiaPYamLv3/hnP/KXDai1NDexN0FpkTaZXTfycHvkRHoenpgl/fvuK/kPbB6xAgoyiryAhQNxYmAQ==", "dev": true, "dependencies": { - "esbuild": "^0.19.3", - "postcss": "^8.4.35", - "rollup": "^4.2.0" + "esbuild": "^0.21.3", + "postcss": "^8.4.38", + "rollup": "^4.13.0" }, "bin": { "vite": "bin/vite.js" @@ -2133,9 +2208,9 @@ } }, "node_modules/vite-node": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.3.1.tgz", - "integrity": "sha512-azbRrqRxlWTJEVbzInZCTchx0X69M/XPTCz4H+TLvlTcR/xH/3hkRqhOakT41fMJCMzXTu4UvegkZiEoJAWvng==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.6.0.tgz", + "integrity": "sha512-de6HJgzC+TFzOu0NTC4RAIsyf/DY/ibWDYQUcuEA84EMHhcefTUGkjFHKKEJhQN4A+6I0u++kr3l36ZF2d7XRw==", "dev": true, "dependencies": { "cac": "^6.7.14", @@ -2155,9 +2230,9 @@ } }, "node_modules/vite/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==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", "cpu": [ "arm" ], @@ -2171,9 +2246,9 @@ } }, "node_modules/vite/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==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", "cpu": [ "arm64" ], @@ -2187,9 +2262,9 @@ } }, "node_modules/vite/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==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", "cpu": [ "x64" ], @@ -2203,9 +2278,9 @@ } }, "node_modules/vite/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==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", "cpu": [ "arm64" ], @@ -2219,9 +2294,9 @@ } }, "node_modules/vite/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==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", "cpu": [ "x64" ], @@ -2235,9 +2310,9 @@ } }, "node_modules/vite/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==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", "cpu": [ "arm64" ], @@ -2251,9 +2326,9 @@ } }, "node_modules/vite/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==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", "cpu": [ "x64" ], @@ -2267,9 +2342,9 @@ } }, "node_modules/vite/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==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", "cpu": [ "arm" ], @@ -2283,9 +2358,9 @@ } }, "node_modules/vite/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==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", "cpu": [ "arm64" ], @@ -2299,9 +2374,9 @@ } }, "node_modules/vite/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==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", "cpu": [ "ia32" ], @@ -2315,9 +2390,9 @@ } }, "node_modules/vite/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==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", "cpu": [ "loong64" ], @@ -2331,9 +2406,9 @@ } }, "node_modules/vite/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==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", "cpu": [ "mips64el" ], @@ -2347,9 +2422,9 @@ } }, "node_modules/vite/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==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", "cpu": [ "ppc64" ], @@ -2363,9 +2438,9 @@ } }, "node_modules/vite/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==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", "cpu": [ "riscv64" ], @@ -2379,9 +2454,9 @@ } }, "node_modules/vite/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==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", "cpu": [ "s390x" ], @@ -2395,9 +2470,9 @@ } }, "node_modules/vite/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==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", "cpu": [ "x64" ], @@ -2411,9 +2486,9 @@ } }, "node_modules/vite/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==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", "cpu": [ "x64" ], @@ -2427,9 +2502,9 @@ } }, "node_modules/vite/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==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", "cpu": [ "x64" ], @@ -2443,9 +2518,9 @@ } }, "node_modules/vite/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==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", "cpu": [ "x64" ], @@ -2459,9 +2534,9 @@ } }, "node_modules/vite/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==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", "cpu": [ "arm64" ], @@ -2475,9 +2550,9 @@ } }, "node_modules/vite/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==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", "cpu": [ "ia32" ], @@ -2491,9 +2566,9 @@ } }, "node_modules/vite/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==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", "cpu": [ "x64" ], @@ -2507,9 +2582,9 @@ } }, "node_modules/vite/node_modules/esbuild": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz", - "integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", "dev": true, "hasInstallScript": true, "bin": { @@ -2519,42 +2594,42 @@ "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" + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" } }, "node_modules/vitest": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.3.1.tgz", - "integrity": "sha512-/1QJqXs8YbCrfv/GPQ05wAZf2eakUPLPa18vkJAKE7RXOKfVHqMZZ1WlTjiwl6Gcn65M5vpNUB6EFLnEdRdEXQ==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.6.0.tgz", + "integrity": "sha512-H5r/dN06swuFnzNFhq/dnz37bPXnq8xB2xB5JOVk8K09rUtoeNN+LHWkoQ0A/i3hvbUKKcCei9KpbxqHMLhLLA==", "dev": true, "dependencies": { - "@vitest/expect": "1.3.1", - "@vitest/runner": "1.3.1", - "@vitest/snapshot": "1.3.1", - "@vitest/spy": "1.3.1", - "@vitest/utils": "1.3.1", + "@vitest/expect": "1.6.0", + "@vitest/runner": "1.6.0", + "@vitest/snapshot": "1.6.0", + "@vitest/spy": "1.6.0", + "@vitest/utils": "1.6.0", "acorn-walk": "^8.3.2", "chai": "^4.3.10", "debug": "^4.3.4", @@ -2566,9 +2641,9 @@ "std-env": "^3.5.0", "strip-literal": "^2.0.0", "tinybench": "^2.5.1", - "tinypool": "^0.8.2", + "tinypool": "^0.8.3", "vite": "^5.0.0", - "vite-node": "1.3.1", + "vite-node": "1.6.0", "why-is-node-running": "^2.2.2" }, "bin": { @@ -2583,8 +2658,8 @@ "peerDependencies": { "@edge-runtime/vm": "*", "@types/node": "^18.0.0 || >=20.0.0", - "@vitest/browser": "1.3.1", - "@vitest/ui": "1.3.1", + "@vitest/browser": "1.6.0", + "@vitest/ui": "1.6.0", "happy-dom": "*", "jsdom": "*" }, @@ -2653,9 +2728,9 @@ } }, "node_modules/workerd": { - "version": "1.20240314.0", - "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20240314.0.tgz", - "integrity": "sha512-5vXqDe6vJTMpfPVW8Vtcy2zcVIBnOIMv0D+Z0gVPMPq++KwEyQWzCIVLpIyc28EUc5bW3gEO49E8BN1PQebgfw==", + "version": "1.20240610.1", + "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20240610.1.tgz", + "integrity": "sha512-Rtut5GrsODQMh6YU43b9WZ980Wd05Ov1/ds88pT/SoetmXFBvkBzdRfiHiATv+azmGX8KveE0i/Eqzk/yI01ug==", "dev": true, "hasInstallScript": true, "bin": { @@ -2665,32 +2740,33 @@ "node": ">=16" }, "optionalDependencies": { - "@cloudflare/workerd-darwin-64": "1.20240314.0", - "@cloudflare/workerd-darwin-arm64": "1.20240314.0", - "@cloudflare/workerd-linux-64": "1.20240314.0", - "@cloudflare/workerd-linux-arm64": "1.20240314.0", - "@cloudflare/workerd-windows-64": "1.20240314.0" + "@cloudflare/workerd-darwin-64": "1.20240610.1", + "@cloudflare/workerd-darwin-arm64": "1.20240610.1", + "@cloudflare/workerd-linux-64": "1.20240610.1", + "@cloudflare/workerd-linux-arm64": "1.20240610.1", + "@cloudflare/workerd-windows-64": "1.20240610.1" } }, "node_modules/wrangler": { - "version": "3.36.0", - "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-3.36.0.tgz", - "integrity": "sha512-Fywf9RGAePIuIDcsSg4BW+lDUZX1jh2jN+TtmZOwG5Ewdr9dJGP3dxoFa85eQQZP1VLvY4lsqrKy67JqOuP9Gw==", + "version": "3.61.0", + "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-3.61.0.tgz", + "integrity": "sha512-feVAp0986x9xL3Dc1zin0ZVXKaqzp7eZur7iPLnpEwjG1Xy4dkVEZ5a1LET94Iyejt1P+EX5lgGcz63H7EfzUw==", "dev": true, "dependencies": { - "@cloudflare/kv-asset-handler": "0.3.1", + "@cloudflare/kv-asset-handler": "0.3.3", "@esbuild-plugins/node-globals-polyfill": "^0.2.3", "@esbuild-plugins/node-modules-polyfill": "^0.2.2", "blake3-wasm": "^2.1.5", "chokidar": "^3.5.3", "esbuild": "0.17.19", - "miniflare": "3.20240314.0", + "miniflare": "3.20240610.1", "nanoid": "^3.3.3", "path-to-regexp": "^6.2.0", "resolve": "^1.22.8", "resolve.exports": "^2.0.2", "selfsigned": "^2.0.1", - "source-map": "0.6.1", + "source-map": "^0.6.1", + "unenv": "npm:unenv-nightly@1.10.0-1717606461.a117952", "xxhash-wasm": "^1.0.1" }, "bin": { @@ -2704,7 +2780,7 @@ "fsevents": "~2.3.2" }, "peerDependencies": { - "@cloudflare/workers-types": "^4.20230914.0" + "@cloudflare/workers-types": "^4.20240605.0" }, "peerDependenciesMeta": { "@cloudflare/workers-types": { @@ -2713,9 +2789,9 @@ } }, "node_modules/ws": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", - "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", "dev": true, "engines": { "node": ">=10.0.0" @@ -2763,9 +2839,9 @@ } }, "node_modules/zod": { - "version": "3.22.4", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz", - "integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==", + "version": "3.23.8", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", + "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", "dev": true, "funding": { "url": "https://github.com/sponsors/colinhacks" diff --git a/ts/sbd-server/package.json b/ts/sbd-server/package.json index 8ecf136..862d7b5 100644 --- a/ts/sbd-server/package.json +++ b/ts/sbd-server/package.json @@ -12,16 +12,16 @@ "test": "npm run test:fmt && npm run test:type && npm run test:unit" }, "devDependencies": { - "@cloudflare/workers-types": "^4.20240312.0", + "@cloudflare/workers-types": "^4.20240614.0", "@types/ws": "^8.5.10", - "prettier": "^3.2.5", - "typescript": "^5.0.4", - "vitest": "^1.3.1", - "wrangler": "^3.36.0", - "ws": "^8.16.0" + "prettier": "^3.3.2", + "typescript": "^5.4.5", + "vitest": "^1.6.0", + "wrangler": "^3.61.0", + "ws": "^8.17.1" }, "dependencies": { - "@noble/ed25519": "^2.0.0", + "@noble/ed25519": "^2.1.0", "@noble/hashes": "^1.4.0", "js-base64": "^3.7.7" } diff --git a/ts/sbd-server/src/index.ts b/ts/sbd-server/src/index.ts index 8d2b97d..296c56d 100644 --- a/ts/sbd-server/src/index.ts +++ b/ts/sbd-server/src/index.ts @@ -75,7 +75,6 @@ export default { const method = request.method; const url = new URL(request.url); - // @ts-expect-error // cf typescript bug // const path: string = url.pathname; // TODO - check headers for content-length / chunked encoding and reject? @@ -148,7 +147,6 @@ export class DoSignal implements DurableObject { try { const ip = request.headers.get('cf-connecting-ip') || 'no-ip'; const url = new URL(request.url); - // @ts-expect-error // cf typescript bug // const path: string = url.pathname; if (path === '/fwd') { diff --git a/ts/sbd-server/wrangler.toml b/ts/sbd-server/wrangler.toml index d412c9f..c2e2f6e 100644 --- a/ts/sbd-server/wrangler.toml +++ b/ts/sbd-server/wrangler.toml @@ -1,6 +1,6 @@ name = "tx5-signal-cf" main = "src/index.ts" -compatibility_date = "2024-03-12" +compatibility_date = "2024-06-18" [[durable_objects.bindings]] name = "SIGNAL" From 29f3a6db203528b9e250e7e7a47af2d85b3ca66f Mon Sep 17 00:00:00 2001 From: neonphog Date: Wed, 19 Jun 2024 15:46:35 -0600 Subject: [PATCH 04/36] integrate with server-o-bahn suite --- Makefile | 1 + ts/sbd-server/package.json | 2 +- ts/sbd-server/server-o-bahn-runner.mjs | 83 ++++++++++++++++++++++++++ ts/sbd-server/src/index.test.ts | 4 +- 4 files changed, 88 insertions(+), 2 deletions(-) create mode 100755 ts/sbd-server/server-o-bahn-runner.mjs diff --git a/Makefile b/Makefile index 5f2cf7d..d4616f1 100644 --- a/Makefile +++ b/Makefile @@ -58,6 +58,7 @@ test: RUST_BACKTRACE=1 cargo test cd ts/sbd-server && npm ci cd ts/sbd-server && npm run test:unit + cd ts/sbd-server && cargo run --manifest-path ../../rust/sbd-o-bahn-server-tester/Cargo.toml -- ./server-o-bahn-runner.mjs static: cargo fmt -- --check diff --git a/ts/sbd-server/package.json b/ts/sbd-server/package.json index 862d7b5..ec417b3 100644 --- a/ts/sbd-server/package.json +++ b/ts/sbd-server/package.json @@ -1,5 +1,5 @@ { - "name": "tx5-signal-cf", + "name": "sbd-signal", "version": "0.0.0", "private": true, "scripts": { diff --git a/ts/sbd-server/server-o-bahn-runner.mjs b/ts/sbd-server/server-o-bahn-runner.mjs new file mode 100755 index 0000000..0b0b1d8 --- /dev/null +++ b/ts/sbd-server/server-o-bahn-runner.mjs @@ -0,0 +1,83 @@ +#!/usr/bin/env node + +import { spawn } from 'node:child_process' +import { createInterface } from 'node:readline' +import { stdin, exit } from 'node:process' + +const reReady = new RegExp('^.*Ready on http:\/\/(.*)$', 'm') + +class Srv { + #proc + #addr + + constructor(proc) { + this.#proc = proc + this.#addr = null + } + + static async spawn() { + const proc = spawn('npx', [ + 'wrangler', + 'dev', + '--show-interactive-dev-session', + 'false', + '--ip', + '127.0.0.1', + '--port', + '0' + ]) + + const out = new Srv(proc) + + const rl = createInterface({ + input: proc.stdout, + }) + + return await new Promise((r, _) => { + rl.on('line', (line) => { + //console.log(`stdout:line:${line}`) + const match = line.match(reReady) + if (match && match.length > 1 && match[1]) { + out.#addr = match[1] + rl.close() + r(out) + } + }) + }) + } + + addr() { + return this.#addr + } + + async kill() { + if (!this.#proc.kill('SIGTERM')) { + await new Promise((r, _) => { + setTimeout(r, 1000) + }) + this.#proc.kill('SIGKILL') + } + } +} + +console.log('CMD/READY') + +let _glb_srv = null + +const rl = createInterface({ + input: stdin, +}) + +for await (const line of rl) { + if (line === 'CMD/START') { + if (_glb_srv) { + await _glb_srv.kill() + } + _glb_srv = await Srv.spawn() + const addr = _glb_srv.addr() + console.log(`CMD/START/${addr}`) + } else { + console.error('INVALID CMD: ' + line) + exit(127) + } +} diff --git a/ts/sbd-server/src/index.test.ts b/ts/sbd-server/src/index.test.ts index 887fb9f..cd6fcfc 100644 --- a/ts/sbd-server/src/index.test.ts +++ b/ts/sbd-server/src/index.test.ts @@ -117,7 +117,9 @@ describe('Worker', () => { let addr: string; beforeAll(async () => { - worker = await unstable_dev('src/index.ts'); + worker = await unstable_dev('src/index.ts', { + experimental: { disableExperimentalWarning: true }, + }); addr = worker.address + ':' + worker.port; }); From cd4d0de075f3661ada6d7e3e87bfe89897955395 Mon Sep 17 00:00:00 2001 From: neonphog Date: Fri, 28 Jun 2024 11:16:02 -0600 Subject: [PATCH 05/36] fix windows ts runner --- Makefile | 2 +- .../src/bin/sbd-o-bahn-server-tester-bin.rs | 10 ++++------ rust/sbd-o-bahn-server-tester/src/lib.rs | 10 +++++++--- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/Makefile b/Makefile index d4616f1..dbbbd80 100644 --- a/Makefile +++ b/Makefile @@ -58,7 +58,7 @@ test: RUST_BACKTRACE=1 cargo test cd ts/sbd-server && npm ci cd ts/sbd-server && npm run test:unit - cd ts/sbd-server && cargo run --manifest-path ../../rust/sbd-o-bahn-server-tester/Cargo.toml -- ./server-o-bahn-runner.mjs + cd ts/sbd-server && cargo run --manifest-path ../../rust/sbd-o-bahn-server-tester/Cargo.toml -- node ./server-o-bahn-runner.mjs static: cargo fmt -- --check diff --git a/rust/sbd-o-bahn-server-tester/src/bin/sbd-o-bahn-server-tester-bin.rs b/rust/sbd-o-bahn-server-tester/src/bin/sbd-o-bahn-server-tester-bin.rs index d0264ff..627637d 100644 --- a/rust/sbd-o-bahn-server-tester/src/bin/sbd-o-bahn-server-tester-bin.rs +++ b/rust/sbd-o-bahn-server-tester/src/bin/sbd-o-bahn-server-tester-bin.rs @@ -1,11 +1,9 @@ #[tokio::main(flavor = "multi_thread")] async fn main() { - let mut args = std::env::args_os(); - args.next().unwrap(); - let result = sbd_o_bahn_server_tester::run( - args.next().expect("Expected Sbd Server Suite Runner"), - ) - .await; + let mut args = std::env::args_os().collect::>(); + // remove the "self" arg + args.remove(0); + let result = sbd_o_bahn_server_tester::run(args).await; println!("{result:#?}"); if !result.failed.is_empty() { panic!("TEST FAILED"); diff --git a/rust/sbd-o-bahn-server-tester/src/lib.rs b/rust/sbd-o-bahn-server-tester/src/lib.rs index c769ae5..fc8da0f 100644 --- a/rust/sbd-o-bahn-server-tester/src/lib.rs +++ b/rust/sbd-o-bahn-server-tester/src/lib.rs @@ -28,7 +28,7 @@ pub struct Report { } /// Run the test suite. -pub async fn run>(cmd: S) -> Report { +pub async fn run>(cmd: Vec) -> Report { let mut server = Server::spawn(cmd).await.unwrap(); let addrs = server.start().await; @@ -44,8 +44,12 @@ struct Server { } impl Server { - pub async fn spawn>(cmd: S) -> Result { - let mut cmd = tokio::process::Command::new(cmd); + pub async fn spawn>( + mut args: Vec, + ) -> Result { + let prog = args.remove(0); + let mut cmd = tokio::process::Command::new(prog); + cmd.args(args); cmd.kill_on_drop(true) .stdin(std::process::Stdio::piped()) .stdout(std::process::Stdio::piped()); From fcd4f6b769d1b55e1aad1520e13cb1d31dd7f1c4 Mon Sep 17 00:00:00 2001 From: neonphog Date: Fri, 28 Jun 2024 14:44:08 -0600 Subject: [PATCH 06/36] ci fix --- rust/sbd-o-bahn-server-tester/src/lib.rs | 4 +- ts/sbd-server/package-lock.json | 1034 +++++++++++----------- ts/sbd-server/package.json | 9 +- ts/sbd-server/server-o-bahn-runner.mjs | 30 +- ts/sbd-server/src/index.test.ts | 151 ---- ts/sbd-server/wrangler.toml | 4 +- 6 files changed, 550 insertions(+), 682 deletions(-) delete mode 100644 ts/sbd-server/src/index.test.ts diff --git a/rust/sbd-o-bahn-server-tester/src/lib.rs b/rust/sbd-o-bahn-server-tester/src/lib.rs index fc8da0f..154fedb 100644 --- a/rust/sbd-o-bahn-server-tester/src/lib.rs +++ b/rust/sbd-o-bahn-server-tester/src/lib.rs @@ -49,8 +49,8 @@ impl Server { ) -> Result { let prog = args.remove(0); let mut cmd = tokio::process::Command::new(prog); - cmd.args(args); - cmd.kill_on_drop(true) + cmd.args(args) + .kill_on_drop(true) .stdin(std::process::Stdio::piped()) .stdout(std::process::Stdio::piped()); diff --git a/ts/sbd-server/package-lock.json b/ts/sbd-server/package-lock.json index dd01631..a925084 100644 --- a/ts/sbd-server/package-lock.json +++ b/ts/sbd-server/package-lock.json @@ -1,11 +1,11 @@ { - "name": "tx5-signal-cf", + "name": "sbd-signal", "version": "0.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "tx5-signal-cf", + "name": "sbd-signal", "version": "0.0.0", "dependencies": { "@noble/ed25519": "^2.1.0", @@ -13,19 +13,18 @@ "js-base64": "^3.7.7" }, "devDependencies": { - "@cloudflare/workers-types": "^4.20240614.0", - "@types/ws": "^8.5.10", + "@cloudflare/workers-types": "^4.20240620.0", + "node-cleanup": "^2.1.2", "prettier": "^3.3.2", - "typescript": "^5.4.5", + "typescript": "^5.5.2", "vitest": "^1.6.0", - "wrangler": "^3.61.0", - "ws": "^8.17.1" + "wrangler": "^3.62.0" } }, "node_modules/@cloudflare/kv-asset-handler": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.3.3.tgz", - "integrity": "sha512-wpE+WiWW2kUNwNE0xyl4CtTAs+STjGtouHGiZPGRaisGB7eXXdbvfZdOrQJQVKgTxZiNAgVgmc7fj0sUmd8zyA==", + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.3.4.tgz", + "integrity": "sha512-YLPHc8yASwjNkmcDMQMY35yiWjoKAKnhUbPRszBRS0YgH+IXtsMp61j+yTcnCE3oO2DgP0U3iejLC8FTtKDC8Q==", "dev": true, "dependencies": { "mime": "^3.0.0" @@ -35,9 +34,9 @@ } }, "node_modules/@cloudflare/workerd-darwin-64": { - "version": "1.20240610.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20240610.1.tgz", - "integrity": "sha512-YanZ1iXgMGaUWlleB5cswSE6qbzyjQ8O7ENWZcPAcZZ6BfuL7q3CWi0t9iM1cv2qx92rRztsRTyjcfq099++XQ==", + "version": "1.20240620.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20240620.1.tgz", + "integrity": "sha512-YWeS2aE8jAzDefuus/3GmZcFGu3Ef94uCAoxsQuaEXNsiGM9NeAhPpKC1BJAlcv168U/Q1J+6hckcGtipf6ZcQ==", "cpu": [ "x64" ], @@ -51,9 +50,9 @@ } }, "node_modules/@cloudflare/workerd-darwin-arm64": { - "version": "1.20240610.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20240610.1.tgz", - "integrity": "sha512-bRe/y/LKjIgp3L2EHjc+CvoCzfHhf4aFTtOBkv2zW+VToNJ4KlXridndf7LvR9urfsFRRo9r4TXCssuKaU+ypQ==", + "version": "1.20240620.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20240620.1.tgz", + "integrity": "sha512-3rdND+EHpmCrwYX6hvxIBSBJ0f40tRNxond1Vfw7GiR1MJVi3gragiBx75UDFHCxfRw3J0GZ1qVlkRce2/Xbsg==", "cpu": [ "arm64" ], @@ -67,9 +66,9 @@ } }, "node_modules/@cloudflare/workerd-linux-64": { - "version": "1.20240610.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20240610.1.tgz", - "integrity": "sha512-2zDcadR7+Gs9SjcMXmwsMji2Xs+yASGNA2cEHDuFc4NMUup+eL1mkzxc/QzvFjyBck98e92rBjMZt2dVscpGKg==", + "version": "1.20240620.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20240620.1.tgz", + "integrity": "sha512-tURcTrXGeSbYqeM5ISVcofY20StKbVIcdxjJvNYNZ+qmSV9Fvn+zr7rRE+q64pEloVZfhsEPAlUCnFso5VV4XQ==", "cpu": [ "x64" ], @@ -83,9 +82,9 @@ } }, "node_modules/@cloudflare/workerd-linux-arm64": { - "version": "1.20240610.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20240610.1.tgz", - "integrity": "sha512-7y41rPi5xmIYJN8CY+t3RHnjLL0xx/WYmaTd/j552k1qSr02eTE2o/TGyWZmGUC+lWnwdPQJla0mXbvdqgRdQg==", + "version": "1.20240620.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20240620.1.tgz", + "integrity": "sha512-TThvkwNxaZFKhHZnNjOGqIYCOk05DDWgO+wYMuXg15ymN/KZPnCicRAkuyqiM+R1Fgc4kwe/pehjP8pbmcf6sg==", "cpu": [ "arm64" ], @@ -99,9 +98,9 @@ } }, "node_modules/@cloudflare/workerd-windows-64": { - "version": "1.20240610.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20240610.1.tgz", - "integrity": "sha512-B0LyT3DB6rXHWNptnntYHPaoJIy0rXnGfeDBM3nEVV8JIsQrx8MEFn2F2jYioH1FkUVavsaqKO/zUosY3tZXVA==", + "version": "1.20240620.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20240620.1.tgz", + "integrity": "sha512-Y/BA9Yj0r7Al1HK3nDHcfISgFllw6NR3XMMPChev57vrVT9C9D4erBL3sUBfofHU+2U9L+ShLsl6obBpe3vvUw==", "cpu": [ "x64" ], @@ -115,9 +114,9 @@ } }, "node_modules/@cloudflare/workers-types": { - "version": "4.20240614.0", - "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20240614.0.tgz", - "integrity": "sha512-fnV3uXD1Hpq5EWnY7XYb+smPcjzIoUFiZpTSV/Tk8qKL3H+w6IqcngZwXQBZ/2U/DwYkDilXHW3FfPhnyD7FZA==", + "version": "4.20240620.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20240620.0.tgz", + "integrity": "sha512-CQD8YS6evRob7LChvIX3gE3zYo0KVgaLDOu1SwNP1BVIS2Sa0b+FC8S1e1hhrNN8/E4chYlVN+FDAgA4KRDUEQ==", "dev": true }, "node_modules/@cspotcode/source-map-support": { @@ -171,9 +170,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", - "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", "cpu": [ "arm" ], @@ -187,9 +186,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", - "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", "cpu": [ "arm64" ], @@ -203,9 +202,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", - "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", "cpu": [ "x64" ], @@ -219,9 +218,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", - "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", "cpu": [ "arm64" ], @@ -235,9 +234,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", - "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", "cpu": [ "x64" ], @@ -251,9 +250,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", - "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", "cpu": [ "arm64" ], @@ -267,9 +266,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", - "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", "cpu": [ "x64" ], @@ -283,9 +282,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", - "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", "cpu": [ "arm" ], @@ -299,9 +298,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", - "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", "cpu": [ "arm64" ], @@ -315,9 +314,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", - "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", "cpu": [ "ia32" ], @@ -331,9 +330,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", - "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", "cpu": [ "loong64" ], @@ -347,9 +346,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", - "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", "cpu": [ "mips64el" ], @@ -363,9 +362,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", - "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", "cpu": [ "ppc64" ], @@ -379,9 +378,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", - "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", "cpu": [ "riscv64" ], @@ -395,9 +394,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", - "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", "cpu": [ "s390x" ], @@ -411,9 +410,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", - "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", "cpu": [ "x64" ], @@ -427,9 +426,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", - "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", "cpu": [ "x64" ], @@ -443,9 +442,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", - "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", "cpu": [ "x64" ], @@ -459,9 +458,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", - "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", "cpu": [ "x64" ], @@ -475,9 +474,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", - "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", "cpu": [ "arm64" ], @@ -491,9 +490,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", - "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", "cpu": [ "ia32" ], @@ -507,9 +506,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", - "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", "cpu": [ "x64" ], @@ -808,9 +807,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.11.27", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.27.tgz", - "integrity": "sha512-qyUZfMnCg1KEz57r7pzFtSGt49f6RPkPBis3Vo4PbS7roQEDn22hiHzl/Lo1q4i4hDEgBJmBF/NTNg2XR0HbFg==", + "version": "20.14.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.9.tgz", + "integrity": "sha512-06OCtnTXtWOZBJlRApleWndH4JsRVs1pDCc8dLSQp+7PpUpX3ePdHyeNSFTeSe7FtKyQkrlPvHwJOW3SLd8Oyg==", "dev": true, "dependencies": { "undici-types": "~5.26.4" @@ -825,15 +824,6 @@ "@types/node": "*" } }, - "node_modules/@types/ws": { - "version": "8.5.10", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", - "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@vitest/expect": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.6.0.tgz", @@ -876,15 +866,6 @@ "url": "https://opencollective.com/vitest" } }, - "node_modules/@vitest/snapshot/node_modules/magic-string": { - "version": "0.30.10", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", - "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", - "dev": true, - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15" - } - }, "node_modules/@vitest/spy": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.6.0.tgz", @@ -912,19 +893,10 @@ "url": "https://opencollective.com/vitest" } }, - "node_modules/@vitest/utils/node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "dev": true, - "dependencies": { - "@types/estree": "^1.0.0" - } - }, "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.0.tgz", + "integrity": "sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -934,10 +906,13 @@ } }, "node_modules/acorn-walk": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", - "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", + "version": "8.3.3", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.3.tgz", + "integrity": "sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==", "dev": true, + "dependencies": { + "acorn": "^8.11.0" + }, "engines": { "node": ">=0.4.0" } @@ -986,12 +961,15 @@ } }, "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "dev": true, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/blake3-wasm": { @@ -1001,12 +979,12 @@ "dev": true }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -1085,6 +1063,12 @@ "fsevents": "~2.3.2" } }, + "node_modules/confbox": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.7.tgz", + "integrity": "sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA==", + "dev": true + }, "node_modules/consola": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/consola/-/consola-3.2.3.tgz", @@ -1123,10 +1107,20 @@ "integrity": "sha512-ND9qDTLc6diwj+Xe5cdAgVTbLVdXbtxTJRXRhli8Mowuaan+0EJOtdqJ0QCHNSSPyoXGx9HX2/VMnKeC34AChA==", "dev": true }, + "node_modules/date-fns": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz", + "integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "dev": true, "dependencies": { "ms": "2.1.2" @@ -1168,9 +1162,9 @@ } }, "node_modules/esbuild": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz", - "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", "dev": true, "hasInstallScript": true, "bin": { @@ -1180,28 +1174,29 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/android-arm": "0.17.19", - "@esbuild/android-arm64": "0.17.19", - "@esbuild/android-x64": "0.17.19", - "@esbuild/darwin-arm64": "0.17.19", - "@esbuild/darwin-x64": "0.17.19", - "@esbuild/freebsd-arm64": "0.17.19", - "@esbuild/freebsd-x64": "0.17.19", - "@esbuild/linux-arm": "0.17.19", - "@esbuild/linux-arm64": "0.17.19", - "@esbuild/linux-ia32": "0.17.19", - "@esbuild/linux-loong64": "0.17.19", - "@esbuild/linux-mips64el": "0.17.19", - "@esbuild/linux-ppc64": "0.17.19", - "@esbuild/linux-riscv64": "0.17.19", - "@esbuild/linux-s390x": "0.17.19", - "@esbuild/linux-x64": "0.17.19", - "@esbuild/netbsd-x64": "0.17.19", - "@esbuild/openbsd-x64": "0.17.19", - "@esbuild/sunos-x64": "0.17.19", - "@esbuild/win32-arm64": "0.17.19", - "@esbuild/win32-ia32": "0.17.19", - "@esbuild/win32-x64": "0.17.19" + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" } }, "node_modules/escape-string-regexp": { @@ -1217,10 +1212,13 @@ } }, "node_modules/estree-walker": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", - "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", - "dev": true + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0" + } }, "node_modules/execa": { "version": "8.0.1", @@ -1258,9 +1256,9 @@ } }, "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==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "dependencies": { "to-regex-range": "^5.0.1" @@ -1375,12 +1373,15 @@ } }, "node_modules/is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.14.0.tgz", + "integrity": "sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A==", "dev": true, "dependencies": { - "hasown": "^2.0.0" + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -1440,15 +1441,9 @@ "integrity": "sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==" }, "node_modules/js-tokens": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-8.0.3.tgz", - "integrity": "sha512-UfJMcSJc+SEXEl9lH/VLHSZbThQyLpw1vLO1Lb+j4RWDvG3N2f7yj3PVQA3cmkTBNldJ9eFnM+xEXxHIXrYiJw==", - "dev": true - }, - "node_modules/jsonc-parser": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", - "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.0.tgz", + "integrity": "sha512-WriZw1luRMlmV3LGJaR6QOJjWwgLUTf89OwT2lUOyjX2dJGBwgmIkbcz+7WFZjrZM635JOIR517++e/67CP9dQ==", "dev": true }, "node_modules/local-pkg": { @@ -1477,12 +1472,12 @@ } }, "node_modules/magic-string": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", - "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "version": "0.30.10", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", + "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", "dev": true, "dependencies": { - "sourcemap-codec": "^1.4.8" + "@jridgewell/sourcemap-codec": "^1.4.15" } }, "node_modules/merge-stream": { @@ -1516,9 +1511,9 @@ } }, "node_modules/miniflare": { - "version": "3.20240610.1", - "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-3.20240610.1.tgz", - "integrity": "sha512-ZkfSpBmX3nJW00yYhvF2kGvjb6f77TOimRR6+2GQvsArbwo6e0iYqLGM9aB/cnJzgFjLMvOv1qj4756iynSxJQ==", + "version": "3.20240620.0", + "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-3.20240620.0.tgz", + "integrity": "sha512-NBMzqUE2mMlh/hIdt6U5MP+aFhEjKDq3l8CAajXAQa1WkndJdciWvzB2mfLETwoVFhMl/lphaVzyEN2AgwJpbQ==", "dev": true, "dependencies": { "@cspotcode/source-map-support": "0.8.1", @@ -1529,7 +1524,7 @@ "glob-to-regexp": "^0.4.1", "stoppable": "^1.1.0", "undici": "^5.28.4", - "workerd": "1.20240610.1", + "workerd": "1.20240620.1", "ws": "^8.14.2", "youch": "^3.2.2", "zod": "^3.22.3" @@ -1542,15 +1537,15 @@ } }, "node_modules/mlly": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.6.1.tgz", - "integrity": "sha512-vLgaHvaeunuOXHSmEbZ9izxPx3USsk8KCQ8iC+aTlp5sKRSoZvwhHh5L9VbKSaVC6sJDqbyohIS76E2VmHIPAA==", + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.1.tgz", + "integrity": "sha512-rrVRZRELyQzrIUAVMHxP97kv+G786pHmOKzuFII8zDYahFBS7qnHh2AlYSl1GAHhaMPCz6/oHjVMcfFYgFYHgA==", "dev": true, "dependencies": { "acorn": "^8.11.3", "pathe": "^1.1.2", - "pkg-types": "^1.0.3", - "ufo": "^1.3.2" + "pkg-types": "^1.1.1", + "ufo": "^1.5.3" } }, "node_modules/ms": { @@ -1586,6 +1581,12 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/node-cleanup": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/node-cleanup/-/node-cleanup-2.1.2.tgz", + "integrity": "sha512-qN8v/s2PAJwGUtr1/hYTpNKlD6Y9rc4p8KSmJXyGdYGZsDGKXrGThikLFP9OCHFeLeEpQzPwiAtdIvBLqm//Hw==", + "dev": true + }, "node_modules/node-fetch-native": { "version": "1.6.4", "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.4.tgz", @@ -1683,9 +1684,9 @@ "dev": true }, "node_modules/path-to-regexp": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz", - "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.2.tgz", + "integrity": "sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw==", "dev": true }, "node_modules/pathe": { @@ -1722,14 +1723,14 @@ } }, "node_modules/pkg-types": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.3.tgz", - "integrity": "sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.1.1.tgz", + "integrity": "sha512-ko14TjmDuQJ14zsotODv7dBlwxKhUKQEhuhmbqo1uCi9BB0Z2alo/wAXg6q1dTR5TyuqYyWhjtfe/Tsh+X28jQ==", "dev": true, "dependencies": { - "jsonc-parser": "^3.2.0", - "mlly": "^1.2.0", - "pathe": "^1.1.0" + "confbox": "^0.1.7", + "mlly": "^1.7.0", + "pathe": "^1.1.2" } }, "node_modules/postcss": { @@ -1886,14 +1887,29 @@ "rollup-pluginutils": "^2.8.1" } }, - "node_modules/rollup-plugin-node-polyfills": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/rollup-plugin-node-polyfills/-/rollup-plugin-node-polyfills-0.2.1.tgz", - "integrity": "sha512-4kCrKPTJ6sK4/gLL/U5QzVT8cxJcofO0OU74tnB19F40cmuAKSzH5/siithxlofFEjwvw1YAhPmbvGNA6jEroA==", - "dev": true, - "dependencies": { - "rollup-plugin-inject": "^3.0.0" - } + "node_modules/rollup-plugin-inject/node_modules/estree-walker": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", + "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", + "dev": true + }, + "node_modules/rollup-plugin-inject/node_modules/magic-string": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", + "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "dev": true, + "dependencies": { + "sourcemap-codec": "^1.4.8" + } + }, + "node_modules/rollup-plugin-node-polyfills": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/rollup-plugin-node-polyfills/-/rollup-plugin-node-polyfills-0.2.1.tgz", + "integrity": "sha512-4kCrKPTJ6sK4/gLL/U5QzVT8cxJcofO0OU74tnB19F40cmuAKSzH5/siithxlofFEjwvw1YAhPmbvGNA6jEroA==", + "dev": true, + "dependencies": { + "rollup-plugin-inject": "^3.0.0" + } }, "node_modules/rollup-pluginutils": { "version": "2.8.2", @@ -1904,6 +1920,12 @@ "estree-walker": "^0.6.1" } }, + "node_modules/rollup-pluginutils/node_modules/estree-walker": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", + "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", + "dev": true + }, "node_modules/selfsigned": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", @@ -2026,12 +2048,12 @@ } }, "node_modules/strip-literal": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-2.0.0.tgz", - "integrity": "sha512-f9vHgsCWBq2ugHAkGMiiYY+AYG0D/cbloKKg0nhaaaSNsujdGIpVXCNsrJpCKr5M0f4aI31mr13UjY6GAuXCKA==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-2.1.0.tgz", + "integrity": "sha512-Op+UycaUt/8FbN/Z2TWPBLge3jWrP3xj10f3fnYxf052bKuS3EKs1ZQcVGjnEMdsNVAM+plXRdmjrZ/KgG3Skw==", "dev": true, "dependencies": { - "js-tokens": "^8.0.2" + "js-tokens": "^9.0.0" }, "funding": { "url": "https://github.com/sponsors/antfu" @@ -2050,9 +2072,9 @@ } }, "node_modules/tinybench": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.6.0.tgz", - "integrity": "sha512-N8hW3PG/3aOoZAN5V/NSAEDz0ZixDSSt5b/a05iqtpgfLWMSVuCo7w0k2vVvEjdrIoeGqZzweX2WlyioNIHchA==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.8.0.tgz", + "integrity": "sha512-1/eK7zUnIklz4JUUlL+658n58XO2hHLQfSk1Zf2LKieUjxidN16eKFEoDEfjHc3ohofSSqK3X5yO6VGb6iW8Lw==", "dev": true }, "node_modules/tinypool": { @@ -2101,9 +2123,9 @@ } }, "node_modules/typescript": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", - "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.2.tgz", + "integrity": "sha512-NcRtPEOsPFFWjobJEtfihkLCZCXZt/os3zf8nTxjVH3RvTSxjrCamJpbExGvYOF+tFHc3pA65qpdwPbzjohhew==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -2153,9 +2175,9 @@ } }, "node_modules/vite": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.3.1.tgz", - "integrity": "sha512-XBmSKRLXLxiaPYamLv3/hnP/KXDai1NDexN0FpkTaZXTfycHvkRHoenpgl/fvuK/kPbB6xAgoyiryAhQNxYmAQ==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.3.2.tgz", + "integrity": "sha512-6lA7OBHBlXUxiJxbO5aAY2fsHHzDr1q7DvXYnyZycRs2Dz+dXBWuhpWHvmljTRTpQC2uvGmUFFkSHF2vGo90MA==", "dev": true, "dependencies": { "esbuild": "^0.21.3", @@ -2229,10 +2251,168 @@ "url": "https://opencollective.com/vitest" } }, - "node_modules/vite/node_modules/@esbuild/android-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", - "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "node_modules/vitest": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.6.0.tgz", + "integrity": "sha512-H5r/dN06swuFnzNFhq/dnz37bPXnq8xB2xB5JOVk8K09rUtoeNN+LHWkoQ0A/i3hvbUKKcCei9KpbxqHMLhLLA==", + "dev": true, + "dependencies": { + "@vitest/expect": "1.6.0", + "@vitest/runner": "1.6.0", + "@vitest/snapshot": "1.6.0", + "@vitest/spy": "1.6.0", + "@vitest/utils": "1.6.0", + "acorn-walk": "^8.3.2", + "chai": "^4.3.10", + "debug": "^4.3.4", + "execa": "^8.0.1", + "local-pkg": "^0.5.0", + "magic-string": "^0.30.5", + "pathe": "^1.1.1", + "picocolors": "^1.0.0", + "std-env": "^3.5.0", + "strip-literal": "^2.0.0", + "tinybench": "^2.5.1", + "tinypool": "^0.8.3", + "vite": "^5.0.0", + "vite-node": "1.6.0", + "why-is-node-running": "^2.2.2" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/node": "^18.0.0 || >=20.0.0", + "@vitest/browser": "1.6.0", + "@vitest/ui": "1.6.0", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "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/why-is-node-running": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.2.2.tgz", + "integrity": "sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==", + "dev": true, + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/workerd": { + "version": "1.20240620.1", + "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20240620.1.tgz", + "integrity": "sha512-Qoq+RrFNk4pvEO+kpJVn8uJ5TRE9YJx5jX5pC5LjdKlw1XeD8EdXt5k0TbByvWunZ4qgYIcF9lnVxhcDFo203g==", + "dev": true, + "hasInstallScript": true, + "bin": { + "workerd": "bin/workerd" + }, + "engines": { + "node": ">=16" + }, + "optionalDependencies": { + "@cloudflare/workerd-darwin-64": "1.20240620.1", + "@cloudflare/workerd-darwin-arm64": "1.20240620.1", + "@cloudflare/workerd-linux-64": "1.20240620.1", + "@cloudflare/workerd-linux-arm64": "1.20240620.1", + "@cloudflare/workerd-windows-64": "1.20240620.1" + } + }, + "node_modules/wrangler": { + "version": "3.62.0", + "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-3.62.0.tgz", + "integrity": "sha512-TM1Bd8+GzxFw/JzwsC3i/Oss4LTWvIEWXXo1vZhx+7PHcsxdbnQGBBwPurHNJDSu2Pw22+2pCZiUGKexmgJksw==", + "dev": true, + "dependencies": { + "@cloudflare/kv-asset-handler": "0.3.4", + "@esbuild-plugins/node-globals-polyfill": "^0.2.3", + "@esbuild-plugins/node-modules-polyfill": "^0.2.2", + "blake3-wasm": "^2.1.5", + "chokidar": "^3.5.3", + "date-fns": "^3.6.0", + "esbuild": "0.17.19", + "miniflare": "3.20240620.0", + "nanoid": "^3.3.3", + "path-to-regexp": "^6.2.0", + "resolve": "^1.22.8", + "resolve.exports": "^2.0.2", + "selfsigned": "^2.0.1", + "source-map": "^0.6.1", + "unenv": "npm:unenv-nightly@1.10.0-1717606461.a117952", + "xxhash-wasm": "^1.0.1" + }, + "bin": { + "wrangler": "bin/wrangler.js", + "wrangler2": "bin/wrangler.js" + }, + "engines": { + "node": ">=16.17.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + }, + "peerDependencies": { + "@cloudflare/workers-types": "^4.20240620.0" + }, + "peerDependenciesMeta": { + "@cloudflare/workers-types": { + "optional": true + } + } + }, + "node_modules/wrangler/node_modules/@esbuild/android-arm": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", + "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", "cpu": [ "arm" ], @@ -2245,10 +2425,10 @@ "node": ">=12" } }, - "node_modules/vite/node_modules/@esbuild/android-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", - "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "node_modules/wrangler/node_modules/@esbuild/android-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", + "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", "cpu": [ "arm64" ], @@ -2261,10 +2441,10 @@ "node": ">=12" } }, - "node_modules/vite/node_modules/@esbuild/android-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", - "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "node_modules/wrangler/node_modules/@esbuild/android-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", + "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", "cpu": [ "x64" ], @@ -2277,10 +2457,10 @@ "node": ">=12" } }, - "node_modules/vite/node_modules/@esbuild/darwin-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", - "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "node_modules/wrangler/node_modules/@esbuild/darwin-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", + "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==", "cpu": [ "arm64" ], @@ -2293,10 +2473,10 @@ "node": ">=12" } }, - "node_modules/vite/node_modules/@esbuild/darwin-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", - "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "node_modules/wrangler/node_modules/@esbuild/darwin-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", + "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", "cpu": [ "x64" ], @@ -2309,10 +2489,10 @@ "node": ">=12" } }, - "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", - "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "node_modules/wrangler/node_modules/@esbuild/freebsd-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", + "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", "cpu": [ "arm64" ], @@ -2325,10 +2505,10 @@ "node": ">=12" } }, - "node_modules/vite/node_modules/@esbuild/freebsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", - "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "node_modules/wrangler/node_modules/@esbuild/freebsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", + "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", "cpu": [ "x64" ], @@ -2341,10 +2521,10 @@ "node": ">=12" } }, - "node_modules/vite/node_modules/@esbuild/linux-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", - "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "node_modules/wrangler/node_modules/@esbuild/linux-arm": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", + "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", "cpu": [ "arm" ], @@ -2357,10 +2537,10 @@ "node": ">=12" } }, - "node_modules/vite/node_modules/@esbuild/linux-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", - "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "node_modules/wrangler/node_modules/@esbuild/linux-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", + "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", "cpu": [ "arm64" ], @@ -2373,10 +2553,10 @@ "node": ">=12" } }, - "node_modules/vite/node_modules/@esbuild/linux-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", - "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "node_modules/wrangler/node_modules/@esbuild/linux-ia32": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", + "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", "cpu": [ "ia32" ], @@ -2389,10 +2569,10 @@ "node": ">=12" } }, - "node_modules/vite/node_modules/@esbuild/linux-loong64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", - "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "node_modules/wrangler/node_modules/@esbuild/linux-loong64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", + "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", "cpu": [ "loong64" ], @@ -2405,10 +2585,10 @@ "node": ">=12" } }, - "node_modules/vite/node_modules/@esbuild/linux-mips64el": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", - "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "node_modules/wrangler/node_modules/@esbuild/linux-mips64el": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", + "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", "cpu": [ "mips64el" ], @@ -2421,10 +2601,10 @@ "node": ">=12" } }, - "node_modules/vite/node_modules/@esbuild/linux-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", - "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "node_modules/wrangler/node_modules/@esbuild/linux-ppc64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", + "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", "cpu": [ "ppc64" ], @@ -2437,10 +2617,10 @@ "node": ">=12" } }, - "node_modules/vite/node_modules/@esbuild/linux-riscv64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", - "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "node_modules/wrangler/node_modules/@esbuild/linux-riscv64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", + "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", "cpu": [ "riscv64" ], @@ -2453,10 +2633,10 @@ "node": ">=12" } }, - "node_modules/vite/node_modules/@esbuild/linux-s390x": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", - "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "node_modules/wrangler/node_modules/@esbuild/linux-s390x": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", + "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", "cpu": [ "s390x" ], @@ -2469,10 +2649,10 @@ "node": ">=12" } }, - "node_modules/vite/node_modules/@esbuild/linux-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", - "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "node_modules/wrangler/node_modules/@esbuild/linux-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", + "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", "cpu": [ "x64" ], @@ -2485,10 +2665,10 @@ "node": ">=12" } }, - "node_modules/vite/node_modules/@esbuild/netbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", - "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "node_modules/wrangler/node_modules/@esbuild/netbsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", + "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", "cpu": [ "x64" ], @@ -2501,10 +2681,10 @@ "node": ">=12" } }, - "node_modules/vite/node_modules/@esbuild/openbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", - "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "node_modules/wrangler/node_modules/@esbuild/openbsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", + "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", "cpu": [ "x64" ], @@ -2517,10 +2697,10 @@ "node": ">=12" } }, - "node_modules/vite/node_modules/@esbuild/sunos-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", - "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "node_modules/wrangler/node_modules/@esbuild/sunos-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", + "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", "cpu": [ "x64" ], @@ -2533,10 +2713,10 @@ "node": ">=12" } }, - "node_modules/vite/node_modules/@esbuild/win32-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", - "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "node_modules/wrangler/node_modules/@esbuild/win32-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", + "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", "cpu": [ "arm64" ], @@ -2549,10 +2729,10 @@ "node": ">=12" } }, - "node_modules/vite/node_modules/@esbuild/win32-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", - "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "node_modules/wrangler/node_modules/@esbuild/win32-ia32": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", + "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", "cpu": [ "ia32" ], @@ -2565,10 +2745,10 @@ "node": ">=12" } }, - "node_modules/vite/node_modules/@esbuild/win32-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", - "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "node_modules/wrangler/node_modules/@esbuild/win32-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", + "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", "cpu": [ "x64" ], @@ -2581,10 +2761,10 @@ "node": ">=12" } }, - "node_modules/vite/node_modules/esbuild": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", - "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "node_modules/wrangler/node_modules/esbuild": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz", + "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==", "dev": true, "hasInstallScript": true, "bin": { @@ -2594,198 +2774,28 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.21.5", - "@esbuild/android-arm": "0.21.5", - "@esbuild/android-arm64": "0.21.5", - "@esbuild/android-x64": "0.21.5", - "@esbuild/darwin-arm64": "0.21.5", - "@esbuild/darwin-x64": "0.21.5", - "@esbuild/freebsd-arm64": "0.21.5", - "@esbuild/freebsd-x64": "0.21.5", - "@esbuild/linux-arm": "0.21.5", - "@esbuild/linux-arm64": "0.21.5", - "@esbuild/linux-ia32": "0.21.5", - "@esbuild/linux-loong64": "0.21.5", - "@esbuild/linux-mips64el": "0.21.5", - "@esbuild/linux-ppc64": "0.21.5", - "@esbuild/linux-riscv64": "0.21.5", - "@esbuild/linux-s390x": "0.21.5", - "@esbuild/linux-x64": "0.21.5", - "@esbuild/netbsd-x64": "0.21.5", - "@esbuild/openbsd-x64": "0.21.5", - "@esbuild/sunos-x64": "0.21.5", - "@esbuild/win32-arm64": "0.21.5", - "@esbuild/win32-ia32": "0.21.5", - "@esbuild/win32-x64": "0.21.5" - } - }, - "node_modules/vitest": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.6.0.tgz", - "integrity": "sha512-H5r/dN06swuFnzNFhq/dnz37bPXnq8xB2xB5JOVk8K09rUtoeNN+LHWkoQ0A/i3hvbUKKcCei9KpbxqHMLhLLA==", - "dev": true, - "dependencies": { - "@vitest/expect": "1.6.0", - "@vitest/runner": "1.6.0", - "@vitest/snapshot": "1.6.0", - "@vitest/spy": "1.6.0", - "@vitest/utils": "1.6.0", - "acorn-walk": "^8.3.2", - "chai": "^4.3.10", - "debug": "^4.3.4", - "execa": "^8.0.1", - "local-pkg": "^0.5.0", - "magic-string": "^0.30.5", - "pathe": "^1.1.1", - "picocolors": "^1.0.0", - "std-env": "^3.5.0", - "strip-literal": "^2.0.0", - "tinybench": "^2.5.1", - "tinypool": "^0.8.3", - "vite": "^5.0.0", - "vite-node": "1.6.0", - "why-is-node-running": "^2.2.2" - }, - "bin": { - "vitest": "vitest.mjs" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "@edge-runtime/vm": "*", - "@types/node": "^18.0.0 || >=20.0.0", - "@vitest/browser": "1.6.0", - "@vitest/ui": "1.6.0", - "happy-dom": "*", - "jsdom": "*" - }, - "peerDependenciesMeta": { - "@edge-runtime/vm": { - "optional": true - }, - "@types/node": { - "optional": true - }, - "@vitest/browser": { - "optional": true - }, - "@vitest/ui": { - "optional": true - }, - "happy-dom": { - "optional": true - }, - "jsdom": { - "optional": true - } - } - }, - "node_modules/vitest/node_modules/magic-string": { - "version": "0.30.8", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz", - "integrity": "sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==", - "dev": true, - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15" - }, - "engines": { - "node": ">=12" - } - }, - "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/why-is-node-running": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.2.2.tgz", - "integrity": "sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==", - "dev": true, - "dependencies": { - "siginfo": "^2.0.0", - "stackback": "0.0.2" - }, - "bin": { - "why-is-node-running": "cli.js" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/workerd": { - "version": "1.20240610.1", - "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20240610.1.tgz", - "integrity": "sha512-Rtut5GrsODQMh6YU43b9WZ980Wd05Ov1/ds88pT/SoetmXFBvkBzdRfiHiATv+azmGX8KveE0i/Eqzk/yI01ug==", - "dev": true, - "hasInstallScript": true, - "bin": { - "workerd": "bin/workerd" - }, - "engines": { - "node": ">=16" - }, - "optionalDependencies": { - "@cloudflare/workerd-darwin-64": "1.20240610.1", - "@cloudflare/workerd-darwin-arm64": "1.20240610.1", - "@cloudflare/workerd-linux-64": "1.20240610.1", - "@cloudflare/workerd-linux-arm64": "1.20240610.1", - "@cloudflare/workerd-windows-64": "1.20240610.1" - } - }, - "node_modules/wrangler": { - "version": "3.61.0", - "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-3.61.0.tgz", - "integrity": "sha512-feVAp0986x9xL3Dc1zin0ZVXKaqzp7eZur7iPLnpEwjG1Xy4dkVEZ5a1LET94Iyejt1P+EX5lgGcz63H7EfzUw==", - "dev": true, - "dependencies": { - "@cloudflare/kv-asset-handler": "0.3.3", - "@esbuild-plugins/node-globals-polyfill": "^0.2.3", - "@esbuild-plugins/node-modules-polyfill": "^0.2.2", - "blake3-wasm": "^2.1.5", - "chokidar": "^3.5.3", - "esbuild": "0.17.19", - "miniflare": "3.20240610.1", - "nanoid": "^3.3.3", - "path-to-regexp": "^6.2.0", - "resolve": "^1.22.8", - "resolve.exports": "^2.0.2", - "selfsigned": "^2.0.1", - "source-map": "^0.6.1", - "unenv": "npm:unenv-nightly@1.10.0-1717606461.a117952", - "xxhash-wasm": "^1.0.1" - }, - "bin": { - "wrangler": "bin/wrangler.js", - "wrangler2": "bin/wrangler.js" - }, - "engines": { - "node": ">=16.17.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - }, - "peerDependencies": { - "@cloudflare/workers-types": "^4.20240605.0" - }, - "peerDependenciesMeta": { - "@cloudflare/workers-types": { - "optional": true - } + "@esbuild/android-arm": "0.17.19", + "@esbuild/android-arm64": "0.17.19", + "@esbuild/android-x64": "0.17.19", + "@esbuild/darwin-arm64": "0.17.19", + "@esbuild/darwin-x64": "0.17.19", + "@esbuild/freebsd-arm64": "0.17.19", + "@esbuild/freebsd-x64": "0.17.19", + "@esbuild/linux-arm": "0.17.19", + "@esbuild/linux-arm64": "0.17.19", + "@esbuild/linux-ia32": "0.17.19", + "@esbuild/linux-loong64": "0.17.19", + "@esbuild/linux-mips64el": "0.17.19", + "@esbuild/linux-ppc64": "0.17.19", + "@esbuild/linux-riscv64": "0.17.19", + "@esbuild/linux-s390x": "0.17.19", + "@esbuild/linux-x64": "0.17.19", + "@esbuild/netbsd-x64": "0.17.19", + "@esbuild/openbsd-x64": "0.17.19", + "@esbuild/sunos-x64": "0.17.19", + "@esbuild/win32-arm64": "0.17.19", + "@esbuild/win32-ia32": "0.17.19", + "@esbuild/win32-x64": "0.17.19" } }, "node_modules/ws": { diff --git a/ts/sbd-server/package.json b/ts/sbd-server/package.json index ec417b3..ed1e3e4 100644 --- a/ts/sbd-server/package.json +++ b/ts/sbd-server/package.json @@ -12,13 +12,12 @@ "test": "npm run test:fmt && npm run test:type && npm run test:unit" }, "devDependencies": { - "@cloudflare/workers-types": "^4.20240614.0", - "@types/ws": "^8.5.10", + "@cloudflare/workers-types": "^4.20240620.0", + "node-cleanup": "^2.1.2", "prettier": "^3.3.2", - "typescript": "^5.4.5", + "typescript": "^5.5.2", "vitest": "^1.6.0", - "wrangler": "^3.61.0", - "ws": "^8.17.1" + "wrangler": "^3.62.0" }, "dependencies": { "@noble/ed25519": "^2.1.0", diff --git a/ts/sbd-server/server-o-bahn-runner.mjs b/ts/sbd-server/server-o-bahn-runner.mjs index 0b0b1d8..9cd0357 100755 --- a/ts/sbd-server/server-o-bahn-runner.mjs +++ b/ts/sbd-server/server-o-bahn-runner.mjs @@ -2,7 +2,8 @@ import { spawn } from 'node:child_process' import { createInterface } from 'node:readline' -import { stdin, exit } from 'node:process' +import { stdin, exit, platform, pid, kill } from 'node:process' +import nodeCleanup from 'node-cleanup' const reReady = new RegExp('^.*Ready on http:\/\/(.*)$', 'm') @@ -16,7 +17,11 @@ class Srv { } static async spawn() { - const proc = spawn('npx', [ + let procName = 'npx' + if (platform.startsWith('win')) { + procName = 'npx.exe' + } + const proc = spawn(procName, [ 'wrangler', 'dev', '--show-interactive-dev-session', @@ -50,13 +55,8 @@ class Srv { return this.#addr } - async kill() { - if (!this.#proc.kill('SIGTERM')) { - await new Promise((r, _) => { - setTimeout(r, 1000) - }) - this.#proc.kill('SIGKILL') - } + kill() { + this.#proc.kill('SIGKILL') } } @@ -64,6 +64,13 @@ console.log('CMD/READY') let _glb_srv = null +nodeCleanup((_code, sig) => { + if (_glb_srv) { + _glb_srv.kill() + } + kill(pid, sig) +}) + const rl = createInterface({ input: stdin, }) @@ -71,13 +78,16 @@ const rl = createInterface({ for await (const line of rl) { if (line === 'CMD/START') { if (_glb_srv) { - await _glb_srv.kill() + _glb_srv.kill() } _glb_srv = await Srv.spawn() const addr = _glb_srv.addr() console.log(`CMD/START/${addr}`) } else { console.error('INVALID CMD: ' + line) + if (_glb_srv) { + _glb_srv.kill() + } exit(127) } } diff --git a/ts/sbd-server/src/index.test.ts b/ts/sbd-server/src/index.test.ts deleted file mode 100644 index cd6fcfc..0000000 --- a/ts/sbd-server/src/index.test.ts +++ /dev/null @@ -1,151 +0,0 @@ -import { unstable_dev } from 'wrangler'; -import type { UnstableDevWorker } from 'wrangler'; -import { describe, expect, assert, it, beforeAll, afterAll } from 'vitest'; -import WebSocket from 'ws'; -import { ed } from './ed.ts'; -import { encodeQuery, encodeSignedQuery } from './msg.ts'; - -type RecvFunction = (msg: Array) => void; - -// helper class for client websocket testing -class C { - ws: WebSocket; - sk: Uint8Array; - pk: Uint8Array; - pend: Array; - res: RecvFunction | null; - closing: boolean; - - constructor(sk: Uint8Array, pk: Uint8Array, ws: WebSocket) { - this.sk = sk; - this.pk = pk; - this.ws = ws; - this.pend = []; - this.res = null; - this.closing = false; - } - - static connect(addr: string): Promise { - return new Promise((res, _) => { - const sk = ed.utils.randomPrivateKey(); - const pk = ed.getPublicKey(sk); - const q = encodeQuery({ - nodePubKey: pk, - nonce: Date.now(), - }); - const s = ed.sign(new TextEncoder().encode(q), sk); - const sq = encodeSignedQuery(s, q); - - const ws = new WebSocket(`ws://${addr}/?${sq}`); - const out = new C(sk, pk, ws); - - ws.on('error', (err) => { - console.error(`error: ${err}`); - throw err; - }); - ws.on('open', async () => { - const list = await out.recv(); - if (list.length !== 1) { - throw new Error('invalid recv length'); - } - const nonce = list[0]; - const handshake = ed.sign(nonce, out.sk); - await out._send(handshake); - res(out); - }); - ws.on('close', (code, reason) => { - if (!out.closing) { - const v = `close code ${code} reason ${reason}`; - console.error(v); - throw new Error(v); - } - }); - ws.on('message', (msg) => { - if (!(msg instanceof Uint8Array)) { - throw new Error('invalid rcv message type'); - } - out.pend.push(msg); - if (out.res) { - const res = out.res; - out.res = null; - res(out.pend.splice(0)); - } - }); - }); - } - - close() { - this.closing = true; - this.ws.close(); - } - - pubKey(): Uint8Array { - return this.pk; - } - - _send(data: Uint8Array): Promise { - return new Promise((res, _) => { - this.ws.send(data, {}, (e: any) => { - if (e) { - throw e; - } - res(null); - }); - }); - } - - async send(peer: Uint8Array, data: string) { - const enc = new TextEncoder().encode(data); - const out = new Uint8Array(peer.byteLength + enc.byteLength); - out.set(peer); - out.set(enc, peer.byteLength); - await this.ws.send(out); - } - - recv(): Promise> { - if (this.pend.length) { - return Promise.resolve(this.pend.splice(0)); - } - return new Promise((res, _) => { - this.res = res; - }); - } -} - -describe('Worker', () => { - let worker: UnstableDevWorker; - let addr: string; - - beforeAll(async () => { - worker = await unstable_dev('src/index.ts', { - experimental: { disableExperimentalWarning: true }, - }); - addr = worker.address + ':' + worker.port; - }); - - afterAll(async () => { - await worker.stop(); - }); - - it('now', async () => { - const res = await worker.fetch('http://' + addr + '/now'); - const json = (await res.json()) as { now: number }; - expect(json.now).to.be.above(Date.now() - 5000); - expect(json.now).to.be.below(Date.now() + 5000); - }); - - it('websocket', async () => { - const wsA = await C.connect(addr); - const wsB = await C.connect(addr); - - const recvPromiseA = wsA.recv(); - await wsB.send(wsA.pubKey(), 'test'); - const result = (await recvPromiseA)[0]; - - wsA.close(); - wsB.close(); - - expect(new Uint8Array(result).subarray(0, 32)).toEqual(wsB.pubKey()); - expect(new TextDecoder().decode(result.subarray(32))).toEqual('test'); - }); -}); diff --git a/ts/sbd-server/wrangler.toml b/ts/sbd-server/wrangler.toml index c2e2f6e..3f9a3bf 100644 --- a/ts/sbd-server/wrangler.toml +++ b/ts/sbd-server/wrangler.toml @@ -1,6 +1,6 @@ -name = "tx5-signal-cf" +name = "sbd-signal" main = "src/index.ts" -compatibility_date = "2024-06-18" +compatibility_date = "2024-06-03" [[durable_objects.bindings]] name = "SIGNAL" From 52343beaed0a268c640508d4f7a63c70a18d9475 Mon Sep 17 00:00:00 2001 From: neonphog Date: Fri, 28 Jun 2024 15:44:58 -0600 Subject: [PATCH 07/36] try through node itself --- ts/sbd-server/server-o-bahn-runner.mjs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/ts/sbd-server/server-o-bahn-runner.mjs b/ts/sbd-server/server-o-bahn-runner.mjs index 9cd0357..aa1a392 100755 --- a/ts/sbd-server/server-o-bahn-runner.mjs +++ b/ts/sbd-server/server-o-bahn-runner.mjs @@ -17,12 +17,8 @@ class Srv { } static async spawn() { - let procName = 'npx' - if (platform.startsWith('win')) { - procName = 'npx.exe' - } - const proc = spawn(procName, [ - 'wrangler', + const proc = spawn('node', [ + './node_modules/.bin/wrangler', 'dev', '--show-interactive-dev-session', 'false', From 0fac19714a92b1dae2f7890010ffb643305294c9 Mon Sep 17 00:00:00 2001 From: neonphog Date: Fri, 28 Jun 2024 16:26:59 -0600 Subject: [PATCH 08/36] do we need to resume? --- ts/sbd-server/server-o-bahn-runner.mjs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ts/sbd-server/server-o-bahn-runner.mjs b/ts/sbd-server/server-o-bahn-runner.mjs index aa1a392..e7078a3 100755 --- a/ts/sbd-server/server-o-bahn-runner.mjs +++ b/ts/sbd-server/server-o-bahn-runner.mjs @@ -67,6 +67,8 @@ nodeCleanup((_code, sig) => { kill(pid, sig) }) +stdin.resume() + const rl = createInterface({ input: stdin, }) From 171f70ffe855944ac4310a3de6212ee4a1ffe521 Mon Sep 17 00:00:00 2001 From: neonphog Date: Fri, 28 Jun 2024 16:55:47 -0600 Subject: [PATCH 09/36] only run cf test on linux --- .github/workflows/test.yml | 4 ++++ Makefile | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 970ccc1..b80d953 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -63,3 +63,7 @@ jobs: env: RUST_BACKTRACE: 1 run: make test + + - name: Cf Test + if: matrix.os == 'ubuntu-latest' + run: make cf-test diff --git a/Makefile b/Makefile index dbbbd80..8c2841b 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ # sbd Makefile -.PHONY: default publish-all publish bump test static +.PHONY: default publish-all publish bump test cf-test static SHELL = /usr/bin/env sh -eu @@ -56,6 +56,8 @@ bump: test: cargo build --all-targets RUST_BACKTRACE=1 cargo test + +cf-test: cd ts/sbd-server && npm ci cd ts/sbd-server && npm run test:unit cd ts/sbd-server && cargo run --manifest-path ../../rust/sbd-o-bahn-server-tester/Cargo.toml -- node ./server-o-bahn-runner.mjs From 01b6908892c1c805ff28a149e30b7bec7d4ce8dd Mon Sep 17 00:00:00 2001 From: neonphog Date: Mon, 1 Jul 2024 17:15:48 -0600 Subject: [PATCH 10/36] protocol update --- ts/sbd-server/src/index.ts | 212 ++++++++++++++------------ ts/sbd-server/src/msg.test.ts | 134 ++++++++++++++--- ts/sbd-server/src/msg.ts | 275 ++++++++++++++++++++++++++++++---- 3 files changed, 476 insertions(+), 145 deletions(-) diff --git a/ts/sbd-server/src/index.ts b/ts/sbd-server/src/index.ts index 296c56d..2d58f1a 100644 --- a/ts/sbd-server/src/index.ts +++ b/ts/sbd-server/src/index.ts @@ -1,33 +1,18 @@ -/** - * This is currently a PoC, but working towards something production ready. - * - * What we need to do: - * - * - batching: clients should batch requests for a number of milliseconds, - * sending within say 5ms if no additional messages are received, but never - * more than 20ms after the first received message. one batch should not - * exceed some byte count... 4096? - * - signing: nodes will be identified by an ed25519 pub key, messages - * will be individually signed, like: - * `["sig-base64","[\"fwd\",42,\"dest-base64\",\"msg-content\"]"]` - * - websocket hello: to verify the client can sign with that pubkey - * must be received within some milliseconds of establishing the ws connection - * set a DO "alarm"? - * `["sig-base64","[\"hello\",0]"]` - * - error if multiple websockets connected to one pubkey do - * - ratelimit messages within a single do instance - * - ratelimit messages (at larger rate) for an ip - * - nonce/message id must be zero for the hello message - * - nonce/message id must start at 1 for each peer communicated with - * and increment by exactly 1 for each additional message sent. - * we will need to maintain a map of these peer message ids that - * must be reset/cleared if the websocket is closed. - */ - import { RateLimit } from './rate-limit.ts'; -import { verifySignedQuery, verifySignedHandshake } from './msg.ts'; import { err } from './err.ts'; +import { ed } from './ed.ts'; import { toB64Url, fromB64Url } from './b64.ts'; +import { + Msg, + MsgLbrt, + MsgLidl, + MsgAreq, + MsgAres, + MsgSrdy, + MsgKeep, + MsgNone, + MsgForward, +} from './msg.ts'; export interface Env { SIGNAL: DurableObjectNamespace; @@ -51,14 +36,25 @@ async function ipRateLimit(env: Env, ip: string) { } } -function checkNonce(nonce: number) { - const now = Date.now(); - if (nonce < now - 5000) { - throw err('nonce older than 5 sec, update clock, or call /now', 400); +function parsePubKey(path: string): { + pubKeyStr: string; + pubKeyBytes: Uint8Array; +} { + const parts: Array = path.split('/'); + + if (parts.length !== 2) { + throw err('expected single pubKey item on path', 400); } - if (nonce > now + 5000) { - throw err('nonce newer than 5 sec, update clock, or call /now', 400); + + const pubKeyStr = parts[1]; + + const pubKeyBytes = fromB64Url(parts[1]); + + if (pubKeyBytes.length !== 32) { + throw err('invalid pubKey length', 400); } + + return { pubKeyStr, pubKeyBytes }; } export default { @@ -75,39 +71,22 @@ export default { const method = request.method; const url = new URL(request.url); - const path: string = url.pathname; - // TODO - check headers for content-length / chunked encoding and reject? if (method !== 'GET') { throw err('expected GET', 400); } - if (path === '/now') { - return Response.json({ now: Date.now() }); - } - - if (path !== '/') { - throw err('expected root path ("/")', 400); - } - - // @ts-expect-error // cf typescript bug // - const nodeId: string = url.searchParams.get('k'); - // @ts-expect-error // cf typescript bug // - const n: string = url.searchParams.get('n'); - // @ts-expect-error // cf typescript bug // - const s: string = url.searchParams.get('s'); + const { pubKeyStr } = parsePubKey(url.pathname); - const q = verifySignedQuery(nodeId, n, s); - checkNonce(q.nonce); - - // DO instanced by our nodeId - const id = env.SIGNAL.idFromName(nodeId); + // DO instanced by our pubKey + const id = env.SIGNAL.idFromName(pubKeyStr); const stub = env.SIGNAL.get(id); // just forward the full request / response return await stub.fetch(request); } catch (e: any) { + console.error('error', e.toString()); return new Response(JSON.stringify({ err: e.toString() }), { status: e.status || 500, }); @@ -147,15 +126,16 @@ export class DoSignal implements DurableObject { try { const ip = request.headers.get('cf-connecting-ip') || 'no-ip'; const url = new URL(request.url); - const path: string = url.pathname; - if (path === '/fwd') { + if (url.pathname === '/fwd') { const message = await request.arrayBuffer(); for (const ws of this.state.getWebSockets()) { ws.send(message); } return new Response('ok'); - } else if (path === '/') { + } else { + const { pubKeyStr, pubKeyBytes } = parsePubKey(url.pathname); + if (this.state.getWebSockets().length > 0) { throw err('websocket already connected', 400); } @@ -170,23 +150,30 @@ export class DoSignal implements DurableObject { const nonce = new Uint8Array(32); crypto.getRandomValues(nonce); - // @ts-expect-error // cf typescript bug // - const nodeId = fromB64Url(url.searchParams.get('k')); - server.serializeAttachment({ - nodeId, + pubKey: pubKeyBytes, ip, nonce, valid: false, }); - server.send(nonce); + server.send(new MsgLbrt(8000).encoded()); + server.send(new MsgLidl(10000).encoded()); + server.send(new MsgAreq(nonce).encoded()); + + console.log( + 'webSocketOpen', + JSON.stringify({ + pubKey: pubKeyStr, + ip, + nonce: toB64Url(nonce), + }), + ); return new Response(null, { status: 101, webSocket: client }); - } else { - throw err('invalid path', 400); } } catch (e: any) { + console.error('error', e.toString()); return new Response(JSON.stringify({ err: e.toString() }), { status: e.status || 500, }); @@ -198,9 +185,9 @@ export class DoSignal implements DurableObject { async webSocketMessage(ws: WebSocket, message: ArrayBuffer | string) { await this.state.blockConcurrencyWhile(async () => { try { - const { nodeId, ip, nonce, valid } = ws.deserializeAttachment(); - if (!nodeId) { - throw err('no associated nodeId'); + const { pubKey, ip, nonce, valid } = ws.deserializeAttachment(); + if (!pubKey) { + throw err('no associated pubKey'); } if (!ip) { throw err('no associated ip'); @@ -213,58 +200,91 @@ export class DoSignal implements DurableObject { } // convert strings into binary - let msg: Uint8Array; + let msgRaw: Uint8Array; if (message instanceof ArrayBuffer) { - msg = new Uint8Array(message); + msgRaw = new Uint8Array(message); } else { const enc = new TextEncoder(); - msg = enc.encode(message); + msgRaw = enc.encode(message); } + const msg = Msg.parse(msgRaw); + if (!valid) { if (!nonce) { throw err('no associated nonce'); } - verifySignedHandshake(nodeId, nonce, msg); - ws.serializeAttachment({ - nodeId, - ip, - nonce: true, // don't need to keep the actual nonce anymore - valid: true, - }); + + if (msg instanceof MsgAres) { + if (!ed.verify(msg.signature(), nonce, pubKey)) { + throw err('invalid handshake signature', 400); + } + console.log('webSocketSignatureVerified'); + + ws.send(new MsgSrdy().encoded()); + + ws.serializeAttachment({ + pubKey, + ip, + nonce: true, // don't need to keep the actual nonce anymore + valid: true, + }); + } else { + throw err(`invalid handshake message type ${msg.type()}`); + } } else { - if (msg.byteLength < 32) { - throw err('invalid destination', 400); + if (msg instanceof MsgNone) { + // no-op + } else if (msg instanceof MsgKeep) { + // keep alive + } else if (msg instanceof MsgForward) { + // extract the destination pubKey (slice does a copy) + const dest = msg.pubKey().slice(0); + + // overwrite the destination pubKey with the source (our) pubKey + // the pubKey() function returns a reference, so editing it + // alters the message that will be sent + msg.pubKey().set(pubKey, 0); + + const req = new Request('http://do/fwd', { + method: 'POST', + body: msg.encoded(), + }); + + const id = this.env.SIGNAL.idFromName(toB64Url(dest)); + const stub = this.env.SIGNAL.get(id); + + // intentionally ignore errors here + await stub.fetch(req); + } else { + throw err(`invalid post-handshake message type: ${msg.type()}`); } - - const dest = new Uint8Array(32); - dest.set(msg.subarray(0, 32)); - msg.set(nodeId); - - const req = new Request('http://do/fwd', { - method: 'POST', - body: msg, - }); - - const id = this.env.SIGNAL.idFromName(toB64Url(dest)); - const stub = this.env.SIGNAL.get(id); - - // intentionally ignore errors here - await stub.fetch(req); } } catch (e: any) { + console.error('error', e.toString()); ws.close(4000 + (e.status || 500), e.toString()); } }); } - // if the websocket is closed... close the websocket?? async webSocketClose( ws: WebSocket, code: number, reason: string, wasClean: boolean, ) { - ws.close(code, reason); + const { pubKey, ip, nonce, valid } = ws.deserializeAttachment(); + console.log( + 'webSocketClose', + JSON.stringify({ + pubKey: toB64Url(pubKey), + ip, + nonce: nonce instanceof Uint8Array ? toB64Url(nonce) : nonce, + valid, + code, + reason, + wasClean, + }), + ); } } diff --git a/ts/sbd-server/src/msg.test.ts b/ts/sbd-server/src/msg.test.ts index 3952176..ca521f7 100644 --- a/ts/sbd-server/src/msg.test.ts +++ b/ts/sbd-server/src/msg.test.ts @@ -1,30 +1,128 @@ import { describe, expect, assert, it, beforeAll, afterAll } from 'vitest'; -import { encodeQuery, encodeSignedQuery, verifySignedQuery } from './msg.ts'; +import { + Msg, + MsgLbrt, + MsgLidl, + MsgAreq, + MsgAres, + MsgSrdy, + MsgKeep, + MsgNone, + MsgForward, +} from './msg.ts'; import { ed } from './ed.ts'; describe('Msg', () => { - it('query safe', async () => { - for (let i = 0; i < 100; ++i) { - const sk = ed.utils.randomPrivateKey(); - const pk = ed.getPublicKey(sk); + it('lbrt', async () => { + const orig = new MsgLbrt(42); + expect(orig.type()).equals('lbrt'); + expect(orig.limit()).equals(42); + const parsed = Msg.parse(orig.encoded()); + expect(parsed.type()).equals('lbrt'); + if (parsed instanceof MsgLbrt) { + expect(parsed.limit()).equals(42); + } else { + throw 'invalid type'; + } + }); + + it('lidl', async () => { + const orig = new MsgLidl(42); + expect(orig.type()).equals('lidl'); + expect(orig.limit()).equals(42); + const parsed = Msg.parse(orig.encoded()); + expect(parsed.type()).equals('lidl'); + if (parsed instanceof MsgLidl) { + expect(parsed.limit()).equals(42); + } else { + throw 'invalid type'; + } + }); + + it('areq', async () => { + const ononce = new Uint8Array([ + 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, + 2, 3, 4, 5, 6, 7, 8, + ]); + const orig = new MsgAreq(ononce); + expect(orig.type()).equals('areq'); + expect(orig.nonce()).deep.equals(ononce); + const parsed = Msg.parse(orig.encoded()); + expect(parsed.type()).equals('areq'); + if (parsed instanceof MsgAreq) { + expect(parsed.nonce()).deep.equals(ononce); + } else { + throw 'invalid type'; + } + }); - const q = encodeQuery({ - nodePubKey: pk, - nonce: Date.now(), - }); + it('ares', async () => { + const osig = new Uint8Array([ + 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, + 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, + 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, + ]); + const orig = new MsgAres(osig); + expect(orig.type()).equals('ares'); + expect(orig.signature()).deep.equals(osig); + const parsed = Msg.parse(orig.encoded()); + expect(parsed.type()).equals('ares'); + if (parsed instanceof MsgAres) { + expect(parsed.signature()).deep.equals(osig); + } else { + throw 'invalid type'; + } + }); - const s = ed.sign(new TextEncoder().encode(q), sk); + it('srdy', async () => { + const orig = new MsgSrdy(); + expect(orig.type()).equals('srdy'); + const parsed = Msg.parse(orig.encoded()); + expect(parsed.type()).equals('srdy'); + if (!(parsed instanceof MsgSrdy)) { + throw 'invalid type'; + } + }); - const sq = new URL('none:?' + encodeSignedQuery(s, q)); + it('keep', async () => { + const orig = new MsgKeep(); + expect(orig.type()).equals('keep'); + const parsed = Msg.parse(orig.encoded()); + expect(parsed.type()).equals('keep'); + if (!(parsed instanceof MsgKeep)) { + throw 'invalid type'; + } + }); - // @ts-expect-error // cf typescript bug // - const ddk: string = sq.searchParams.get('k'); - // @ts-expect-error // cf typescript bug // - const ddn: string = sq.searchParams.get('n'); - // @ts-expect-error // cf typescript bug // - const dds: string = sq.searchParams.get('s'); + it('none', async () => { + const unknown = new Uint8Array([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 23, 23, 23, 23, 0, 1, 0, 2, 0, 3, 0, 4, + ]); + const parsed = Msg.parse(unknown); + expect(parsed.type()).equals('none'); + if (!(parsed instanceof MsgNone)) { + throw 'invalid type'; + } + }); - verifySignedQuery(ddk, ddn, dds); + it('forward', async () => { + const opk = new Uint8Array([ + 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, + 2, 3, 4, 5, 6, 7, 8, + ]); + const odata = new Uint8Array([1, 2, 3, 4]); + const orig = MsgForward.build(opk, odata); + expect(orig.type()).equals('forward'); + expect(orig.pubKey()).deep.equals(opk); + expect(orig.payload()).deep.equals(odata); + const parsed = Msg.parse(orig.encoded()); + expect(parsed.type()).equals('forward'); + if (parsed instanceof MsgForward) { + expect(parsed.pubKey()).deep.equals(opk); + expect(parsed.payload()).deep.equals(odata); + } else { + throw 'invalid type'; } }); }); diff --git a/ts/sbd-server/src/msg.ts b/ts/sbd-server/src/msg.ts index c615831..9ada23f 100644 --- a/ts/sbd-server/src/msg.ts +++ b/ts/sbd-server/src/msg.ts @@ -2,46 +2,259 @@ import { ed } from './ed.ts'; import { err } from './err.ts'; import { toB64Url, fromB64Url } from './b64.ts'; -interface Query { - nodePubKey: Uint8Array; - nonce: number; +function cmp(a: Uint8Array, b: Uint8Array): boolean { + if (a.byteLength !== b.byteLength) { + return false; + } + for (let i = 0; i < a.byteLength; ++i) { + if (a[i] !== b[i]) { + return false; + } + } + return true; } -export function encodeQuery(query: Query): string { - const k = toB64Url(query.nodePubKey); - return `k=${k}&n=${query.nonce}`; +const CMD: Uint8Array = new Uint8Array(28); + +export const MSG_T_LBRT: string = 'lbrt'; +const MSG_B_LBRT: Uint8Array = new TextEncoder().encode(MSG_T_LBRT); + +export const MSG_T_LIDL: string = 'lidl'; +const MSG_B_LIDL: Uint8Array = new TextEncoder().encode(MSG_T_LIDL); + +export const MSG_T_AREQ: string = 'areq'; +const MSG_B_AREQ: Uint8Array = new TextEncoder().encode(MSG_T_AREQ); + +export const MSG_T_ARES: string = 'ares'; +const MSG_B_ARES: Uint8Array = new TextEncoder().encode(MSG_T_ARES); + +export const MSG_T_SRDY: string = 'srdy'; +const MSG_B_SRDY: Uint8Array = new TextEncoder().encode(MSG_T_SRDY); + +export const MSG_T_KEEP: string = 'keep'; +const MSG_B_KEEP: Uint8Array = new TextEncoder().encode(MSG_T_KEEP); + +export const MSG_T_NONE: string = 'none'; +const MSG_B_NONE: Uint8Array = new TextEncoder().encode(MSG_T_NONE); + +export const MSG_T_FORWARD: string = 'forward'; + +export class Msg { + #bytes: Uint8Array; + #type: string; + + constructor(bytes: Uint8Array, type: string) { + this.#bytes = bytes; + this.#type = type; + } + + static parse( + bytes: Uint8Array, + ): MsgLbrt | MsgLidl | MsgAreq | MsgAres | MsgSrdy | MsgKeep { + if (bytes.byteLength < 32) { + throw err(`invalid msg length ${bytes.byteLength}`, 400); + } + + if (cmp(bytes.subarray(0, 28), CMD)) { + if (cmp(bytes.subarray(28, 32), MSG_B_LBRT)) { + if (bytes.byteLength !== 32 + 4) { + throw err( + `invalid lbrt msg length, expected 36, got: ${bytes.byteLength}`, + 400, + ); + } + const limit = new DataView(bytes.buffer).getInt32(32, false); + return new MsgLbrt(limit); + } else if (cmp(bytes.subarray(28, 32), MSG_B_LIDL)) { + if (bytes.byteLength !== 32 + 4) { + throw err( + `invalid lidl msg length, expected 36, got: ${bytes.byteLength}`, + 400, + ); + } + const limit = new DataView(bytes.buffer).getInt32(32, false); + return new MsgLidl(limit); + } else if (cmp(bytes.subarray(28, 32), MSG_B_AREQ)) { + if (bytes.byteLength !== 32 + 32) { + throw err( + `invalid areq msg length, expected 64, got: ${bytes.byteLength}`, + 400, + ); + } + const nonce = bytes.slice(32); + return new MsgAreq(nonce); + } else if (cmp(bytes.subarray(28, 32), MSG_B_ARES)) { + if (bytes.byteLength !== 32 + 64) { + throw err( + `invalid ares msg length, expected 96, got: ${bytes.byteLength}`, + 400, + ); + } + const signature = bytes.slice(32); + return new MsgAres(signature); + } else if (cmp(bytes.subarray(28, 32), MSG_B_SRDY)) { + if (bytes.byteLength !== 32) { + throw err( + `invalid srdy msg length, expected 32, got: ${bytes.byteLength}`, + 400, + ); + } + return new MsgSrdy(); + } else if (cmp(bytes.subarray(28, 32), MSG_B_KEEP)) { + if (bytes.byteLength !== 32) { + throw err( + `invalid keep msg length, expected 32, got: ${bytes.byteLength}`, + 400, + ); + } + return new MsgKeep(); + } else { + return new MsgNone(); + } + } else { + return new MsgForward(bytes); + } + } + + type(): string { + return this.#type; + } + + encoded(): Uint8Array { + return this.#bytes; + } } -export function encodeSignedQuery( - signature: Uint8Array, - query: string, -): string { - const s = toB64Url(signature); - return `${query}&s=${s}`; +export class MsgLbrt extends Msg { + #limit: number; + + constructor(limit: number) { + const bytes = new Uint8Array(32 + 4); + bytes.set(CMD, 0); + bytes.set(MSG_B_LBRT, 28); + new DataView(bytes.buffer).setInt32(32, limit, false); + + super(bytes, MSG_T_LBRT); + + this.#limit = limit; + } + + limit(): number { + return this.#limit; + } } -export function verifySignedQuery(k: string, n: string, s: string): Query { - const query = { - nodePubKey: fromB64Url(k), - nonce: parseFloat(n), - }; - const enc = new TextEncoder().encode(encodeQuery(query)); - const sig = fromB64Url(s); - if (!ed.verify(sig, enc, query.nodePubKey)) { - throw err('invalid query signature', 400); +export class MsgLidl extends Msg { + #limit: number; + + constructor(limit: number) { + const bytes = new Uint8Array(32 + 4); + bytes.set(CMD, 0); + bytes.set(MSG_B_LIDL, 28); + new DataView(bytes.buffer).setInt32(32, limit, false); + + super(bytes, MSG_T_LIDL); + + this.#limit = limit; + } + + limit(): number { + return this.#limit; } - return query; } -export function verifySignedHandshake( - pk: Uint8Array, - nonce: Uint8Array, - sig: Uint8Array, -) { - if (sig.byteLength !== 64) { - throw err(`invalid signature length ${sig.byteLength}`, 400); +export class MsgAreq extends Msg { + #nonce: Uint8Array; + + constructor(nonce: Uint8Array) { + const bytes = new Uint8Array(32 + 32); + bytes.set(CMD, 0); + bytes.set(MSG_B_AREQ, 28); + bytes.set(nonce, 32); + + super(bytes, MSG_T_AREQ); + + this.#nonce = nonce; + } + + nonce(): Uint8Array { + return this.#nonce; + } +} + +export class MsgAres extends Msg { + #signature: Uint8Array; + + constructor(signature: Uint8Array) { + const bytes = new Uint8Array(32 + 64); + bytes.set(CMD, 0); + bytes.set(MSG_B_ARES, 28); + bytes.set(signature, 32); + + super(bytes, MSG_T_ARES); + + this.#signature = signature; + } + + signature(): Uint8Array { + return this.#signature; + } +} + +export class MsgSrdy extends Msg { + constructor() { + const bytes = new Uint8Array(32); + bytes.set(CMD, 0); + bytes.set(MSG_B_SRDY, 28); + + super(bytes, MSG_T_SRDY); + } +} + +export class MsgKeep extends Msg { + constructor() { + const bytes = new Uint8Array(32); + bytes.set(CMD, 0); + bytes.set(MSG_B_KEEP, 28); + + super(bytes, MSG_T_KEEP); + } +} + +export class MsgNone extends Msg { + constructor() { + const bytes = new Uint8Array(32); + bytes.set(CMD, 0); + bytes.set(MSG_B_NONE, 28); + + super(bytes, MSG_T_NONE); + } +} + +export class MsgForward extends Msg { + constructor(bytes: Uint8Array) { + super(bytes, MSG_T_FORWARD); + } + + static build(pubKey: Uint8Array, payload: Uint8Array): MsgForward { + if (pubKey.byteLength !== 32) { + throw err( + `invalid pubKey length, expected 32, got: ${pubKey.byteLength}`, + 400, + ); + } + const bytes = new Uint8Array(32 + payload.byteLength); + bytes.set(pubKey, 0); + bytes.set(payload, 32); + + return new MsgForward(bytes); + } + + pubKey(): Uint8Array { + return this.encoded().subarray(0, 32); } - if (!ed.verify(sig, nonce, pk)) { - throw err('invalid handshake signature', 400); + + payload(): Uint8Array { + return this.encoded().subarray(32); } } From 4cb9928ca18acfef57b837931e8cb3c2b933afc8 Mon Sep 17 00:00:00 2001 From: neonphog Date: Thu, 4 Jul 2024 09:13:46 -0600 Subject: [PATCH 11/36] ensure message ordering through batching --- ts/sbd-server/src/index.ts | 221 +++++++++++++++++++++++-------------- 1 file changed, 138 insertions(+), 83 deletions(-) diff --git a/ts/sbd-server/src/index.ts b/ts/sbd-server/src/index.ts index 2d58f1a..86a7cf1 100644 --- a/ts/sbd-server/src/index.ts +++ b/ts/sbd-server/src/index.ts @@ -1,3 +1,4 @@ +import { DurableObject } from 'cloudflare:workers'; import { RateLimit } from './rate-limit.ts'; import { err } from './err.ts'; import { ed } from './ed.ts'; @@ -14,6 +15,8 @@ import { MsgForward, } from './msg.ts'; +const BATCH_DUR_MS = 20; + export interface Env { SIGNAL: DurableObjectNamespace; RATE_LIMIT: DurableObjectNamespace; @@ -22,12 +25,8 @@ export interface Env { async function ipRateLimit(env: Env, ip: string) { try { const ipId = env.RATE_LIMIT.idFromName(ip); - const ipStub = env.RATE_LIMIT.get(ipId); - const res = await ipStub.fetch(new Request(`http://do`)); - if (res.status !== 200) { - throw err(`limit bad status ${res.status}`, 429); - } - const { limit } = (await res.json()) as { limit: number }; + const ipStub = env.RATE_LIMIT.get(ipId) as DurableObjectStub; + const limit = await ipStub.trackRequest(Date.now(), 1); if (limit > 0) { throw err(`limit ${limit}`, 429); } @@ -94,96 +93,98 @@ export default { }, }; -export class DoRateLimit implements DurableObject { - state: DurableObjectState; +export class DoRateLimit extends DurableObject { + ctx: DurableObjectState; env: Env; rl: RateLimit; - constructor(state: DurableObjectState, env: Env) { - this.state = state; + constructor(ctx: DurableObjectState, env: Env) { + super(ctx, env); + this.ctx = ctx; this.env = env; this.rl = new RateLimit(5000); } - async fetch(request: Request): Promise { - return Response.json({ limit: this.rl.trackRequest(Date.now(), 1) }); + async trackRequest(now: number, reqWeightMs: number): Promise { + return this.rl.trackRequest(now, reqWeightMs); } } -export class DoSignal implements DurableObject { - state: DurableObjectState; +export class DoSignal extends DurableObject { + ctx: DurableObjectState; env: Env; - rl: RateLimit; + queue: { [index: string]: Array }; + alarmLock: boolean; - constructor(state: DurableObjectState, env: Env) { - this.state = state; + constructor(ctx: DurableObjectState, env: Env) { + super(ctx, env); + this.ctx = ctx; this.env = env; - this.rl = new RateLimit(5000); + this.queue = {}; + this.alarmLock = false; + } + + async forward(messageList: Array) { + for (const ws of this.ctx.getWebSockets()) { + for (const message of messageList) { + ws.send(message); + } + } } async fetch(request: Request): Promise { - return await this.state.blockConcurrencyWhile(async () => { - try { - const ip = request.headers.get('cf-connecting-ip') || 'no-ip'; - const url = new URL(request.url); + try { + const ip = request.headers.get('cf-connecting-ip') || 'no-ip'; + const url = new URL(request.url); - if (url.pathname === '/fwd') { - const message = await request.arrayBuffer(); - for (const ws of this.state.getWebSockets()) { - ws.send(message); - } - return new Response('ok'); - } else { - const { pubKeyStr, pubKeyBytes } = parsePubKey(url.pathname); + const { pubKeyStr, pubKeyBytes } = parsePubKey(url.pathname); - if (this.state.getWebSockets().length > 0) { - throw err('websocket already connected', 400); - } - if (request.headers.get('Upgrade') !== 'websocket') { - throw err('expected websocket', 426); - } + if (this.ctx.getWebSockets().length > 0) { + throw err('websocket already connected', 400); + } + if (request.headers.get('Upgrade') !== 'websocket') { + throw err('expected websocket', 426); + } - const [client, server] = Object.values(new WebSocketPair()); + const [client, server] = Object.values(new WebSocketPair()); - this.state.acceptWebSocket(server); + this.ctx.acceptWebSocket(server); - const nonce = new Uint8Array(32); - crypto.getRandomValues(nonce); + const nonce = new Uint8Array(32); + crypto.getRandomValues(nonce); - server.serializeAttachment({ - pubKey: pubKeyBytes, - ip, - nonce, - valid: false, - }); + server.serializeAttachment({ + pubKey: pubKeyBytes, + ip, + nonce, + valid: false, + }); - server.send(new MsgLbrt(8000).encoded()); - server.send(new MsgLidl(10000).encoded()); - server.send(new MsgAreq(nonce).encoded()); + server.send(new MsgLbrt(8000).encoded()); + server.send(new MsgLidl(10000).encoded()); + server.send(new MsgAreq(nonce).encoded()); - console.log( - 'webSocketOpen', - JSON.stringify({ - pubKey: pubKeyStr, - ip, - nonce: toB64Url(nonce), - }), - ); + console.log( + 'webSocketOpen', + JSON.stringify({ + pubKey: pubKeyStr, + ip, + nonce: toB64Url(nonce), + }), + ); - return new Response(null, { status: 101, webSocket: client }); - } - } catch (e: any) { - console.error('error', e.toString()); - return new Response(JSON.stringify({ err: e.toString() }), { - status: e.status || 500, - }); - } - }); + return new Response(null, { status: 101, webSocket: client }); + } catch (e: any) { + console.error('error', e.toString()); + return new Response(JSON.stringify({ err: e.toString() }), { + status: e.status || 500, + }); + } } // handle incoming websocket messages async webSocketMessage(ws: WebSocket, message: ArrayBuffer | string) { - await this.state.blockConcurrencyWhile(async () => { + const ip = await this.ctx.blockConcurrencyWhile(async () => { try { const { pubKey, ip, nonce, valid } = ws.deserializeAttachment(); if (!pubKey) { @@ -193,12 +194,6 @@ export class DoSignal implements DurableObject { throw err('no associated ip'); } - await ipRateLimit(this.env, ip); - - if (this.rl.trackRequest(Date.now(), 20) > 0) { - throw err('rate limit', 429); - } - // convert strings into binary let msgRaw: Uint8Array; if (message instanceof ArrayBuffer) { @@ -219,7 +214,6 @@ export class DoSignal implements DurableObject { if (!ed.verify(msg.signature(), nonce, pubKey)) { throw err('invalid handshake signature', 400); } - console.log('webSocketSignatureVerified'); ws.send(new MsgSrdy().encoded()); @@ -229,6 +223,8 @@ export class DoSignal implements DurableObject { nonce: true, // don't need to keep the actual nonce anymore valid: true, }); + + console.log('webSocketAuthenticated'); } else { throw err(`invalid handshake message type ${msg.type()}`); } @@ -246,25 +242,84 @@ export class DoSignal implements DurableObject { // alters the message that will be sent msg.pubKey().set(pubKey, 0); - const req = new Request('http://do/fwd', { - method: 'POST', - body: msg.encoded(), - }); - - const id = this.env.SIGNAL.idFromName(toB64Url(dest)); - const stub = this.env.SIGNAL.get(id); + const id = toB64Url(dest); + if (!this.queue[id]) { + this.queue[id] = []; + } + this.queue[id].push(msg.encoded()); - // intentionally ignore errors here - await stub.fetch(req); + if (!this.alarmLock) { + const alarm = await this.ctx.storage.getAlarm(); + if (!alarm) { + this.ctx.storage.setAlarm(Date.now() + BATCH_DUR_MS); + } + } } else { throw err(`invalid post-handshake message type: ${msg.type()}`); } } + + return ip; } catch (e: any) { console.error('error', e.toString()); ws.close(4000 + (e.status || 500), e.toString()); } }); + + try { + // NOTE: It's a little odd to run the rate-limiting *after* forwarding, + // but this lets our concurrency block be faster without having + // to await the rate limit check. + // + // It's not the end of the world if a couple extra messages get + // through before the websocket is closed. + await ipRateLimit(this.env, ip); + } catch (e: any) { + console.error('error', e.toString()); + ws.close(4000 + (e.status || 500), e.toString()); + } + } + + async alarm() { + const { shouldReturn, queue } = await this.ctx.blockConcurrencyWhile( + async () => { + if (this.alarmLock) { + return { shouldReturn: true, queue: {} }; + } + this.alarmLock = true; + const queue = this.queue; + this.queue = {}; + const shouldReturn = Object.keys(queue).length === 0; + return { shouldReturn, queue }; + }, + ); + + if (shouldReturn) { + return; + } + + for (const idName in queue) { + const id = this.env.SIGNAL.idFromName(idName); + const stub = this.env.SIGNAL.get(id) as DurableObjectStub; + + try { + await stub.forward(queue[idName]); + } catch (e: any) { + /* pass */ + } + } + + await this.ctx.blockConcurrencyWhile(async () => { + this.alarmLock = false; + + if (Object.keys(this.queue).length !== 0) { + const alarm = await this.ctx.storage.getAlarm(); + if (!alarm) { + // batch by 100 millis + this.ctx.storage.setAlarm(Date.now() + BATCH_DUR_MS); + } + } + }); } async webSocketClose( From df80bf139ff6a1f1a0a43834a87595d53444a2e8 Mon Sep 17 00:00:00 2001 From: neonphog Date: Thu, 4 Jul 2024 11:16:57 -0600 Subject: [PATCH 12/36] concurrency fixes --- ts/sbd-server/src/index.ts | 48 +++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/ts/sbd-server/src/index.ts b/ts/sbd-server/src/index.ts index 86a7cf1..9218b69 100644 --- a/ts/sbd-server/src/index.ts +++ b/ts/sbd-server/src/index.ts @@ -15,7 +15,12 @@ import { MsgForward, } from './msg.ts'; -const BATCH_DUR_MS = 20; +// How long to wait ahead of "now" to batch up message sends. +// Note, we're setting this to zero which will try to send queued messages +// as fast as possible. This doesn't mean messages won't be queued/batched, +// since there will be a delay between requesting an alarm and when it +// is actually invoked + however long it takes to actually run. +const BATCH_DUR_MS = 0; export interface Env { SIGNAL: DurableObjectNamespace; @@ -184,7 +189,7 @@ export class DoSignal extends DurableObject { // handle incoming websocket messages async webSocketMessage(ws: WebSocket, message: ArrayBuffer | string) { - const ip = await this.ctx.blockConcurrencyWhile(async () => { + await this.ctx.blockConcurrencyWhile(async () => { try { const { pubKey, ip, nonce, valid } = ws.deserializeAttachment(); if (!pubKey) { @@ -194,6 +199,8 @@ export class DoSignal extends DurableObject { throw err('no associated ip'); } + await ipRateLimit(this.env, ip); + // convert strings into binary let msgRaw: Uint8Array; if (message instanceof ArrayBuffer) { @@ -258,39 +265,23 @@ export class DoSignal extends DurableObject { throw err(`invalid post-handshake message type: ${msg.type()}`); } } - - return ip; } catch (e: any) { console.error('error', e.toString()); ws.close(4000 + (e.status || 500), e.toString()); } }); - - try { - // NOTE: It's a little odd to run the rate-limiting *after* forwarding, - // but this lets our concurrency block be faster without having - // to await the rate limit check. - // - // It's not the end of the world if a couple extra messages get - // through before the websocket is closed. - await ipRateLimit(this.env, ip); - } catch (e: any) { - console.error('error', e.toString()); - ws.close(4000 + (e.status || 500), e.toString()); - } } async alarm() { const { shouldReturn, queue } = await this.ctx.blockConcurrencyWhile( async () => { - if (this.alarmLock) { + if (this.alarmLock || Object.keys(this.queue).length === 0) { return { shouldReturn: true, queue: {} }; } this.alarmLock = true; const queue = this.queue; this.queue = {}; - const shouldReturn = Object.keys(queue).length === 0; - return { shouldReturn, queue }; + return { shouldReturn: false, queue }; }, ); @@ -298,14 +289,20 @@ export class DoSignal extends DurableObject { return; } - for (const idName in queue) { - const id = this.env.SIGNAL.idFromName(idName); - const stub = this.env.SIGNAL.get(id) as DurableObjectStub; + // We cannot do the actual forwarding within a blockConcurrency because + // then if two peers try to send each other data at the same time it + // will deadlock. Hence all the complexity with the alarms and alarmLock. + for (const idName in queue) { try { + const id = this.env.SIGNAL.idFromName(idName); + const stub = this.env.SIGNAL.get(id) as DurableObjectStub; + await stub.forward(queue[idName]); - } catch (e: any) { - /* pass */ + } catch (_e: any) { + // It is okay to get errors forwarding to peers, they may have + // disconnected. We still want to forward to other peers who + // may still be there. } } @@ -315,7 +312,6 @@ export class DoSignal extends DurableObject { if (Object.keys(this.queue).length !== 0) { const alarm = await this.ctx.storage.getAlarm(); if (!alarm) { - // batch by 100 millis this.ctx.storage.setAlarm(Date.now() + BATCH_DUR_MS); } } From 28f6eead628c8eb5eb06fc87e82d9b431a081163 Mon Sep 17 00:00:00 2001 From: neonphog Date: Thu, 4 Jul 2024 14:55:55 -0600 Subject: [PATCH 13/36] rate limiting --- Makefile | 2 +- ts/sbd-server/src/index.ts | 83 ++++++++++++++++-------- ts/sbd-server/src/rate-limit.test.ts | 95 ++++++++++++++++++++++++---- ts/sbd-server/src/rate-limit.ts | 85 ++++++++++++++++++++++--- 4 files changed, 216 insertions(+), 49 deletions(-) diff --git a/Makefile b/Makefile index 8c2841b..c964ef2 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ SHELL = /usr/bin/env sh -eu -default: static test +default: static test cf-test publish-all: $(MAKE) publish crate=sbd-client diff --git a/ts/sbd-server/src/index.ts b/ts/sbd-server/src/index.ts index 9218b69..ccf14c6 100644 --- a/ts/sbd-server/src/index.ts +++ b/ts/sbd-server/src/index.ts @@ -1,5 +1,5 @@ import { DurableObject } from 'cloudflare:workers'; -import { RateLimit } from './rate-limit.ts'; +import { RateLimit, RateLimitResult } from './rate-limit.ts'; import { err } from './err.ts'; import { ed } from './ed.ts'; import { toB64Url, fromB64Url } from './b64.ts'; @@ -15,31 +15,26 @@ import { MsgForward, } from './msg.ts'; -// How long to wait ahead of "now" to batch up message sends. -// Note, we're setting this to zero which will try to send queued messages -// as fast as possible. This doesn't mean messages won't be queued/batched, -// since there will be a delay between requesting an alarm and when it -// is actually invoked + however long it takes to actually run. +/** + * How long to wait ahead of "now" to batch up message sends. + * Note, we're setting this to zero which will try to send queued messages + * as fast as possible. This doesn't mean messages won't be queued/batched, + * since there will be a delay between requesting an alarm and when it + * is actually invoked + however long it takes to actually run. + */ const BATCH_DUR_MS = 0; +/** + * How many nanoseconds of rate limiting quota should be burned by a single + * byte sent through the system. Higher numbers mean slower rate limiting. + */ +const LIMIT_NANOS_PER_BYTE = 8000; + export interface Env { SIGNAL: DurableObjectNamespace; RATE_LIMIT: DurableObjectNamespace; } -async function ipRateLimit(env: Env, ip: string) { - try { - const ipId = env.RATE_LIMIT.idFromName(ip); - const ipStub = env.RATE_LIMIT.get(ipId) as DurableObjectStub; - const limit = await ipStub.trackRequest(Date.now(), 1); - if (limit > 0) { - throw err(`limit ${limit}`, 429); - } - } catch (e) { - throw err(`limit ${e}`, 429); - } -} - function parsePubKey(path: string): { pubKeyStr: string; pubKeyBytes: Uint8Array; @@ -70,7 +65,7 @@ export default { try { const ip = request.headers.get('cf-connecting-ip') || 'no-ip'; - await ipRateLimit(env, ip); + //await ipRateLimit(env, ip); const method = request.method; const url = new URL(request.url); @@ -107,11 +102,15 @@ export class DoRateLimit extends DurableObject { super(ctx, env); this.ctx = ctx; this.env = env; - this.rl = new RateLimit(5000); + this.rl = new RateLimit(LIMIT_NANOS_PER_BYTE, 16 * 16 * 1024); } - async trackRequest(now: number, reqWeightMs: number): Promise { - return this.rl.trackRequest(now, reqWeightMs); + async bytesReceived( + now: number, + pk: string, + bytes: number, + ): Promise { + return this.rl.bytesReceived(now, pk, bytes); } } @@ -120,6 +119,7 @@ export class DoSignal extends DurableObject { env: Env; queue: { [index: string]: Array }; alarmLock: boolean; + curLimit: number; constructor(ctx: DurableObjectState, env: Env) { super(ctx, env); @@ -127,6 +127,7 @@ export class DoSignal extends DurableObject { this.env = env; this.queue = {}; this.alarmLock = false; + this.curLimit = 0; } async forward(messageList: Array) { @@ -138,6 +139,7 @@ export class DoSignal extends DurableObject { } async fetch(request: Request): Promise { + let cleanServer = null; try { const ip = request.headers.get('cf-connecting-ip') || 'no-ip'; const url = new URL(request.url); @@ -154,6 +156,7 @@ export class DoSignal extends DurableObject { const [client, server] = Object.values(new WebSocketPair()); this.ctx.acceptWebSocket(server); + cleanServer = server; const nonce = new Uint8Array(32); crypto.getRandomValues(nonce); @@ -165,7 +168,9 @@ export class DoSignal extends DurableObject { valid: false, }); - server.send(new MsgLbrt(8000).encoded()); + // this will also send MsgLbrt + await this.ipRateLimit(ip, pubKeyStr, 1, server); + server.send(new MsgLidl(10000).encoded()); server.send(new MsgAreq(nonce).encoded()); @@ -181,12 +186,38 @@ export class DoSignal extends DurableObject { return new Response(null, { status: 101, webSocket: client }); } catch (e: any) { console.error('error', e.toString()); + if (cleanServer) { + cleanServer.close(4000 + (e.status || 500), e.toString()); + } return new Response(JSON.stringify({ err: e.toString() }), { status: e.status || 500, }); } } + async ipRateLimit(ip: string, pk: string, bytes: number, ws: WebSocket) { + try { + const ipId = this.env.RATE_LIMIT.idFromName(ip); + const ipStub = this.env.RATE_LIMIT.get( + ipId, + ) as DurableObjectStub; + const { limitNanosPerByte, shouldBlock } = await ipStub.bytesReceived( + Date.now(), + pk, + bytes, + ); + if (shouldBlock) { + throw err(`limit`, 429); + } + if (this.curLimit !== limitNanosPerByte) { + this.curLimit = limitNanosPerByte; + ws.send(new MsgLbrt(limitNanosPerByte).encoded()); + } + } catch (e) { + throw err(`limit ${e}`, 429); + } + } + // handle incoming websocket messages async webSocketMessage(ws: WebSocket, message: ArrayBuffer | string) { await this.ctx.blockConcurrencyWhile(async () => { @@ -199,8 +230,6 @@ export class DoSignal extends DurableObject { throw err('no associated ip'); } - await ipRateLimit(this.env, ip); - // convert strings into binary let msgRaw: Uint8Array; if (message instanceof ArrayBuffer) { @@ -210,6 +239,8 @@ export class DoSignal extends DurableObject { msgRaw = enc.encode(message); } + await this.ipRateLimit(ip, pubKey, msgRaw.byteLength, ws); + const msg = Msg.parse(msgRaw); if (!valid) { diff --git a/ts/sbd-server/src/rate-limit.test.ts b/ts/sbd-server/src/rate-limit.test.ts index 206def9..028bc8a 100644 --- a/ts/sbd-server/src/rate-limit.test.ts +++ b/ts/sbd-server/src/rate-limit.test.ts @@ -2,23 +2,92 @@ import { describe, expect, assert, it, beforeAll, afterAll } from 'vitest'; import { RateLimit } from './rate-limit.ts'; describe('RateLimit', () => { - it('allows steady rate', async () => { - const rl = new RateLimit(10); - for (let now = 0; now < 1000; ++now) { - expect(rl.trackRequest(now, 1)).toEqual(0); + it('check multi-node rate limit', async () => { + const addr1 = 'yada1'; + const addr2 = 'yada2'; + + let now = 100; + + const rate = new RateLimit(8000, 16 * 16 * 1024); + + let limitNanosPerByte = null; + + ({ limitNanosPerByte } = rate.bytesReceived(now, addr1, 1)); + + expect(limitNanosPerByte).equals(8000); + + ({ limitNanosPerByte } = rate.bytesReceived(now, addr2, 1)); + + expect(limitNanosPerByte).equals(16000); + + now += 20000; + + ({ limitNanosPerByte } = rate.bytesReceived(now, addr2, 1)); + expect(limitNanosPerByte).equals(8000); + }); + + it('1 to 1 and prune', async () => { + const addr = 'yada'; + + let now = 100n; + let shouldBlock = null; + + const rate = new RateLimit(1, 1); + + // should always be ok when advancing with time + for (let i = 0; i < 10; ++i) { + now += 1n; + + ({ shouldBlock } = rate.bytesReceived(now, addr, 1)); + + assert(!shouldBlock); } + + // but one more without a time advance fails + ({ shouldBlock } = rate.bytesReceived(now, addr, 1)); + assert(shouldBlock); + + now += 1n; + + // make sure prune doesn't prune it yet + rate.prune(now); + ({ shouldBlock } = rate.bytesReceived(now, addr, 1)); + assert(shouldBlock); + + now += 1n; + + // make sure prune doesn't prune it even after 10 seconds + rate.prune(now + 10000000000n); + ({ shouldBlock } = rate.bytesReceived(now, addr, 1)); + assert(shouldBlock); + + now += 1n; + + // but it *will* after 10 seconds + 1 nanosecond + rate.prune(now + 10000000001n); + ({ shouldBlock } = rate.bytesReceived(now, addr, 1)); + assert(!shouldBlock); }); it('burst', async () => { - let now = 100; - const rl = new RateLimit(10); - for (let i = 0; i < 10; ++i) { - expect(rl.trackRequest(now, 1)).toEqual(0); + const addr = 'yada'; + + let now = 100n; + let shouldBlock = null; + + const rate = new RateLimit(1, 5); + + for (let i = 0; i < 5; ++i) { + ({ shouldBlock } = rate.bytesReceived(now, addr, 1)); + assert(!shouldBlock); } - expect(rl.trackRequest(now, 1)).toEqual(1); - now += 1; - expect(rl.trackRequest(now, 1)).toEqual(1); - now += 2; - expect(rl.trackRequest(now, 1)).toEqual(0); + + ({ shouldBlock } = rate.bytesReceived(now, addr, 1)); + assert(shouldBlock); + + now += 2n; + + ({ shouldBlock } = rate.bytesReceived(now, addr, 1)); + assert(!shouldBlock); }); }); diff --git a/ts/sbd-server/src/rate-limit.ts b/ts/sbd-server/src/rate-limit.ts index 80f360c..c194c42 100644 --- a/ts/sbd-server/src/rate-limit.ts +++ b/ts/sbd-server/src/rate-limit.ts @@ -1,16 +1,83 @@ +export interface RateLimitResult { + limitNanosPerByte: number; + shouldBlock: boolean; +} + +function nowNanos(now: number | bigint): bigint { + if (typeof now === 'bigint') { + return now; + } else { + const tmp: bigint = BigInt(now); + return tmp * 1000000n; + } +} + export class RateLimit { - gracePeriodMs: number; - nextAllowedTime: number; + map: { [pk: string]: bigint }; + limitNanosPerByte: bigint; + burst: bigint; + + constructor(limitNanosPerByte: number, burst: number) { + this.map = {}; + this.limitNanosPerByte = BigInt(limitNanosPerByte); + this.burst = this.limitNanosPerByte * BigInt(burst); + } + + /** + * - now: if now is a number, it is milliseconds since epoch + * if now is a bigint, it is nanoseconds since epoch + */ + prune(now: number | bigint) { + const nowNs = nowNanos(now); + + const newMap: { [pk: string]: bigint } = {}; + + for (const pk in this.map) { + const cur = this.map[pk]; + if (nowNs <= cur || nowNs - cur < 10000000000n) { + newMap[pk] = cur; + } + } - constructor(gracePeriodMs: number) { - this.gracePeriodMs = gracePeriodMs; - this.nextAllowedTime = 0; + this.map = newMap; } - trackRequest(now: number, reqWeightMs: number): number { - this.nextAllowedTime = Math.max(now, this.nextAllowedTime); - this.nextAllowedTime += reqWeightMs; + /** + * - now: if now is a number, it is milliseconds since epoch + * if now is a bigint, it is nanoseconds since epoch + */ + bytesReceived( + now: number | bigint, + pk: string, + bytes: number, + ): RateLimitResult { + this.prune(now); + + const nowNs = nowNanos(now); + + const rateAdd = BigInt(bytes) * this.limitNanosPerByte; + + if (!(pk in this.map)) { + this.map[pk] = nowNs; + } + + let cur = this.map[pk]; + + if (nowNs > cur) { + cur = nowNs; + } + + cur += rateAdd; + + this.map[pk] = cur; + + const nextActionInNanos = cur - nowNs; + + const shouldBlock = nextActionInNanos > this.burst; + + const nodeCount: bigint = BigInt(Object.keys(this.map).length); + const limitNanosPerByte = Number(this.limitNanosPerByte * nodeCount); - return Math.max(0, this.nextAllowedTime - now - this.gracePeriodMs); + return { limitNanosPerByte, shouldBlock }; } } From b71017c8982bd8e875294490e431de5bbf09acb9 Mon Sep 17 00:00:00 2001 From: neonphog Date: Thu, 4 Jul 2024 16:00:10 -0600 Subject: [PATCH 14/36] cleanup --- ts/sbd-server/src/index.ts | 27 +++++++++++++++++++++++---- ts/sbd-server/wrangler.toml | 4 +++- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/ts/sbd-server/src/index.ts b/ts/sbd-server/src/index.ts index ccf14c6..6793dca 100644 --- a/ts/sbd-server/src/index.ts +++ b/ts/sbd-server/src/index.ts @@ -30,6 +30,11 @@ const BATCH_DUR_MS = 0; */ const LIMIT_NANOS_PER_BYTE = 8000; +/** + * Milliseconds connections are allowed to remain idle before being closed. + */ +const LIMIT_IDLE_MILLIS = 10000; + export interface Env { SIGNAL: DurableObjectNamespace; RATE_LIMIT: DurableObjectNamespace; @@ -65,8 +70,6 @@ export default { try { const ip = request.headers.get('cf-connecting-ip') || 'no-ip'; - //await ipRateLimit(env, ip); - const method = request.method; const url = new URL(request.url); @@ -78,6 +81,19 @@ export default { const { pubKeyStr } = parsePubKey(url.pathname); + const ipId = env.RATE_LIMIT.idFromName(ip); + const ipStub = env.RATE_LIMIT.get( + ipId, + ) as DurableObjectStub; + const { shouldBlock } = await ipStub.bytesReceived( + Date.now(), + pubKeyStr, + 1, + ); + if (shouldBlock) { + throw err(`limit`, 429); + } + // DO instanced by our pubKey const id = env.SIGNAL.idFromName(pubKeyStr); const stub = env.SIGNAL.get(id); @@ -171,7 +187,7 @@ export class DoSignal extends DurableObject { // this will also send MsgLbrt await this.ipRateLimit(ip, pubKeyStr, 1, server); - server.send(new MsgLidl(10000).encoded()); + server.send(new MsgLidl(LIMIT_IDLE_MILLIS).encoded()); server.send(new MsgAreq(nonce).encoded()); console.log( @@ -262,7 +278,10 @@ export class DoSignal extends DurableObject { valid: true, }); - console.log('webSocketAuthenticated'); + console.log( + 'webSocketAuthenticated', + JSON.stringify({ pubKey: toB64Url(pubKey) }), + ); } else { throw err(`invalid handshake message type ${msg.type()}`); } diff --git a/ts/sbd-server/wrangler.toml b/ts/sbd-server/wrangler.toml index 3f9a3bf..68edfc3 100644 --- a/ts/sbd-server/wrangler.toml +++ b/ts/sbd-server/wrangler.toml @@ -1,6 +1,8 @@ -name = "sbd-signal" +name = "sbd" main = "src/index.ts" compatibility_date = "2024-06-03" +route = "sbd.holo.host/*" +account_id = "18ff2b4e6205b938652998cfca0d8cff" [[durable_objects.bindings]] name = "SIGNAL" From 7a040885a83f6ea27246bf42a41a0356c9deab50 Mon Sep 17 00:00:00 2001 From: neonphog Date: Thu, 4 Jul 2024 16:01:43 -0600 Subject: [PATCH 15/36] fmt --- ts/sbd-server/src/index.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ts/sbd-server/src/index.ts b/ts/sbd-server/src/index.ts index 6793dca..da4b6df 100644 --- a/ts/sbd-server/src/index.ts +++ b/ts/sbd-server/src/index.ts @@ -82,9 +82,7 @@ export default { const { pubKeyStr } = parsePubKey(url.pathname); const ipId = env.RATE_LIMIT.idFromName(ip); - const ipStub = env.RATE_LIMIT.get( - ipId, - ) as DurableObjectStub; + const ipStub = env.RATE_LIMIT.get(ipId) as DurableObjectStub; const { shouldBlock } = await ipStub.bytesReceived( Date.now(), pubKeyStr, From ba3934e86e0eaa9fb152fdf54a8cd9a2c9d7f9f2 Mon Sep 17 00:00:00 2001 From: neonphog Date: Fri, 5 Jul 2024 14:11:17 -0600 Subject: [PATCH 16/36] cleanup and comments --- ts/sbd-server/package-lock.json | 72 +++++++++++++------------- ts/sbd-server/package.json | 2 +- ts/sbd-server/src/b64.ts | 6 +++ ts/sbd-server/src/ed.ts | 3 ++ ts/sbd-server/src/err.ts | 7 +++ ts/sbd-server/src/index.ts | 47 ++++++++++++++++- ts/sbd-server/src/msg.ts | 90 +++++++++++++++++++++++++++++++++ ts/sbd-server/src/rate-limit.ts | 23 +++++++++ ts/sbd-server/wrangler.toml | 1 + 9 files changed, 213 insertions(+), 38 deletions(-) diff --git a/ts/sbd-server/package-lock.json b/ts/sbd-server/package-lock.json index a925084..697c100 100644 --- a/ts/sbd-server/package-lock.json +++ b/ts/sbd-server/package-lock.json @@ -18,7 +18,7 @@ "prettier": "^3.3.2", "typescript": "^5.5.2", "vitest": "^1.6.0", - "wrangler": "^3.62.0" + "wrangler": "^3.63.1" } }, "node_modules/@cloudflare/kv-asset-handler": { @@ -34,9 +34,9 @@ } }, "node_modules/@cloudflare/workerd-darwin-64": { - "version": "1.20240620.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20240620.1.tgz", - "integrity": "sha512-YWeS2aE8jAzDefuus/3GmZcFGu3Ef94uCAoxsQuaEXNsiGM9NeAhPpKC1BJAlcv168U/Q1J+6hckcGtipf6ZcQ==", + "version": "1.20240701.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20240701.0.tgz", + "integrity": "sha512-XAZa4ZP+qyTn6JQQACCPH09hGZXP2lTnWKkmg5mPwT8EyRzCKLkczAf98vPP5bq7JZD/zORdFWRY0dOTap8zTQ==", "cpu": [ "x64" ], @@ -50,9 +50,9 @@ } }, "node_modules/@cloudflare/workerd-darwin-arm64": { - "version": "1.20240620.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20240620.1.tgz", - "integrity": "sha512-3rdND+EHpmCrwYX6hvxIBSBJ0f40tRNxond1Vfw7GiR1MJVi3gragiBx75UDFHCxfRw3J0GZ1qVlkRce2/Xbsg==", + "version": "1.20240701.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20240701.0.tgz", + "integrity": "sha512-w80ZVAgfH4UwTz7fXZtk7KmS2FzlXniuQm4ku4+cIgRTilBAuKqjpOjwUCbx5g13Gqcm9NuiHce+IDGtobRTIQ==", "cpu": [ "arm64" ], @@ -66,9 +66,9 @@ } }, "node_modules/@cloudflare/workerd-linux-64": { - "version": "1.20240620.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20240620.1.tgz", - "integrity": "sha512-tURcTrXGeSbYqeM5ISVcofY20StKbVIcdxjJvNYNZ+qmSV9Fvn+zr7rRE+q64pEloVZfhsEPAlUCnFso5VV4XQ==", + "version": "1.20240701.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20240701.0.tgz", + "integrity": "sha512-UWLr/Anxwwe/25nGv451MNd2jhREmPt/ws17DJJqTLAx6JxwGWA15MeitAIzl0dbxRFAJa+0+R8ag2WR3F/D6g==", "cpu": [ "x64" ], @@ -82,9 +82,9 @@ } }, "node_modules/@cloudflare/workerd-linux-arm64": { - "version": "1.20240620.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20240620.1.tgz", - "integrity": "sha512-TThvkwNxaZFKhHZnNjOGqIYCOk05DDWgO+wYMuXg15ymN/KZPnCicRAkuyqiM+R1Fgc4kwe/pehjP8pbmcf6sg==", + "version": "1.20240701.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20240701.0.tgz", + "integrity": "sha512-3kCnF9kYgov1ggpuWbgpXt4stPOIYtVmPCa7MO2xhhA0TWP6JDUHRUOsnmIgKrvDjXuXqlK16cdg3v+EWsaPJg==", "cpu": [ "arm64" ], @@ -98,9 +98,9 @@ } }, "node_modules/@cloudflare/workerd-windows-64": { - "version": "1.20240620.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20240620.1.tgz", - "integrity": "sha512-Y/BA9Yj0r7Al1HK3nDHcfISgFllw6NR3XMMPChev57vrVT9C9D4erBL3sUBfofHU+2U9L+ShLsl6obBpe3vvUw==", + "version": "1.20240701.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20240701.0.tgz", + "integrity": "sha512-6IPGITRAeS67j3BH1rN4iwYWDt47SqJG7KlZJ5bB4UaNAia4mvMBSy/p2p4vA89bbXoDRjMtEvRu7Robu6O7hQ==", "cpu": [ "x64" ], @@ -1511,9 +1511,9 @@ } }, "node_modules/miniflare": { - "version": "3.20240620.0", - "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-3.20240620.0.tgz", - "integrity": "sha512-NBMzqUE2mMlh/hIdt6U5MP+aFhEjKDq3l8CAajXAQa1WkndJdciWvzB2mfLETwoVFhMl/lphaVzyEN2AgwJpbQ==", + "version": "3.20240701.0", + "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-3.20240701.0.tgz", + "integrity": "sha512-m9+I+7JNyqDGftCMKp9cK9pCZkK72hAL2mM9IWwhct+ZmucLBA8Uu6+rHQqA5iod86cpwOkrB2PrPA3wx9YNgw==", "dev": true, "dependencies": { "@cspotcode/source-map-support": "0.8.1", @@ -1524,8 +1524,8 @@ "glob-to-regexp": "^0.4.1", "stoppable": "^1.1.0", "undici": "^5.28.4", - "workerd": "1.20240620.1", - "ws": "^8.14.2", + "workerd": "1.20240701.0", + "ws": "^8.17.1", "youch": "^3.2.2", "zod": "^3.22.3" }, @@ -2348,9 +2348,9 @@ } }, "node_modules/workerd": { - "version": "1.20240620.1", - "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20240620.1.tgz", - "integrity": "sha512-Qoq+RrFNk4pvEO+kpJVn8uJ5TRE9YJx5jX5pC5LjdKlw1XeD8EdXt5k0TbByvWunZ4qgYIcF9lnVxhcDFo203g==", + "version": "1.20240701.0", + "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20240701.0.tgz", + "integrity": "sha512-qSgNVqauqzNCij9MaJLF2c2ko3AnFioVSIxMSryGbRK+LvtGr9BKBt6JOxCb24DoJASoJDx3pe3DJHBVydUiBg==", "dev": true, "hasInstallScript": true, "bin": { @@ -2360,17 +2360,17 @@ "node": ">=16" }, "optionalDependencies": { - "@cloudflare/workerd-darwin-64": "1.20240620.1", - "@cloudflare/workerd-darwin-arm64": "1.20240620.1", - "@cloudflare/workerd-linux-64": "1.20240620.1", - "@cloudflare/workerd-linux-arm64": "1.20240620.1", - "@cloudflare/workerd-windows-64": "1.20240620.1" + "@cloudflare/workerd-darwin-64": "1.20240701.0", + "@cloudflare/workerd-darwin-arm64": "1.20240701.0", + "@cloudflare/workerd-linux-64": "1.20240701.0", + "@cloudflare/workerd-linux-arm64": "1.20240701.0", + "@cloudflare/workerd-windows-64": "1.20240701.0" } }, "node_modules/wrangler": { - "version": "3.62.0", - "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-3.62.0.tgz", - "integrity": "sha512-TM1Bd8+GzxFw/JzwsC3i/Oss4LTWvIEWXXo1vZhx+7PHcsxdbnQGBBwPurHNJDSu2Pw22+2pCZiUGKexmgJksw==", + "version": "3.63.1", + "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-3.63.1.tgz", + "integrity": "sha512-fxMPNEyDc9pZNtQOuYqRikzv6lL5eP4S1zv7L/kw24uu1cCEmJ39j8bfJGzrAEqKDNsiFXVjEka0RjlpgEVWPg==", "dev": true, "dependencies": { "@cloudflare/kv-asset-handler": "0.3.4", @@ -2380,7 +2380,7 @@ "chokidar": "^3.5.3", "date-fns": "^3.6.0", "esbuild": "0.17.19", - "miniflare": "3.20240620.0", + "miniflare": "3.20240701.0", "nanoid": "^3.3.3", "path-to-regexp": "^6.2.0", "resolve": "^1.22.8", @@ -2799,9 +2799,9 @@ } }, "node_modules/ws": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", - "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", "dev": true, "engines": { "node": ">=10.0.0" diff --git a/ts/sbd-server/package.json b/ts/sbd-server/package.json index ed1e3e4..c619b80 100644 --- a/ts/sbd-server/package.json +++ b/ts/sbd-server/package.json @@ -17,7 +17,7 @@ "prettier": "^3.3.2", "typescript": "^5.5.2", "vitest": "^1.6.0", - "wrangler": "^3.62.0" + "wrangler": "^3.63.1" }, "dependencies": { "@noble/ed25519": "^2.1.0", diff --git a/ts/sbd-server/src/b64.ts b/ts/sbd-server/src/b64.ts index 5dfb4a0..585d33f 100644 --- a/ts/sbd-server/src/b64.ts +++ b/ts/sbd-server/src/b64.ts @@ -1,5 +1,8 @@ import { fromUint8Array, toUint8Array } from 'js-base64'; +/** + * Convert to base64url representation. + */ export function toB64Url(s: Uint8Array): string { return fromUint8Array(s) .replace(/\=/g, '') @@ -7,6 +10,9 @@ export function toB64Url(s: Uint8Array): string { .replace(/\//g, '_'); } +/** + * Convert from base64url representation. + */ export function fromB64Url(s: string): Uint8Array { return toUint8Array(s.replace(/\-/g, '+').replace(/\_/g, '/')); } diff --git a/ts/sbd-server/src/ed.ts b/ts/sbd-server/src/ed.ts index 2883b1b..5436b54 100644 --- a/ts/sbd-server/src/ed.ts +++ b/ts/sbd-server/src/ed.ts @@ -1,3 +1,6 @@ +// This ed25519 lib annoyingly needs a hash lib explicitly configured. +// Do that with their own recommended hash lib, and re-export that. + import * as ed from '@noble/ed25519'; import { sha512 } from '@noble/hashes/sha512'; ed.etc.sha512Sync = (...m) => sha512(ed.etc.concatBytes(...m)); diff --git a/ts/sbd-server/src/err.ts b/ts/sbd-server/src/err.ts index bed0dbc..f7b8feb 100644 --- a/ts/sbd-server/src/err.ts +++ b/ts/sbd-server/src/err.ts @@ -4,6 +4,13 @@ interface AddStatus { type StatusError = Error & AddStatus; +/** + * Adds a 'status' property to ts Error type. + * If not specified will be set to 500. + * Allows altering the http or ws error status for responses. + * In the case of a websocket error, the http status code + * will be added to 4000 for user-specified error codes. + */ export function err(e: string, s?: number): StatusError { const out: any = new Error(e); out.status = s || 500; diff --git a/ts/sbd-server/src/index.ts b/ts/sbd-server/src/index.ts index da4b6df..8e5b92b 100644 --- a/ts/sbd-server/src/index.ts +++ b/ts/sbd-server/src/index.ts @@ -35,11 +35,17 @@ const LIMIT_NANOS_PER_BYTE = 8000; */ const LIMIT_IDLE_MILLIS = 10000; +/** + * Cloudflare worker typescript boilerplate. + */ export interface Env { SIGNAL: DurableObjectNamespace; RATE_LIMIT: DurableObjectNamespace; } +/** + * Pull pubKey string and bytes from the url path. + */ function parsePubKey(path: string): { pubKeyStr: string; pubKeyBytes: Uint8Array; @@ -61,6 +67,10 @@ function parsePubKey(path: string): { return { pubKeyStr, pubKeyBytes }; } +/** + * This is the http entrypoint. + * Forward the request to the "SIGNAL" durable object. + */ export default { async fetch( request: Request, @@ -107,6 +117,10 @@ export default { }, }; +/** + * "RATE_LIMIT" durable object. + * This is a thin wrapper around the "RateLimit" class. + */ export class DoRateLimit extends DurableObject { ctx: DurableObjectState; env: Env; @@ -128,6 +142,9 @@ export class DoRateLimit extends DurableObject { } } +/** + * "SIGNAL" durable object. + */ export class DoSignal extends DurableObject { ctx: DurableObjectState; env: Env; @@ -144,6 +161,12 @@ export class DoSignal extends DurableObject { this.curLimit = 0; } + /** + * Client websockets are connected to a durable object identified + * by their own pubKey. When they send forward messages, those must + * be sent to durable objects identified by the destination pubKey. + * This is the api for those messages to be forwarded. + */ async forward(messageList: Array) { for (const ws of this.ctx.getWebSockets()) { for (const message of messageList) { @@ -152,6 +175,12 @@ export class DoSignal extends DurableObject { } } + /** + * This is the http endpoint for the "SIGNAL" durable object. + * The worker http fetch endpoint above forwards the request here. + * This function performs some checks, then upgrades the connection + * to a websocket. + */ async fetch(request: Request): Promise { let cleanServer = null; try { @@ -209,6 +238,10 @@ export class DoSignal extends DurableObject { } } + /** + * Helper function for performing the rate-limit check and + * closing the websocket if we violate the limit. + */ async ipRateLimit(ip: string, pk: string, bytes: number, ws: WebSocket) { try { const ipId = this.env.RATE_LIMIT.idFromName(ip); @@ -232,7 +265,10 @@ export class DoSignal extends DurableObject { } } - // handle incoming websocket messages + /** + * Handle incoming websocket messages. + * First handshake the connection, then start handling forwarding messages. + */ async webSocketMessage(ws: WebSocket, message: ArrayBuffer | string) { await this.ctx.blockConcurrencyWhile(async () => { try { @@ -320,6 +356,12 @@ export class DoSignal extends DurableObject { }); } + /** + * The `webSocketMessage` handler above enqueues messages for delivery, + * then sets up an alarm to handle actually forwarding them. This ensures + * the messages are delivered in order without deadlocking two clients + * that happened to try to forward messages to each other at the same moment. + */ async alarm() { const { shouldReturn, queue } = await this.ctx.blockConcurrencyWhile( async () => { @@ -366,6 +408,9 @@ export class DoSignal extends DurableObject { }); } + /** + * The websocket was closed. + */ async webSocketClose( ws: WebSocket, code: number, diff --git a/ts/sbd-server/src/msg.ts b/ts/sbd-server/src/msg.ts index 9ada23f..2beec2b 100644 --- a/ts/sbd-server/src/msg.ts +++ b/ts/sbd-server/src/msg.ts @@ -2,6 +2,9 @@ import { ed } from './ed.ts'; import { err } from './err.ts'; import { toB64Url, fromB64Url } from './b64.ts'; +/** + * Byte-by-byte comparison of Uint8Array types. + */ function cmp(a: Uint8Array, b: Uint8Array): boolean { if (a.byteLength !== b.byteLength) { return false; @@ -14,31 +17,63 @@ function cmp(a: Uint8Array, b: Uint8Array): boolean { return true; } +/** + * 28 zeroes indicate a "command" type message. + */ const CMD: Uint8Array = new Uint8Array(28); +/** + * Limit bitrate. + */ export const MSG_T_LBRT: string = 'lbrt'; const MSG_B_LBRT: Uint8Array = new TextEncoder().encode(MSG_T_LBRT); +/** + * Idle limit milliseconds. + */ export const MSG_T_LIDL: string = 'lidl'; const MSG_B_LIDL: Uint8Array = new TextEncoder().encode(MSG_T_LIDL); +/** + * Server initiated handshake request. + */ export const MSG_T_AREQ: string = 'areq'; const MSG_B_AREQ: Uint8Array = new TextEncoder().encode(MSG_T_AREQ); +/** + * Client handshake response. + */ export const MSG_T_ARES: string = 'ares'; const MSG_B_ARES: Uint8Array = new TextEncoder().encode(MSG_T_ARES); +/** + * Handshake success. + */ export const MSG_T_SRDY: string = 'srdy'; const MSG_B_SRDY: Uint8Array = new TextEncoder().encode(MSG_T_SRDY); +/** + * Client-sent keepalive. + */ export const MSG_T_KEEP: string = 'keep'; const MSG_B_KEEP: Uint8Array = new TextEncoder().encode(MSG_T_KEEP); +/** + * "Unknown message" to be used for compatibility with future clients. + */ export const MSG_T_NONE: string = 'none'; const MSG_B_NONE: Uint8Array = new TextEncoder().encode(MSG_T_NONE); +/** + * This message was not a command, it was a forward. + * The first 32 bytes are the pubkey to which we will forward the data. + * (There's no binary Uint8Array version of this, it's just a flag). + */ export const MSG_T_FORWARD: string = 'forward'; +/** + * Base message abstract class. + */ export class Msg { #bytes: Uint8Array; #type: string; @@ -48,6 +83,9 @@ export class Msg { this.#type = type; } + /** + * Parse a message byte array into the correct message subtype. + */ static parse( bytes: Uint8Array, ): MsgLbrt | MsgLidl | MsgAreq | MsgAres | MsgSrdy | MsgKeep { @@ -116,15 +154,24 @@ export class Msg { } } + /** + * Return the `MSG_T_` type of this message. + */ type(): string { return this.#type; } + /** + * Get the encoded bytes of this message. + */ encoded(): Uint8Array { return this.#bytes; } } +/** + * Limit bitrate. + */ export class MsgLbrt extends Msg { #limit: number; @@ -139,11 +186,17 @@ export class MsgLbrt extends Msg { this.#limit = limit; } + /** + * Get the "nanoseconds per byte" bitrate limit. + */ limit(): number { return this.#limit; } } +/** + * Idle limit milliseconds. + */ export class MsgLidl extends Msg { #limit: number; @@ -158,11 +211,17 @@ export class MsgLidl extends Msg { this.#limit = limit; } + /** + * Get the millisecond count this connection can idle without being closed. + */ limit(): number { return this.#limit; } } +/** + * Server initiated handshake request. + */ export class MsgAreq extends Msg { #nonce: Uint8Array; @@ -177,11 +236,17 @@ export class MsgAreq extends Msg { this.#nonce = nonce; } + /** + * A nonce for the client to sign. + */ nonce(): Uint8Array { return this.#nonce; } } +/** + * Client handshake response. + */ export class MsgAres extends Msg { #signature: Uint8Array; @@ -196,11 +261,17 @@ export class MsgAres extends Msg { this.#signature = signature; } + /** + * A signature over the nonce bytes the server had sent. + */ signature(): Uint8Array { return this.#signature; } } +/** + * Handshake success. + */ export class MsgSrdy extends Msg { constructor() { const bytes = new Uint8Array(32); @@ -211,6 +282,9 @@ export class MsgSrdy extends Msg { } } +/** + * Client-sent keepalive. + */ export class MsgKeep extends Msg { constructor() { const bytes = new Uint8Array(32); @@ -221,6 +295,9 @@ export class MsgKeep extends Msg { } } +/** + * "Unknown message" to be used for compatibility with future clients. + */ export class MsgNone extends Msg { constructor() { const bytes = new Uint8Array(32); @@ -231,11 +308,18 @@ export class MsgNone extends Msg { } } +/** + * This message is not a command, it is a forward. + * The first 32 bytes are the pubkey to which we will forward the data. + */ export class MsgForward extends Msg { constructor(bytes: Uint8Array) { super(bytes, MSG_T_FORWARD); } + /** + * Construct a forward message from parts. + */ static build(pubKey: Uint8Array, payload: Uint8Array): MsgForward { if (pubKey.byteLength !== 32) { throw err( @@ -250,10 +334,16 @@ export class MsgForward extends Msg { return new MsgForward(bytes); } + /** + * Get a subarray reference to the pubkey portion of this message. + */ pubKey(): Uint8Array { return this.encoded().subarray(0, 32); } + /** + * Get a subarray reference to the payload portion of this message. + */ payload(): Uint8Array { return this.encoded().subarray(32); } diff --git a/ts/sbd-server/src/rate-limit.ts b/ts/sbd-server/src/rate-limit.ts index c194c42..26de16a 100644 --- a/ts/sbd-server/src/rate-limit.ts +++ b/ts/sbd-server/src/rate-limit.ts @@ -1,8 +1,22 @@ +/** + * `bytesReceived` call response type. + */ export interface RateLimitResult { + /** + * How many nanos per byte this connection should be allowed to send. + */ limitNanosPerByte: number; + + /** + * True if this connection has already breached its rate limit. + */ shouldBlock: boolean; } +/** + * If a classic number, milliseconds since epoch. + * If a bigint, nanoseconds since epoch. + */ function nowNanos(now: number | bigint): bigint { if (typeof now === 'bigint') { return now; @@ -12,6 +26,9 @@ function nowNanos(now: number | bigint): bigint { } } +/** + * Ratelimit potentially multiple clients coming from the same ip address. + */ export class RateLimit { map: { [pk: string]: bigint }; limitNanosPerByte: bigint; @@ -24,6 +41,8 @@ export class RateLimit { } /** + * Clear out any connections older that 10s in the past. + * * - now: if now is a number, it is milliseconds since epoch * if now is a bigint, it is nanoseconds since epoch */ @@ -43,6 +62,10 @@ export class RateLimit { } /** + * Log a number of bytes received from a single pubKey (connection). + * Return a bitrate limit this connection should be following, and + * whether that ip has already breached the limit. + * * - now: if now is a number, it is milliseconds since epoch * if now is a bigint, it is nanoseconds since epoch */ diff --git a/ts/sbd-server/wrangler.toml b/ts/sbd-server/wrangler.toml index 68edfc3..5f083a3 100644 --- a/ts/sbd-server/wrangler.toml +++ b/ts/sbd-server/wrangler.toml @@ -3,6 +3,7 @@ main = "src/index.ts" compatibility_date = "2024-06-03" route = "sbd.holo.host/*" account_id = "18ff2b4e6205b938652998cfca0d8cff" +workers_dev = false [[durable_objects.bindings]] name = "SIGNAL" From d54e5b9addda9e6aa43c962c1cc44ffe839d65ea Mon Sep 17 00:00:00 2001 From: neonphog Date: Fri, 5 Jul 2024 16:42:59 -0600 Subject: [PATCH 17/36] test2 different behavior --- rust/sbd-o-bahn-server-tester/Cargo.toml | 2 +- .../src/bin/sbd-o-bahn-server-tester-bin.rs | 5 +- rust/sbd-o-bahn-server-tester/src/it.rs | 76 ++++++++++++++----- rust/sbd-o-bahn-server-tester/src/it/it_1.rs | 12 ++- rust/sbd-o-bahn-server-tester/src/it/it_2.rs | 32 ++++++++ rust/sbd-o-bahn-server-tester/src/lib.rs | 7 +- rust/sbd-server/tests/suite.rs | 11 ++- 7 files changed, 108 insertions(+), 37 deletions(-) create mode 100644 rust/sbd-o-bahn-server-tester/src/it/it_2.rs diff --git a/rust/sbd-o-bahn-server-tester/Cargo.toml b/rust/sbd-o-bahn-server-tester/Cargo.toml index 27b909b..0a8f2f2 100644 --- a/rust/sbd-o-bahn-server-tester/Cargo.toml +++ b/rust/sbd-o-bahn-server-tester/Cargo.toml @@ -11,5 +11,5 @@ categories = ["network-programming"] edition = "2021" [dependencies] -sbd-client = { workspace = true } +sbd-client = { workspace = true, features = [ "raw_client" ] } tokio = { workspace = true, features = [ "full" ] } diff --git a/rust/sbd-o-bahn-server-tester/src/bin/sbd-o-bahn-server-tester-bin.rs b/rust/sbd-o-bahn-server-tester/src/bin/sbd-o-bahn-server-tester-bin.rs index 627637d..2940072 100644 --- a/rust/sbd-o-bahn-server-tester/src/bin/sbd-o-bahn-server-tester-bin.rs +++ b/rust/sbd-o-bahn-server-tester/src/bin/sbd-o-bahn-server-tester-bin.rs @@ -4,8 +4,9 @@ async fn main() { // remove the "self" arg args.remove(0); let result = sbd_o_bahn_server_tester::run(args).await; - println!("{result:#?}"); + println!("-- TEST RESULTS --\n{result:#?}"); if !result.failed.is_empty() { - panic!("TEST FAILED"); + eprintln!("TEST FAILED"); + std::process::exit(127); } } diff --git a/rust/sbd-o-bahn-server-tester/src/it.rs b/rust/sbd-o-bahn-server-tester/src/it.rs index e618ff6..4e23f10 100644 --- a/rust/sbd-o-bahn-server-tester/src/it.rs +++ b/rust/sbd-o-bahn-server-tester/src/it.rs @@ -4,42 +4,45 @@ use std::io::{Error, Result}; use crate::Report; macro_rules! expect { - ($h:ident, $cond:expr, $note:literal) => { - $h.expect(file!(), line!(), $cond, $note) + ($cond:expr, $note:expr) => { + if !$cond { + return Err(::std::io::Error::other( + format!( + "{}:{}: failed: {}", + file!(), + line!(), + $note, + ) + )); + } }; } /// Utilities for helping with the test. pub struct TestHelper<'h> { - addr_list: &'h [String], + server: &'h mut crate::Server, + addr_list: Vec, err_list: Vec, report: Report, } impl<'h> TestHelper<'h> { - fn new(addr_list: &'h [String]) -> Self { + fn new(server: &'h mut crate::Server) -> Self { Self { - addr_list, + server, + addr_list: Vec::new(), err_list: Vec::new(), report: Report::default(), } } - fn into_report(self) -> Report { - self.report + pub async fn start(&mut self) { + self.addr_list = self.server.start().await; + println!("GOT RUNNING ADDRS: {:?}", self.addr_list); } - /// expect a condition to be true - pub fn expect( - &mut self, - file: &'static str, - line: u32, - cond: bool, - note: &'static str, - ) { - if !cond { - self.err_list.push(format!("{file}:{line}: failed: {note}")); - } + fn into_report(self) -> Report { + self.report } /// connect a client @@ -62,6 +65,27 @@ impl<'h> TestHelper<'h> { } Err(Error::other("could not connect to server")) } + + /// connect a raw client + pub async fn connect_raw_client( + &self, + path: String, + max_message_size: usize, + headers: Vec<(String, String)>, + ) -> Result<(sbd_client::raw_client::WsRawSend, sbd_client::raw_client::WsRawRecv)> { + for addr in self.addr_list.iter() { + if let Ok(client) = (sbd_client::raw_client::WsRawConnect { + full_url: format!("ws://{addr}/{path}"), + max_message_size, + allow_plain_text: true, + danger_disable_certificate_check: false, + headers: headers.clone(), + }).connect().await { + return Ok(client); + } + } + Err(Error::other("could not connect to server")) + } } /// Test definition. @@ -72,23 +96,33 @@ pub trait It { } pub mod it_1; +pub mod it_2; /// Execute the full test suite. -pub async fn exec_all(addr_list: &[String]) -> Report { - let mut helper = TestHelper::new(addr_list); +pub async fn exec_all(server: &mut crate::Server) -> Report { + let mut helper = TestHelper::new(server); exec_one::(&mut helper).await; + exec_one::(&mut helper).await; helper.into_report() } -async fn exec_one<'h, T: It>(helper: &mut TestHelper<'h>) { +async fn exec_one<'h, T: It>( + helper: &mut TestHelper<'h>, +) { + println!("-- RUNNING TEST {} --", T::NAME); + + helper.start().await; + helper.err_list.clear(); match T::exec(helper).await { Ok(_) => { + println!("passed"); helper.report.passed.push(T::NAME.to_string()); } Err(err) => { + println!("{err:?}"); helper.err_list.push(err.to_string()); let err = format!("{:?}", helper.err_list); helper.err_list.clear(); diff --git a/rust/sbd-o-bahn-server-tester/src/it/it_1.rs b/rust/sbd-o-bahn-server-tester/src/it/it_1.rs index ad6937e..544d684 100644 --- a/rust/sbd-o-bahn-server-tester/src/it/it_1.rs +++ b/rust/sbd-o-bahn-server-tester/src/it/it_1.rs @@ -8,6 +8,8 @@ impl It for It1 { fn exec(helper: &mut TestHelper) -> impl Future> { async { + println!("create clients"); + let ((c1, mut r1), (c2, mut r2)) = tokio::try_join!( helper.connect_client(), helper.connect_client(), @@ -16,25 +18,27 @@ impl It for It1 { let p1 = c1.pub_key().clone(); let p2 = c2.pub_key().clone(); + println!("connect clients"); tokio::try_join!(c1.send(&p2, b"hello"), c2.send(&p1, b"world"))?; + println!("await results"); let (result1, result2) = tokio::try_join!( async { r1.recv().await.ok_or(Error::other("closed")) }, async { r2.recv().await.ok_or(Error::other("closed")) }, )?; + println!("check results"); + expect!( - helper, result1.pub_key_ref() == &p2[..], "r1 recv from p2" ); - expect!(helper, result1.message() == b"world", "r1 got 'world'"); + expect!(result1.message() == b"world", "r1 got 'world'"); expect!( - helper, result2.pub_key_ref() == &p1[..], "r2 recv from p1" ); - expect!(helper, result2.message() == b"hello", "r2 got 'hello'"); + expect!(result2.message() == b"hello", "r2 got 'hello'"); Ok(()) } diff --git a/rust/sbd-o-bahn-server-tester/src/it/it_2.rs b/rust/sbd-o-bahn-server-tester/src/it/it_2.rs new file mode 100644 index 0000000..729f941 --- /dev/null +++ b/rust/sbd-o-bahn-server-tester/src/it/it_2.rs @@ -0,0 +1,32 @@ +use super::*; + +/// test 2 +pub struct It2; + +impl It for It2 { + const NAME: &'static str = "bad-pubkey-path"; + + fn exec(helper: &mut TestHelper) -> impl Future> { + async { + let (_send, mut recv) = helper.connect_raw_client( + "bad-pubkey-path".to_string(), + 20_000, + vec![], + ).await?; + + let err = match recv.recv().await { + Ok(_) => return Err(Error::other("unexpected connect success")), + Err(err) => err.to_string(), + }; + + let msg = format!("expected 'Connection reset', but got: {err}"); + + expect!( + err.contains("Connection reset"), + &msg + ); + + Ok(()) + } + } +} diff --git a/rust/sbd-o-bahn-server-tester/src/lib.rs b/rust/sbd-o-bahn-server-tester/src/lib.rs index 154fedb..118e398 100644 --- a/rust/sbd-o-bahn-server-tester/src/lib.rs +++ b/rust/sbd-o-bahn-server-tester/src/lib.rs @@ -29,12 +29,9 @@ pub struct Report { /// Run the test suite. pub async fn run>(cmd: Vec) -> Report { - let mut server = Server::spawn(cmd).await.unwrap(); - let addrs = server.start().await; + let mut server = crate::Server::spawn(cmd).await.unwrap(); - println!("GOT RUNNING ADDRS: {addrs:?}"); - - it::exec_all(&addrs).await + it::exec_all(&mut server).await } struct Server { diff --git a/rust/sbd-server/tests/suite.rs b/rust/sbd-server/tests/suite.rs index a9704cd..a00acd2 100644 --- a/rust/sbd-server/tests/suite.rs +++ b/rust/sbd-server/tests/suite.rs @@ -18,10 +18,13 @@ fn suite() { .unwrap(); println!("RUNNING the test suite {:?}", suite.path()); - assert!(suite + let result = suite .command() .arg(server.path()) - .status() - .unwrap() - .success()); + .status(); + + match result { + Ok(status) if status.success() => (), + _ => std::process::exit(127), + } } From bd326e95d636b054ee862c4d23e1ffae6a468395 Mon Sep 17 00:00:00 2001 From: David Braden Date: Mon, 8 Jul 2024 13:12:27 -0600 Subject: [PATCH 18/36] Update ts/sbd-server/server-o-bahn-runner.mjs Co-authored-by: Jost Schulte --- ts/sbd-server/server-o-bahn-runner.mjs | 1 - 1 file changed, 1 deletion(-) diff --git a/ts/sbd-server/server-o-bahn-runner.mjs b/ts/sbd-server/server-o-bahn-runner.mjs index e7078a3..acd33c0 100755 --- a/ts/sbd-server/server-o-bahn-runner.mjs +++ b/ts/sbd-server/server-o-bahn-runner.mjs @@ -36,7 +36,6 @@ class Srv { return await new Promise((r, _) => { rl.on('line', (line) => { - //console.log(`stdout:line:${line}`) const match = line.match(reReady) if (match && match.length > 1 && match[1]) { out.#addr = match[1] From 15883dac0692599310893462abb0edd293300685 Mon Sep 17 00:00:00 2001 From: David Braden Date: Mon, 8 Jul 2024 13:17:55 -0600 Subject: [PATCH 19/36] Update ts/sbd-server/src/index.ts Co-authored-by: Jost Schulte --- ts/sbd-server/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ts/sbd-server/src/index.ts b/ts/sbd-server/src/index.ts index 8e5b92b..64a7dec 100644 --- a/ts/sbd-server/src/index.ts +++ b/ts/sbd-server/src/index.ts @@ -36,7 +36,7 @@ const LIMIT_NANOS_PER_BYTE = 8000; const LIMIT_IDLE_MILLIS = 10000; /** - * Cloudflare worker typescript boilerplate. + * Cloudflare worker environment objects. */ export interface Env { SIGNAL: DurableObjectNamespace; From 6a92bdc9da99a2f1a1f22d2726cd0a43be303490 Mon Sep 17 00:00:00 2001 From: neonphog Date: Tue, 9 Jul 2024 15:03:43 -0600 Subject: [PATCH 20/36] bad sig test --- rust/sbd-o-bahn-server-tester/src/it.rs | 30 +++++---- rust/sbd-o-bahn-server-tester/src/it/it_1.rs | 10 +-- rust/sbd-o-bahn-server-tester/src/it/it_2.rs | 25 +++++--- rust/sbd-o-bahn-server-tester/src/it/it_3.rs | 67 ++++++++++++++++++++ rust/sbd-server/tests/suite.rs | 5 +- 5 files changed, 102 insertions(+), 35 deletions(-) create mode 100644 rust/sbd-o-bahn-server-tester/src/it/it_3.rs diff --git a/rust/sbd-o-bahn-server-tester/src/it.rs b/rust/sbd-o-bahn-server-tester/src/it.rs index 4e23f10..8f781f6 100644 --- a/rust/sbd-o-bahn-server-tester/src/it.rs +++ b/rust/sbd-o-bahn-server-tester/src/it.rs @@ -6,14 +6,12 @@ use crate::Report; macro_rules! expect { ($cond:expr, $note:expr) => { if !$cond { - return Err(::std::io::Error::other( - format!( - "{}:{}: failed: {}", - file!(), - line!(), - $note, - ) - )); + return Err(::std::io::Error::other(format!( + "{}:{}: failed: {}", + file!(), + line!(), + $note, + ))); } }; } @@ -72,7 +70,10 @@ impl<'h> TestHelper<'h> { path: String, max_message_size: usize, headers: Vec<(String, String)>, - ) -> Result<(sbd_client::raw_client::WsRawSend, sbd_client::raw_client::WsRawRecv)> { + ) -> Result<( + sbd_client::raw_client::WsRawSend, + sbd_client::raw_client::WsRawRecv, + )> { for addr in self.addr_list.iter() { if let Ok(client) = (sbd_client::raw_client::WsRawConnect { full_url: format!("ws://{addr}/{path}"), @@ -80,7 +81,10 @@ impl<'h> TestHelper<'h> { allow_plain_text: true, danger_disable_certificate_check: false, headers: headers.clone(), - }).connect().await { + }) + .connect() + .await + { return Ok(client); } } @@ -97,6 +101,7 @@ pub trait It { pub mod it_1; pub mod it_2; +pub mod it_3; /// Execute the full test suite. pub async fn exec_all(server: &mut crate::Server) -> Report { @@ -104,13 +109,12 @@ pub async fn exec_all(server: &mut crate::Server) -> Report { exec_one::(&mut helper).await; exec_one::(&mut helper).await; + exec_one::(&mut helper).await; helper.into_report() } -async fn exec_one<'h, T: It>( - helper: &mut TestHelper<'h>, -) { +async fn exec_one<'h, T: It>(helper: &mut TestHelper<'h>) { println!("-- RUNNING TEST {} --", T::NAME); helper.start().await; diff --git a/rust/sbd-o-bahn-server-tester/src/it/it_1.rs b/rust/sbd-o-bahn-server-tester/src/it/it_1.rs index 544d684..189ba69 100644 --- a/rust/sbd-o-bahn-server-tester/src/it/it_1.rs +++ b/rust/sbd-o-bahn-server-tester/src/it/it_1.rs @@ -29,15 +29,9 @@ impl It for It1 { println!("check results"); - expect!( - result1.pub_key_ref() == &p2[..], - "r1 recv from p2" - ); + expect!(result1.pub_key_ref() == &p2[..], "r1 recv from p2"); expect!(result1.message() == b"world", "r1 got 'world'"); - expect!( - result2.pub_key_ref() == &p1[..], - "r2 recv from p1" - ); + expect!(result2.pub_key_ref() == &p1[..], "r2 recv from p1"); expect!(result2.message() == b"hello", "r2 got 'hello'"); Ok(()) diff --git a/rust/sbd-o-bahn-server-tester/src/it/it_2.rs b/rust/sbd-o-bahn-server-tester/src/it/it_2.rs index 729f941..6e9c6ce 100644 --- a/rust/sbd-o-bahn-server-tester/src/it/it_2.rs +++ b/rust/sbd-o-bahn-server-tester/src/it/it_2.rs @@ -8,23 +8,28 @@ impl It for It2 { fn exec(helper: &mut TestHelper) -> impl Future> { async { - let (_send, mut recv) = helper.connect_raw_client( - "bad-pubkey-path".to_string(), - 20_000, - vec![], - ).await?; + let (_send, mut recv) = match helper + .connect_raw_client( + "bad-pubkey-path".to_string(), + 20_000, + vec![], + ) + .await + { + Ok(r) => r, + Err(_) => return Ok(()), + }; let err = match recv.recv().await { - Ok(_) => return Err(Error::other("unexpected connect success")), + Ok(_) => { + return Err(Error::other("unexpected connect success")) + } Err(err) => err.to_string(), }; let msg = format!("expected 'Connection reset', but got: {err}"); - expect!( - err.contains("Connection reset"), - &msg - ); + expect!(err.contains("Connection reset"), &msg); Ok(()) } diff --git a/rust/sbd-o-bahn-server-tester/src/it/it_3.rs b/rust/sbd-o-bahn-server-tester/src/it/it_3.rs new file mode 100644 index 0000000..4570bda --- /dev/null +++ b/rust/sbd-o-bahn-server-tester/src/it/it_3.rs @@ -0,0 +1,67 @@ +use super::*; +use std::sync::Arc; + +/// test 3 +pub struct It3; + +impl It for It3 { + const NAME: &'static str = "bad-handshake-sig"; + + fn exec(helper: &mut TestHelper) -> impl Future> { + async { + use sbd_client::Crypto; + + let crypto = sbd_client::DefaultCrypto::default(); + + let pub_key = sbd_client::PubKey(Arc::new(*crypto.pub_key())); + + let (mut send, mut recv) = helper + .connect_raw_client(format!("{pub_key:?}"), 20_000, vec![]) + .await?; + + let _sig = loop { + let msg = recv.recv().await?; + + if msg.len() < 32 { + return Err(Error::other("invalid msg len")); + } + + if msg[28] == b'a' + && msg[29] == b'r' + && msg[30] == b'e' + && msg[31] == b'q' + { + break crypto.sign(&msg[32..])?; + } + }; + + let mut res = vec![0_u8; 32 + 64]; + res[28] = b'a'; + res[29] = b'r'; + res[30] = b'e'; + res[31] = b's'; + + // the following line should make it handshake success. + // but, since we're testing the negative, leave the signature + // as all zeroes. + //res[32..].copy_from_slice(&sig); + + send.send(res).await?; + + loop { + match recv.recv().await { + Ok(msg) => { + let cmd = String::from_utf8_lossy(&msg[28..32]); + if cmd == "lbrt" { + continue; + } + return Err(Error::other(format!( + "unexpected handshake success: {cmd}" + ))); + } + Err(_) => return Ok(()), + } + } + } + } +} diff --git a/rust/sbd-server/tests/suite.rs b/rust/sbd-server/tests/suite.rs index a00acd2..bf8df9c 100644 --- a/rust/sbd-server/tests/suite.rs +++ b/rust/sbd-server/tests/suite.rs @@ -18,10 +18,7 @@ fn suite() { .unwrap(); println!("RUNNING the test suite {:?}", suite.path()); - let result = suite - .command() - .arg(server.path()) - .status(); + let result = suite.command().arg(server.path()).status(); match result { Ok(status) if status.success() => (), From 93c53d80fd7367cd35f19f00b3b33495525ce282 Mon Sep 17 00:00:00 2001 From: neonphog Date: Tue, 9 Jul 2024 15:47:07 -0600 Subject: [PATCH 21/36] test 4 & 5 --- rust/sbd-o-bahn-server-tester/src/it.rs | 4 ++ rust/sbd-o-bahn-server-tester/src/it/it_4.rs | 38 ++++++++++++++++ rust/sbd-o-bahn-server-tester/src/it/it_5.rs | 45 +++++++++++++++++++ .../examples/server-o-bahn-runner.rs | 1 + rust/sbd-server/src/cslot.rs | 27 +++++++---- ts/sbd-server/src/index.ts | 5 ++- 6 files changed, 110 insertions(+), 10 deletions(-) create mode 100644 rust/sbd-o-bahn-server-tester/src/it/it_4.rs create mode 100644 rust/sbd-o-bahn-server-tester/src/it/it_5.rs diff --git a/rust/sbd-o-bahn-server-tester/src/it.rs b/rust/sbd-o-bahn-server-tester/src/it.rs index 8f781f6..8c9d729 100644 --- a/rust/sbd-o-bahn-server-tester/src/it.rs +++ b/rust/sbd-o-bahn-server-tester/src/it.rs @@ -102,6 +102,8 @@ pub trait It { pub mod it_1; pub mod it_2; pub mod it_3; +pub mod it_4; +pub mod it_5; /// Execute the full test suite. pub async fn exec_all(server: &mut crate::Server) -> Report { @@ -110,6 +112,8 @@ pub async fn exec_all(server: &mut crate::Server) -> Report { exec_one::(&mut helper).await; exec_one::(&mut helper).await; exec_one::(&mut helper).await; + exec_one::(&mut helper).await; + exec_one::(&mut helper).await; helper.into_report() } diff --git a/rust/sbd-o-bahn-server-tester/src/it/it_4.rs b/rust/sbd-o-bahn-server-tester/src/it/it_4.rs new file mode 100644 index 0000000..73470a8 --- /dev/null +++ b/rust/sbd-o-bahn-server-tester/src/it/it_4.rs @@ -0,0 +1,38 @@ +use super::*; +use std::sync::Arc; + +/// test 4 +pub struct It4; + +impl It for It4 { + const NAME: &'static str = "ignore-none-pre-handshake"; + + fn exec(helper: &mut TestHelper) -> impl Future> { + async { + use sbd_client::Crypto; + + let crypto = sbd_client::DefaultCrypto::default(); + + let pub_key = sbd_client::PubKey(Arc::new(*crypto.pub_key())); + + let (mut send, mut recv) = helper + .connect_raw_client(format!("{pub_key:?}"), 20_000, vec![]) + .await?; + + let mut none = vec![0_u8; 49]; + none[28] = b'n'; + none[29] = b'o'; + none[30] = b'n'; + none[31] = b'e'; + + send.send(none).await?; + + sbd_client::raw_client::Handshake::handshake( + &mut send, &mut recv, &crypto, + ) + .await?; + + Ok(()) + } + } +} diff --git a/rust/sbd-o-bahn-server-tester/src/it/it_5.rs b/rust/sbd-o-bahn-server-tester/src/it/it_5.rs new file mode 100644 index 0000000..6e8ef5f --- /dev/null +++ b/rust/sbd-o-bahn-server-tester/src/it/it_5.rs @@ -0,0 +1,45 @@ +use super::*; +use std::sync::Arc; + +/// test 5 +pub struct It5; + +impl It for It5 { + const NAME: &'static str = "ignore-none-post-handshake"; + + fn exec(helper: &mut TestHelper) -> impl Future> { + async { + use sbd_client::Crypto; + + let crypto = sbd_client::DefaultCrypto::default(); + + let pub_key = sbd_client::PubKey(Arc::new(*crypto.pub_key())); + + let (mut send, mut recv) = helper + .connect_raw_client(format!("{pub_key:?}"), 20_000, vec![]) + .await?; + + sbd_client::raw_client::Handshake::handshake( + &mut send, &mut recv, &crypto, + ) + .await?; + + let mut none = vec![0_u8; 49]; + none[28] = b'n'; + none[29] = b'o'; + none[30] = b'n'; + none[31] = b'e'; + + send.send(none).await?; + + let mut msg = vec![0_u8; 32]; + msg.copy_from_slice(crypto.pub_key()); + + send.send(msg).await?; + + let _msg = recv.recv().await?; + + Ok(()) + } + } +} diff --git a/rust/sbd-server/examples/server-o-bahn-runner.rs b/rust/sbd-server/examples/server-o-bahn-runner.rs index c3d7d2b..f087595 100644 --- a/rust/sbd-server/examples/server-o-bahn-runner.rs +++ b/rust/sbd-server/examples/server-o-bahn-runner.rs @@ -15,6 +15,7 @@ async fn main() { "CMD/START" => { drop(server); let mut config = sbd_server::Config::default(); + config.limit_clients = 100; config.bind.push("127.0.0.1:0".to_string()); config.bind.push("[::1]:0".to_string()); server = Some( diff --git a/rust/sbd-server/src/cslot.rs b/rust/sbd-server/src/cslot.rs index 9bacea6..b0f39a4 100644 --- a/rust/sbd-server/src/cslot.rs +++ b/rust/sbd-server/src/cslot.rs @@ -341,18 +341,27 @@ async fn ws_task( ws.send(cmd::SbdCmd::auth_req(&nonce)).await?; - let auth_res = ws.recv().await?; + loop { + let auth_res = ws.recv().await?; - if !ip_rate.is_ok(&ip, auth_res.as_ref().len()).await { - return Err(Error::other("ip rate limited")); - } + if !ip_rate.is_ok(&ip, auth_res.as_ref().len()).await { + return Err(Error::other("ip rate limited")); + } - if let cmd::SbdCmd::AuthRes(sig) = cmd::SbdCmd::parse(auth_res)? { - if !pk.verify(&sig, &nonce) { - return Err(Error::other("invalid sig")); + match cmd::SbdCmd::parse(auth_res)? { + cmd::SbdCmd::AuthRes(sig) => { + if !pk.verify(&sig, &nonce) { + return Err(Error::other("invalid sig")); + } + break; + } + cmd::SbdCmd::Message(_) => { + return Err(Error::other( + "invalid forward before handshake", + )); + } + _ => continue, } - } else { - return Err(Error::other("invalid auth response")); } // NOTE: the byte_nanos limit is sent during the cslot insert diff --git a/ts/sbd-server/src/index.ts b/ts/sbd-server/src/index.ts index 64a7dec..26e6a59 100644 --- a/ts/sbd-server/src/index.ts +++ b/ts/sbd-server/src/index.ts @@ -317,7 +317,10 @@ export class DoSignal extends DurableObject { JSON.stringify({ pubKey: toB64Url(pubKey) }), ); } else { - throw err(`invalid handshake message type ${msg.type()}`); + if (msg instanceof MsgForward) { + throw err(`invalid forward before handshake`); + } + // otherwise just ignore the message } } else { if (msg instanceof MsgNone) { From 07a015a5acbd9c47166e41b67d72b3394c46e046 Mon Sep 17 00:00:00 2001 From: neonphog Date: Tue, 9 Jul 2024 16:28:03 -0600 Subject: [PATCH 22/36] msg-too-big --- rust/sbd-o-bahn-server-tester/src/it.rs | 2 ++ rust/sbd-o-bahn-server-tester/src/it/it_6.rs | 38 ++++++++++++++++++++ spec.md | 1 + ts/sbd-server/src/index.ts | 9 +++++ 4 files changed, 50 insertions(+) create mode 100644 rust/sbd-o-bahn-server-tester/src/it/it_6.rs diff --git a/rust/sbd-o-bahn-server-tester/src/it.rs b/rust/sbd-o-bahn-server-tester/src/it.rs index 8c9d729..d948ccb 100644 --- a/rust/sbd-o-bahn-server-tester/src/it.rs +++ b/rust/sbd-o-bahn-server-tester/src/it.rs @@ -104,6 +104,7 @@ pub mod it_2; pub mod it_3; pub mod it_4; pub mod it_5; +pub mod it_6; /// Execute the full test suite. pub async fn exec_all(server: &mut crate::Server) -> Report { @@ -114,6 +115,7 @@ pub async fn exec_all(server: &mut crate::Server) -> Report { exec_one::(&mut helper).await; exec_one::(&mut helper).await; exec_one::(&mut helper).await; + exec_one::(&mut helper).await; helper.into_report() } diff --git a/rust/sbd-o-bahn-server-tester/src/it/it_6.rs b/rust/sbd-o-bahn-server-tester/src/it/it_6.rs new file mode 100644 index 0000000..5bc7c2d --- /dev/null +++ b/rust/sbd-o-bahn-server-tester/src/it/it_6.rs @@ -0,0 +1,38 @@ +use super::*; +use std::sync::Arc; + +/// test 6 +pub struct It6; + +impl It for It6 { + const NAME: &'static str = "msg-too-big"; + + fn exec(helper: &mut TestHelper) -> impl Future> { + async { + use sbd_client::Crypto; + + let crypto = sbd_client::DefaultCrypto::default(); + + let pub_key = sbd_client::PubKey(Arc::new(*crypto.pub_key())); + + let (mut send, mut recv) = helper + .connect_raw_client(format!("{pub_key:?}"), 25_000, vec![]) + .await?; + + sbd_client::raw_client::Handshake::handshake( + &mut send, &mut recv, &crypto, + ) + .await?; + + let mut msg = vec![0_u8; 25_000]; + msg[..32].copy_from_slice(crypto.pub_key()); + + send.send(msg).await?; + + match recv.recv().await { + Ok(_) => Err(Error::other("unexpected success")), + Err(_) => Ok(()), + } + } + } +} diff --git a/spec.md b/spec.md index c342c83..c5537ca 100644 --- a/spec.md +++ b/spec.md @@ -51,6 +51,7 @@ If the header is a "command" the next four literal ascii bytes are interpreted a - `ares` - authentication response - 64 byte signature - client sent - `srdy` - server ready - no additional data - server sent - `keep` - keepalive - no additional data - client sent +- `none` - unknown - arbitary additional data - reserved to repr unknown msg If the header is a "forward" type, the 32 byte header is interpreted as the public key to forward the message to. The remaining bytes in the message are the data to forward. diff --git a/ts/sbd-server/src/index.ts b/ts/sbd-server/src/index.ts index 26e6a59..773829c 100644 --- a/ts/sbd-server/src/index.ts +++ b/ts/sbd-server/src/index.ts @@ -35,6 +35,11 @@ const LIMIT_NANOS_PER_BYTE = 8000; */ const LIMIT_IDLE_MILLIS = 10000; +/** + * Max message size. + */ +const MAX_MESSAGE_BYTES = 20000; + /** * Cloudflare worker environment objects. */ @@ -291,6 +296,10 @@ export class DoSignal extends DurableObject { await this.ipRateLimit(ip, pubKey, msgRaw.byteLength, ws); + if (msgRaw.byteLength > MAX_MESSAGE_BYTES) { + throw err('max message length exceeded', 400); + } + const msg = Msg.parse(msgRaw); if (!valid) { From 680360e6a4901379f00ae69d07345e11f7a11f9d Mon Sep 17 00:00:00 2001 From: neonphog Date: Tue, 9 Jul 2024 16:51:52 -0600 Subject: [PATCH 23/36] order stress --- rust/sbd-o-bahn-server-tester/src/it.rs | 3 +- rust/sbd-o-bahn-server-tester/src/it/it_7.rs | 80 ++++++++++++++++++++ 2 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 rust/sbd-o-bahn-server-tester/src/it/it_7.rs diff --git a/rust/sbd-o-bahn-server-tester/src/it.rs b/rust/sbd-o-bahn-server-tester/src/it.rs index d948ccb..6742bb1 100644 --- a/rust/sbd-o-bahn-server-tester/src/it.rs +++ b/rust/sbd-o-bahn-server-tester/src/it.rs @@ -105,6 +105,7 @@ pub mod it_3; pub mod it_4; pub mod it_5; pub mod it_6; +pub mod it_7; /// Execute the full test suite. pub async fn exec_all(server: &mut crate::Server) -> Report { @@ -115,7 +116,7 @@ pub async fn exec_all(server: &mut crate::Server) -> Report { exec_one::(&mut helper).await; exec_one::(&mut helper).await; exec_one::(&mut helper).await; - exec_one::(&mut helper).await; + exec_one::(&mut helper).await; helper.into_report() } diff --git a/rust/sbd-o-bahn-server-tester/src/it/it_7.rs b/rust/sbd-o-bahn-server-tester/src/it/it_7.rs new file mode 100644 index 0000000..51c1d36 --- /dev/null +++ b/rust/sbd-o-bahn-server-tester/src/it/it_7.rs @@ -0,0 +1,80 @@ +use super::*; +use std::sync::Arc; + +const COUNT: usize = 10; + +/// test 7 +pub struct It7; + +impl It for It7 { + const NAME: &'static str = "order-stress"; + + fn exec(helper: &mut TestHelper) -> impl Future> { + async { + let (c, mut r) = helper.connect_client().await?; + let p = c.pub_key().clone(); + + let mut tasks = Vec::new(); + + let b = Arc::new(tokio::sync::Barrier::new(COUNT)); + + for _ in 0..COUNT { + let p = p.clone(); + let b = b.clone(); + let (c, mut r) = helper.connect_client().await?; + tasks.push(tokio::task::spawn(async move { + c.send(&p, b"a").await?; + + let m = + r.recv().await.ok_or_else(|| Error::other("closed"))?; + + if m.message() != b"a" { + return Err(Error::other("bad resp")); + } + + b.wait().await; + + const LIST: &[&[u8]] = + &[b"b", b"c", b"d", b"e", b"f", b"g", b"h", b"i", b"j"]; + + for d in LIST { + c.send(&p, d).await?; + } + + for d in LIST { + let m = r + .recv() + .await + .ok_or_else(|| Error::other("closed"))?; + if &m.message() != d { + return Err(Error::other("bad resp")); + } + } + + Ok(()) + })); + } + + let mut count = 0; + + loop { + count += 1; + + let msg = + r.recv().await.ok_or_else(|| Error::other("closed"))?; + + c.send(&msg.pub_key(), msg.message()).await?; + + if count >= COUNT * 10 { + break; + } + } + + for task in tasks { + task.await??; + } + + Ok(()) + } + } +} From 89bb5e441092f9cff4ec42e2994c47985f24106b Mon Sep 17 00:00:00 2001 From: neonphog Date: Wed, 10 Jul 2024 11:34:00 -0600 Subject: [PATCH 24/36] tweaks --- rust/sbd-client/src/send_buf.rs | 11 +++++++++++ ts/sbd-server/package.json | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/rust/sbd-client/src/send_buf.rs b/rust/sbd-client/src/send_buf.rs index b6494cf..e155de1 100644 --- a/rust/sbd-client/src/send_buf.rs +++ b/rust/sbd-client/src/send_buf.rs @@ -59,6 +59,14 @@ impl SendBuf { /// We received a new rate limit from the server, update our records. pub fn new_rate_limit(&mut self, limit: u64) { + /* + + -- This was premature and caused some client lockups. + -- I'm going to leave the code in here for now as + -- an example of a naive solution that did *not* work, + -- in case we see that bumping rate limits on new + -- connections does indeed cause bad ratelimit drops. + if limit < self.limit_rate { // rate limit updates are sent on a best effort, // and there are network timing conditions to worry about. @@ -70,6 +78,9 @@ impl SendBuf { self.next_send_at = std::cmp::max(now, self.next_send_at) + (MAX_MSG_SIZE as u64 * self.limit_rate); } + + */ + self.limit_rate = limit; let kbps = (8_000_000.0 / limit as f64) as u64; let next_send_s = self.next_send_at as f64 / 1_000_000_000.0; diff --git a/ts/sbd-server/package.json b/ts/sbd-server/package.json index c619b80..e54f0fb 100644 --- a/ts/sbd-server/package.json +++ b/ts/sbd-server/package.json @@ -3,7 +3,7 @@ "version": "0.0.0", "private": true, "scripts": { - "deploy": "wrangler deploy", + "deploy": "wrangler deploy --minify", "dev": "wrangler dev", "start": "wrangler dev", "test:fmt": "prettier -w src", From ed9c52a44e8ebdef89f34471820099f777002957 Mon Sep 17 00:00:00 2001 From: neonphog Date: Wed, 10 Jul 2024 15:05:18 -0600 Subject: [PATCH 25/36] address code review comments --- rust/sbd-o-bahn-server-tester/src/it.rs | 6 +- rust/sbd-o-bahn-server-tester/src/it/it_1.rs | 4 +- rust/sbd-o-bahn-server-tester/src/it/it_2.rs | 4 +- rust/sbd-o-bahn-server-tester/src/it/it_3.rs | 3 +- rust/sbd-o-bahn-server-tester/src/it/it_4.rs | 3 +- rust/sbd-o-bahn-server-tester/src/it/it_5.rs | 3 +- rust/sbd-o-bahn-server-tester/src/it/it_6.rs | 4 +- rust/sbd-o-bahn-server-tester/src/it/it_7.rs | 4 +- rust/sbd-o-bahn-server-tester/src/it/it_8.rs | 74 ++++++++++++++++++++ 9 files changed, 97 insertions(+), 8 deletions(-) create mode 100644 rust/sbd-o-bahn-server-tester/src/it/it_8.rs diff --git a/rust/sbd-o-bahn-server-tester/src/it.rs b/rust/sbd-o-bahn-server-tester/src/it.rs index 6742bb1..4caa8b0 100644 --- a/rust/sbd-o-bahn-server-tester/src/it.rs +++ b/rust/sbd-o-bahn-server-tester/src/it.rs @@ -95,6 +95,7 @@ impl<'h> TestHelper<'h> { /// Test definition. pub trait It { const NAME: &'static str; + const DESC: &'static str; fn exec(helper: &mut TestHelper) -> impl Future>; } @@ -106,6 +107,7 @@ pub mod it_4; pub mod it_5; pub mod it_6; pub mod it_7; +pub mod it_8; /// Execute the full test suite. pub async fn exec_all(server: &mut crate::Server) -> Report { @@ -116,13 +118,15 @@ pub async fn exec_all(server: &mut crate::Server) -> Report { exec_one::(&mut helper).await; exec_one::(&mut helper).await; exec_one::(&mut helper).await; + exec_one::(&mut helper).await; exec_one::(&mut helper).await; + exec_one::(&mut helper).await; helper.into_report() } async fn exec_one<'h, T: It>(helper: &mut TestHelper<'h>) { - println!("-- RUNNING TEST {} --", T::NAME); + println!("-- RUNNING TEST {} ({}) --", T::NAME, T::DESC); helper.start().await; diff --git a/rust/sbd-o-bahn-server-tester/src/it/it_1.rs b/rust/sbd-o-bahn-server-tester/src/it/it_1.rs index 189ba69..1ba4f8b 100644 --- a/rust/sbd-o-bahn-server-tester/src/it/it_1.rs +++ b/rust/sbd-o-bahn-server-tester/src/it/it_1.rs @@ -4,7 +4,9 @@ use super::*; pub struct It1; impl It for It1 { - const NAME: &'static str = "sanity"; + const NAME: &'static str = "1-sanity"; + const DESC: &'static str = + "two simple nodes are able to send messages to each other"; fn exec(helper: &mut TestHelper) -> impl Future> { async { diff --git a/rust/sbd-o-bahn-server-tester/src/it/it_2.rs b/rust/sbd-o-bahn-server-tester/src/it/it_2.rs index 6e9c6ce..334647c 100644 --- a/rust/sbd-o-bahn-server-tester/src/it/it_2.rs +++ b/rust/sbd-o-bahn-server-tester/src/it/it_2.rs @@ -4,7 +4,9 @@ use super::*; pub struct It2; impl It for It2 { - const NAME: &'static str = "bad-pubkey-path"; + const NAME: &'static str = "2-bad-pubkey-path"; + const DESC: &'static str = + "connection is dropped if url path is not a valid pubkey"; fn exec(helper: &mut TestHelper) -> impl Future> { async { diff --git a/rust/sbd-o-bahn-server-tester/src/it/it_3.rs b/rust/sbd-o-bahn-server-tester/src/it/it_3.rs index 4570bda..e9884e6 100644 --- a/rust/sbd-o-bahn-server-tester/src/it/it_3.rs +++ b/rust/sbd-o-bahn-server-tester/src/it/it_3.rs @@ -5,7 +5,8 @@ use std::sync::Arc; pub struct It3; impl It for It3 { - const NAME: &'static str = "bad-handshake-sig"; + const NAME: &'static str = "3-bad-handshake-sig"; + const DESC: &'static str = "connection is dropped if the client responds with a bad handshake signature"; fn exec(helper: &mut TestHelper) -> impl Future> { async { diff --git a/rust/sbd-o-bahn-server-tester/src/it/it_4.rs b/rust/sbd-o-bahn-server-tester/src/it/it_4.rs index 73470a8..0651c3a 100644 --- a/rust/sbd-o-bahn-server-tester/src/it/it_4.rs +++ b/rust/sbd-o-bahn-server-tester/src/it/it_4.rs @@ -5,7 +5,8 @@ use std::sync::Arc; pub struct It4; impl It for It4 { - const NAME: &'static str = "ignore-none-pre-handshake"; + const NAME: &'static str = "4-ignore-none-pre-handshake"; + const DESC: &'static str = "ensure server ignores unknown commands before the handshake for forward compatibility"; fn exec(helper: &mut TestHelper) -> impl Future> { async { diff --git a/rust/sbd-o-bahn-server-tester/src/it/it_5.rs b/rust/sbd-o-bahn-server-tester/src/it/it_5.rs index 6e8ef5f..5c2863f 100644 --- a/rust/sbd-o-bahn-server-tester/src/it/it_5.rs +++ b/rust/sbd-o-bahn-server-tester/src/it/it_5.rs @@ -5,7 +5,8 @@ use std::sync::Arc; pub struct It5; impl It for It5 { - const NAME: &'static str = "ignore-none-post-handshake"; + const NAME: &'static str = "5-ignore-none-post-handshake"; + const DESC: &'static str = "ensure server ignores unknown commands after the handshake for forward compatibility"; fn exec(helper: &mut TestHelper) -> impl Future> { async { diff --git a/rust/sbd-o-bahn-server-tester/src/it/it_6.rs b/rust/sbd-o-bahn-server-tester/src/it/it_6.rs index 5bc7c2d..5226e4e 100644 --- a/rust/sbd-o-bahn-server-tester/src/it/it_6.rs +++ b/rust/sbd-o-bahn-server-tester/src/it/it_6.rs @@ -5,7 +5,9 @@ use std::sync::Arc; pub struct It6; impl It for It6 { - const NAME: &'static str = "msg-too-big"; + const NAME: &'static str = "6-msg-too-big"; + const DESC: &'static str = + "connection is dropped if too large a message is sent"; fn exec(helper: &mut TestHelper) -> impl Future> { async { diff --git a/rust/sbd-o-bahn-server-tester/src/it/it_7.rs b/rust/sbd-o-bahn-server-tester/src/it/it_7.rs index 51c1d36..4c35b45 100644 --- a/rust/sbd-o-bahn-server-tester/src/it/it_7.rs +++ b/rust/sbd-o-bahn-server-tester/src/it/it_7.rs @@ -7,7 +7,9 @@ const COUNT: usize = 10; pub struct It7; impl It for It7 { - const NAME: &'static str = "order-stress"; + const NAME: &'static str = "7-order-stress"; + const DESC: &'static str = + "multi-client echo stress test ensure messages are delivered in order"; fn exec(helper: &mut TestHelper) -> impl Future> { async { diff --git a/rust/sbd-o-bahn-server-tester/src/it/it_8.rs b/rust/sbd-o-bahn-server-tester/src/it/it_8.rs new file mode 100644 index 0000000..68c703e --- /dev/null +++ b/rust/sbd-o-bahn-server-tester/src/it/it_8.rs @@ -0,0 +1,74 @@ +use super::*; +use std::sync::Arc; + +const NODE_COUNT: usize = 10; +const MSG_COUNT: usize = 10; + +/// test 8 +pub struct It8; + +impl It for It8 { + const NAME: &'static str = "8-correct-dest"; + const DESC: &'static str = "multi-client echo stress test ensure messages are only delivered to the correct target"; + + fn exec(helper: &mut TestHelper) -> impl Future> { + async { + let mut tasks = Vec::new(); + let mut echo_addrs = Vec::new(); + + for _ in 0..NODE_COUNT { + let (c, mut r) = helper.connect_client().await?; + echo_addrs.push(c.pub_key().clone()); + tasks.push(tokio::task::spawn(async move { + for _ in 0..MSG_COUNT { + let msg = r + .recv() + .await + .ok_or_else(|| Error::other("closed"))?; + + c.send(&msg.pub_key(), msg.message()).await?; + } + + tokio::time::sleep(std::time::Duration::from_secs(1)).await; + + Ok(()) + })); + } + + let b = Arc::new(tokio::sync::Barrier::new(NODE_COUNT)); + + for i in 0..NODE_COUNT { + let p = echo_addrs.remove(0); + let b = b.clone(); + let (c, mut r) = helper.connect_client().await?; + tasks.push(tokio::task::spawn(async move { + for j in 0..MSG_COUNT { + if j == 1 { + b.wait().await; + } + + let msg = format!("{i}-{j}"); + c.send(&p, msg.as_bytes()).await?; + + let m = r + .recv() + .await + .ok_or_else(|| Error::other("closed"))?; + + if m.message() != msg.as_bytes() { + return Err(Error::other("bad resp")); + } + } + + Ok(()) + })); + } + + for task in tasks { + task.await??; + } + + Ok(()) + } + } +} From 6aa92aace8373c852cb29886b39ac214e7bed4a8 Mon Sep 17 00:00:00 2001 From: neonphog Date: Thu, 11 Jul 2024 14:26:41 -0600 Subject: [PATCH 26/36] cloudflare metrics --- ts/sbd-server/README.md | 45 +++++++ ts/sbd-server/package-lock.json | 206 ++++++++++++++++---------------- ts/sbd-server/src/index.ts | 100 +++++++++++++++- ts/sbd-server/src/prom.ts | 46 +++++++ ts/sbd-server/wrangler.toml | 4 + 5 files changed, 295 insertions(+), 106 deletions(-) create mode 100644 ts/sbd-server/README.md create mode 100644 ts/sbd-server/src/prom.ts diff --git a/ts/sbd-server/README.md b/ts/sbd-server/README.md new file mode 100644 index 0000000..aee5bb1 --- /dev/null +++ b/ts/sbd-server/README.md @@ -0,0 +1,45 @@ +# Cloudflare SbdServer + +## Metrics + +It's hard to get a sense of what is going on with distributed durable objects. To mitigate this, we are writing metrics to a KV called `SBD_COORDINATION`. These metrics can be enumerated from a central metrics http endpoint. However, as these metrics list IP addresses, and cause billable load on our worker kv endpoint, they will be guarded by an api key. + +### Set Api Key + +Set these api keys via worker secrets in the form: `METRIC_API_$(whoami)="$(uuidgen)"`. + +E.g. `METRIC_API_NEONPHOG=d6d38e16-9fe2-4cbf-b66d-e49775064d59` + +If doing this through the cloudflare dashboard, don't forget to click `encrypt`! + +Or you can use `wrangler secret put METRIC_API_NEONPHOG` and then paste in the uuidgen result. + +### Access the Metrics Endpoint + +`$(url)/metris/$(whoami)/$(uuidgen)` + +E.g. `https://sbd.holo.host/metrics/NEONPHOG/d6d38e16-9fe2-4cbf-b66d-e49775064d59` + +Should give you something like: + +``` +# HELP client.count active client count +# TYPE client.count guage +client.count 4 + +# HELP client.recv.byte.count bytes received from client +# TYPE client.recv.byte.count guage +client.recv.byte.count{name="AqpAUD6QBb8lOfSBGna4C3tGAbI7E5slQ0MKkjm28kQ",opened=1720728911,active=1720728911,ip="no-ip"} 96 + +# HELP client.recv.byte.count bytes received from client +# TYPE client.recv.byte.count guage +client.recv.byte.count{name="R2qUfRVFfBhGGyxC4i_MorG48Ptk3JXwWvkIsh9mtRo",opened=1720728935,active=1720728935,ip="no-ip"} 96 + +# HELP client.recv.byte.count bytes received from client +# TYPE client.recv.byte.count guage +client.recv.byte.count{name="ia6EqgbobPhVrOdqlqZtL7v8EK5uDj5vlV4uTMB6vsY",opened=1720728936,active=1720728936,ip="no-ip"} 96 + +# HELP client.recv.byte.count bytes received from client +# TYPE client.recv.byte.count guage +client.recv.byte.count{name="u-JEHfSU6hArnHSjf9KA5W_ABH37go3Cm453UagScI8",opened=1720728911,active=1720728911,ip="no-ip"} 96 +``` diff --git a/ts/sbd-server/package-lock.json b/ts/sbd-server/package-lock.json index 697c100..38d3eb6 100644 --- a/ts/sbd-server/package-lock.json +++ b/ts/sbd-server/package-lock.json @@ -114,9 +114,9 @@ } }, "node_modules/@cloudflare/workers-types": { - "version": "4.20240620.0", - "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20240620.0.tgz", - "integrity": "sha512-CQD8YS6evRob7LChvIX3gE3zYo0KVgaLDOu1SwNP1BVIS2Sa0b+FC8S1e1hhrNN8/E4chYlVN+FDAgA4KRDUEQ==", + "version": "4.20240701.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20240701.0.tgz", + "integrity": "sha512-6Cu6NIAicmb8H6CkzFdQG5Ib+TDs9HU8AKQEGlxnbvEBDmhUNpmL30ETXpLS0asdeyc+rTb2xag0hSv0Z1BflQ==", "dev": true }, "node_modules/@cspotcode/source-map-support": { @@ -552,9 +552,9 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "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 }, "node_modules/@jridgewell/trace-mapping": { @@ -587,9 +587,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.0.tgz", - "integrity": "sha512-Tya6xypR10giZV1XzxmH5wr25VcZSncG0pZIjfePT0OVBvqNEurzValetGNarVrGiq66EBVAFn15iYX4w6FKgQ==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.1.tgz", + "integrity": "sha512-lncuC4aHicncmbORnx+dUaAgzee9cm/PbIqgWz1PpXuwc+sa1Ct83tnqUDy/GFKleLiN7ZIeytM6KJ4cAn1SxA==", "cpu": [ "arm" ], @@ -600,9 +600,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.18.0.tgz", - "integrity": "sha512-avCea0RAP03lTsDhEyfy+hpfr85KfyTctMADqHVhLAF3MlIkq83CP8UfAHUssgXTYd+6er6PaAhx/QGv4L1EiA==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.18.1.tgz", + "integrity": "sha512-F/tkdw0WSs4ojqz5Ovrw5r9odqzFjb5LIgHdHZG65dFI1lWTWRVy32KDJLKRISHgJvqUeUhdIvy43fX41znyDg==", "cpu": [ "arm64" ], @@ -613,9 +613,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.18.0.tgz", - "integrity": "sha512-IWfdwU7KDSm07Ty0PuA/W2JYoZ4iTj3TUQjkVsO/6U+4I1jN5lcR71ZEvRh52sDOERdnNhhHU57UITXz5jC1/w==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.18.1.tgz", + "integrity": "sha512-vk+ma8iC1ebje/ahpxpnrfVQJibTMyHdWpOGZ3JpQ7Mgn/3QNHmPq7YwjZbIE7km73dH5M1e6MRRsnEBW7v5CQ==", "cpu": [ "arm64" ], @@ -626,9 +626,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.18.0.tgz", - "integrity": "sha512-n2LMsUz7Ynu7DoQrSQkBf8iNrjOGyPLrdSg802vk6XT3FtsgX6JbE8IHRvposskFm9SNxzkLYGSq9QdpLYpRNA==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.18.1.tgz", + "integrity": "sha512-IgpzXKauRe1Tafcej9STjSSuG0Ghu/xGYH+qG6JwsAUxXrnkvNHcq/NL6nz1+jzvWAnQkuAJ4uIwGB48K9OCGA==", "cpu": [ "x64" ], @@ -639,9 +639,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.18.0.tgz", - "integrity": "sha512-C/zbRYRXFjWvz9Z4haRxcTdnkPt1BtCkz+7RtBSuNmKzMzp3ZxdM28Mpccn6pt28/UWUCTXa+b0Mx1k3g6NOMA==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.18.1.tgz", + "integrity": "sha512-P9bSiAUnSSM7EmyRK+e5wgpqai86QOSv8BwvkGjLwYuOpaeomiZWifEos517CwbG+aZl1T4clSE1YqqH2JRs+g==", "cpu": [ "arm" ], @@ -652,9 +652,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.18.0.tgz", - "integrity": "sha512-l3m9ewPgjQSXrUMHg93vt0hYCGnrMOcUpTz6FLtbwljo2HluS4zTXFy2571YQbisTnfTKPZ01u/ukJdQTLGh9A==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.18.1.tgz", + "integrity": "sha512-5RnjpACoxtS+aWOI1dURKno11d7krfpGDEn19jI8BuWmSBbUC4ytIADfROM1FZrFhQPSoP+KEa3NlEScznBTyQ==", "cpu": [ "arm" ], @@ -665,9 +665,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.18.0.tgz", - "integrity": "sha512-rJ5D47d8WD7J+7STKdCUAgmQk49xuFrRi9pZkWoRD1UeSMakbcepWXPF8ycChBoAqs1pb2wzvbY6Q33WmN2ftw==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.18.1.tgz", + "integrity": "sha512-8mwmGD668m8WaGbthrEYZ9CBmPug2QPGWxhJxh/vCgBjro5o96gL04WLlg5BA233OCWLqERy4YUzX3bJGXaJgQ==", "cpu": [ "arm64" ], @@ -678,9 +678,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.18.0.tgz", - "integrity": "sha512-be6Yx37b24ZwxQ+wOQXXLZqpq4jTckJhtGlWGZs68TgdKXJgw54lUUoFYrg6Zs/kjzAQwEwYbp8JxZVzZLRepQ==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.18.1.tgz", + "integrity": "sha512-dJX9u4r4bqInMGOAQoGYdwDP8lQiisWb9et+T84l2WXk41yEej8v2iGKodmdKimT8cTAYt0jFb+UEBxnPkbXEQ==", "cpu": [ "arm64" ], @@ -691,9 +691,9 @@ ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.18.0.tgz", - "integrity": "sha512-hNVMQK+qrA9Todu9+wqrXOHxFiD5YmdEi3paj6vP02Kx1hjd2LLYR2eaN7DsEshg09+9uzWi2W18MJDlG0cxJA==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.18.1.tgz", + "integrity": "sha512-V72cXdTl4EI0x6FNmho4D502sy7ed+LuVW6Ym8aI6DRQ9hQZdp5sj0a2usYOlqvFBNKQnLQGwmYnujo2HvjCxQ==", "cpu": [ "ppc64" ], @@ -704,9 +704,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.18.0.tgz", - "integrity": "sha512-ROCM7i+m1NfdrsmvwSzoxp9HFtmKGHEqu5NNDiZWQtXLA8S5HBCkVvKAxJ8U+CVctHwV2Gb5VUaK7UAkzhDjlg==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.18.1.tgz", + "integrity": "sha512-f+pJih7sxoKmbjghrM2RkWo2WHUW8UbfxIQiWo5yeCaCM0TveMEuAzKJte4QskBp1TIinpnRcxkquY+4WuY/tg==", "cpu": [ "riscv64" ], @@ -717,9 +717,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.18.0.tgz", - "integrity": "sha512-0UyyRHyDN42QL+NbqevXIIUnKA47A+45WyasO+y2bGJ1mhQrfrtXUpTxCOrfxCR4esV3/RLYyucGVPiUsO8xjg==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.18.1.tgz", + "integrity": "sha512-qb1hMMT3Fr/Qz1OKovCuUM11MUNLUuHeBC2DPPAWUYYUAOFWaxInaTwTQmc7Fl5La7DShTEpmYwgdt2hG+4TEg==", "cpu": [ "s390x" ], @@ -730,9 +730,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.18.0.tgz", - "integrity": "sha512-xuglR2rBVHA5UsI8h8UbX4VJ470PtGCf5Vpswh7p2ukaqBGFTnsfzxUBetoWBWymHMxbIG0Cmx7Y9qDZzr648w==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.18.1.tgz", + "integrity": "sha512-7O5u/p6oKUFYjRbZkL2FLbwsyoJAjyeXHCU3O4ndvzg2OFO2GinFPSJFGbiwFDaCFc+k7gs9CF243PwdPQFh5g==", "cpu": [ "x64" ], @@ -743,9 +743,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.18.0.tgz", - "integrity": "sha512-LKaqQL9osY/ir2geuLVvRRs+utWUNilzdE90TpyoX0eNqPzWjRm14oMEE+YLve4k/NAqCdPkGYDaDF5Sw+xBfg==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.18.1.tgz", + "integrity": "sha512-pDLkYITdYrH/9Cv/Vlj8HppDuLMDUBmgsM0+N+xLtFd18aXgM9Nyqupb/Uw+HeidhfYg2lD6CXvz6CjoVOaKjQ==", "cpu": [ "x64" ], @@ -756,9 +756,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.18.0.tgz", - "integrity": "sha512-7J6TkZQFGo9qBKH0pk2cEVSRhJbL6MtfWxth7Y5YmZs57Pi+4x6c2dStAUvaQkHQLnEQv1jzBUW43GvZW8OFqA==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.18.1.tgz", + "integrity": "sha512-W2ZNI323O/8pJdBGil1oCauuCzmVd9lDmWBBqxYZcOqWD6aWqJtVBQ1dFrF4dYpZPks6F+xCZHfzG5hYlSHZ6g==", "cpu": [ "arm64" ], @@ -769,9 +769,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.18.0.tgz", - "integrity": "sha512-Txjh+IxBPbkUB9+SXZMpv+b/vnTEtFyfWZgJ6iyCmt2tdx0OF5WhFowLmnh8ENGNpfUlUZkdI//4IEmhwPieNg==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.18.1.tgz", + "integrity": "sha512-ELfEX1/+eGZYMaCIbK4jqLxO1gyTSOIlZr6pbC4SRYFaSIDVKOnZNMdoZ+ON0mrFDp4+H5MhwNC1H/AhE3zQLg==", "cpu": [ "ia32" ], @@ -782,9 +782,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.18.0.tgz", - "integrity": "sha512-UOo5FdvOL0+eIVTgS4tIdbW+TtnBLWg1YBCcU2KWM7nuNwRz9bksDX1bekJJCpu25N1DVWaCwnT39dVQxzqS8g==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.18.1.tgz", + "integrity": "sha512-yjk2MAkQmoaPYCSu35RLJ62+dz358nE83VfTePJRp8CG7aMg25mEJYpXFiD+NcevhX8LxD5OP5tktPXnXN7GDw==", "cpu": [ "x64" ], @@ -807,9 +807,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.14.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.9.tgz", - "integrity": "sha512-06OCtnTXtWOZBJlRApleWndH4JsRVs1pDCc8dLSQp+7PpUpX3ePdHyeNSFTeSe7FtKyQkrlPvHwJOW3SLd8Oyg==", + "version": "20.14.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.10.tgz", + "integrity": "sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ==", "dev": true, "dependencies": { "undici-types": "~5.26.4" @@ -894,9 +894,9 @@ } }, "node_modules/acorn": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.0.tgz", - "integrity": "sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==", + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -1723,20 +1723,20 @@ } }, "node_modules/pkg-types": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.1.1.tgz", - "integrity": "sha512-ko14TjmDuQJ14zsotODv7dBlwxKhUKQEhuhmbqo1uCi9BB0Z2alo/wAXg6q1dTR5TyuqYyWhjtfe/Tsh+X28jQ==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.1.3.tgz", + "integrity": "sha512-+JrgthZG6m3ckicaOB74TwQ+tBWsFl3qVQg7mN8ulwSOElJ7gBhKzj2VkCPnZ4NlF6kEquYU+RIYNVAvzd54UA==", "dev": true, "dependencies": { "confbox": "^0.1.7", - "mlly": "^1.7.0", + "mlly": "^1.7.1", "pathe": "^1.1.2" } }, "node_modules/postcss": { - "version": "8.4.38", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", - "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", + "version": "8.4.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.39.tgz", + "integrity": "sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==", "dev": true, "funding": [ { @@ -1754,7 +1754,7 @@ ], "dependencies": { "nanoid": "^3.3.7", - "picocolors": "^1.0.0", + "picocolors": "^1.0.1", "source-map-js": "^1.2.0" }, "engines": { @@ -1841,9 +1841,9 @@ } }, "node_modules/rollup": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.18.0.tgz", - "integrity": "sha512-QmJz14PX3rzbJCN1SG4Xe/bAAX2a6NpCP8ab2vfu2GiUr8AQcr2nCV/oEO3yneFarB67zk8ShlIyWb2LGTb3Sg==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.18.1.tgz", + "integrity": "sha512-Elx2UT8lzxxOXMpy5HWQGZqkrQOtrVDDa/bm9l10+U4rQnVzbL/LgZ4NOM1MPIDyHk69W4InuYDF5dzRh4Kw1A==", "dev": true, "dependencies": { "@types/estree": "1.0.5" @@ -1856,22 +1856,22 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.18.0", - "@rollup/rollup-android-arm64": "4.18.0", - "@rollup/rollup-darwin-arm64": "4.18.0", - "@rollup/rollup-darwin-x64": "4.18.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.18.0", - "@rollup/rollup-linux-arm-musleabihf": "4.18.0", - "@rollup/rollup-linux-arm64-gnu": "4.18.0", - "@rollup/rollup-linux-arm64-musl": "4.18.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.18.0", - "@rollup/rollup-linux-riscv64-gnu": "4.18.0", - "@rollup/rollup-linux-s390x-gnu": "4.18.0", - "@rollup/rollup-linux-x64-gnu": "4.18.0", - "@rollup/rollup-linux-x64-musl": "4.18.0", - "@rollup/rollup-win32-arm64-msvc": "4.18.0", - "@rollup/rollup-win32-ia32-msvc": "4.18.0", - "@rollup/rollup-win32-x64-msvc": "4.18.0", + "@rollup/rollup-android-arm-eabi": "4.18.1", + "@rollup/rollup-android-arm64": "4.18.1", + "@rollup/rollup-darwin-arm64": "4.18.1", + "@rollup/rollup-darwin-x64": "4.18.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.18.1", + "@rollup/rollup-linux-arm-musleabihf": "4.18.1", + "@rollup/rollup-linux-arm64-gnu": "4.18.1", + "@rollup/rollup-linux-arm64-musl": "4.18.1", + "@rollup/rollup-linux-powerpc64le-gnu": "4.18.1", + "@rollup/rollup-linux-riscv64-gnu": "4.18.1", + "@rollup/rollup-linux-s390x-gnu": "4.18.1", + "@rollup/rollup-linux-x64-gnu": "4.18.1", + "@rollup/rollup-linux-x64-musl": "4.18.1", + "@rollup/rollup-win32-arm64-msvc": "4.18.1", + "@rollup/rollup-win32-ia32-msvc": "4.18.1", + "@rollup/rollup-win32-x64-msvc": "4.18.1", "fsevents": "~2.3.2" } }, @@ -2123,9 +2123,9 @@ } }, "node_modules/typescript": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.2.tgz", - "integrity": "sha512-NcRtPEOsPFFWjobJEtfihkLCZCXZt/os3zf8nTxjVH3RvTSxjrCamJpbExGvYOF+tFHc3pA65qpdwPbzjohhew==", + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", + "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -2175,13 +2175,13 @@ } }, "node_modules/vite": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.3.2.tgz", - "integrity": "sha512-6lA7OBHBlXUxiJxbO5aAY2fsHHzDr1q7DvXYnyZycRs2Dz+dXBWuhpWHvmljTRTpQC2uvGmUFFkSHF2vGo90MA==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.3.3.tgz", + "integrity": "sha512-NPQdeCU0Dv2z5fu+ULotpuq5yfCS1BzKUIPhNbP3YBfAMGJXbt2nS+sbTFu+qchaqWTD+H3JK++nRwr6XIcp6A==", "dev": true, "dependencies": { "esbuild": "^0.21.3", - "postcss": "^8.4.38", + "postcss": "^8.4.39", "rollup": "^4.13.0" }, "bin": { @@ -2332,9 +2332,9 @@ } }, "node_modules/why-is-node-running": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.2.2.tgz", - "integrity": "sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", "dev": true, "dependencies": { "siginfo": "^2.0.0", @@ -2368,9 +2368,9 @@ } }, "node_modules/wrangler": { - "version": "3.63.1", - "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-3.63.1.tgz", - "integrity": "sha512-fxMPNEyDc9pZNtQOuYqRikzv6lL5eP4S1zv7L/kw24uu1cCEmJ39j8bfJGzrAEqKDNsiFXVjEka0RjlpgEVWPg==", + "version": "3.64.0", + "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-3.64.0.tgz", + "integrity": "sha512-q2VQADJXzuOkXs9KIfPSx7UCZHBoxsqSNbJDLkc2pHpGmsyNQXsJRqjMoTg/Kls7O3K9A7EGnzGr7+Io2vE6AQ==", "dev": true, "dependencies": { "@cloudflare/kv-asset-handler": "0.3.4", @@ -2826,9 +2826,9 @@ "dev": true }, "node_modules/yocto-queue": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", - "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.1.1.tgz", + "integrity": "sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==", "dev": true, "engines": { "node": ">=12.20" diff --git a/ts/sbd-server/src/index.ts b/ts/sbd-server/src/index.ts index 773829c..bb61909 100644 --- a/ts/sbd-server/src/index.ts +++ b/ts/sbd-server/src/index.ts @@ -1,4 +1,5 @@ import { DurableObject } from 'cloudflare:workers'; +import { Prom } from './prom.ts'; import { RateLimit, RateLimitResult } from './rate-limit.ts'; import { err } from './err.ts'; import { ed } from './ed.ts'; @@ -44,10 +45,18 @@ const MAX_MESSAGE_BYTES = 20000; * Cloudflare worker environment objects. */ export interface Env { + SBD_COORDINATION: KVNamespace; SIGNAL: DurableObjectNamespace; RATE_LIMIT: DurableObjectNamespace; } +/** + * Seconds since epoch timestamp. + */ +function timestamp(): number { + return (Date.now() / 1000) | 0; +} + /** * Pull pubKey string and bytes from the url path. */ @@ -94,6 +103,56 @@ export default { throw err('expected GET', 400); } + let pathParts = url.pathname.split('/') + + if (pathParts.length === 4 && pathParts[1] === 'metrics') { + if (env['METRICS_API_' + pathParts[2]] !== pathParts[3]) { + throw err('bad metrics api key', 400); + } + + const p = new Prom(); + + let res = await env.SBD_COORDINATION.list({ prefix: 'client' }); + + let count = 0; + + while (true) { + for (const item of res.keys) { + if ('name' in item) { + count += 1; + + const opened = item.metadata.opened || 0; + const active = item.metadata.active || 0; + const ip = item.metadata.ip || 'no-ip'; + const activeBytesReceived = item.metadata.activeBytesReceived || 0; + p.guage( + false, + 'client.recv.byte.count', + 'bytes received from client', + { name: item.name.split(':')[1], opened, active, ip }, + activeBytesReceived + ); + } + } + + if (res.list_complete) { + break; + } + + res = await env.SBD_COORDINATION.list({ prefix: 'client', cursor: res.cursor }); + } + + p.guage( + true, + 'client.count', + 'active client count', + {}, + count + ); + + return new Response(await p.render()); + } + const { pubKeyStr } = parsePubKey(url.pathname); const ipId = env.RATE_LIMIT.idFromName(ip); @@ -156,6 +215,9 @@ export class DoSignal extends DurableObject { queue: { [index: string]: Array }; alarmLock: boolean; curLimit: number; + active: number; + lastCoord: number; + activeBytesReceived: number; constructor(ctx: DurableObjectState, env: Env) { super(ctx, env); @@ -164,6 +226,9 @@ export class DoSignal extends DurableObject { this.queue = {}; this.alarmLock = false; this.curLimit = 0; + this.active = timestamp(); + this.lastCoord = timestamp(); + this.activeBytesReceived = 0; } /** @@ -209,11 +274,14 @@ export class DoSignal extends DurableObject { const nonce = new Uint8Array(32); crypto.getRandomValues(nonce); + const opened = timestamp(); + server.serializeAttachment({ pubKey: pubKeyBytes, ip, nonce, valid: false, + opened, }); // this will also send MsgLbrt @@ -225,6 +293,8 @@ export class DoSignal extends DurableObject { console.log( 'webSocketOpen', JSON.stringify({ + opened, + active: this.active, pubKey: pubKeyStr, ip, nonce: toB64Url(nonce), @@ -277,7 +347,7 @@ export class DoSignal extends DurableObject { async webSocketMessage(ws: WebSocket, message: ArrayBuffer | string) { await this.ctx.blockConcurrencyWhile(async () => { try { - const { pubKey, ip, nonce, valid } = ws.deserializeAttachment(); + const { pubKey, ip, nonce, valid, opened } = ws.deserializeAttachment(); if (!pubKey) { throw err('no associated pubKey'); } @@ -294,12 +364,15 @@ export class DoSignal extends DurableObject { msgRaw = enc.encode(message); } + this.activeBytesReceived += msgRaw.byteLength; await this.ipRateLimit(ip, pubKey, msgRaw.byteLength, ws); if (msgRaw.byteLength > MAX_MESSAGE_BYTES) { throw err('max message length exceeded', 400); } + const pubKeyStr = toB64Url(pubKey); + const msg = Msg.parse(msgRaw); if (!valid) { @@ -319,12 +392,22 @@ export class DoSignal extends DurableObject { ip, nonce: true, // don't need to keep the actual nonce anymore valid: true, + opened }); console.log( 'webSocketAuthenticated', - JSON.stringify({ pubKey: toB64Url(pubKey) }), + JSON.stringify({ opened, active: this.active, pubKey: pubKeyStr }), + ); + + const metadata = { opened, active: this.active, activeBytesReceived: this.activeBytesReceived, ip }; + await this.env.SBD_COORDINATION.put( + `client:${pubKeyStr}`, + JSON.stringify(metadata), + { expirationTtl: 60, metadata } ); + + this.lastCoord = timestamp(); } else { if (msg instanceof MsgForward) { throw err(`invalid forward before handshake`); @@ -332,6 +415,15 @@ export class DoSignal extends DurableObject { // otherwise just ignore the message } } else { + if (timestamp() - this.lastCoord >= 30) { + const metadata = { opened, active: this.active, activeBytesReceived: this.activeBytesReceived, ip }; + await this.env.SBD_COORDINATION.put( + `client:${pubKeyStr}`, + JSON.stringify(metadata), + { expirationTtl: 60, metadata } + ); + } + if (msg instanceof MsgNone) { // no-op } else if (msg instanceof MsgKeep) { @@ -429,10 +521,12 @@ export class DoSignal extends DurableObject { reason: string, wasClean: boolean, ) { - const { pubKey, ip, nonce, valid } = ws.deserializeAttachment(); + const { pubKey, ip, nonce, valid, opened } = ws.deserializeAttachment(); console.log( 'webSocketClose', JSON.stringify({ + opened, + active: this.active, pubKey: toB64Url(pubKey), ip, nonce: nonce instanceof Uint8Array ? toB64Url(nonce) : nonce, diff --git a/ts/sbd-server/src/prom.ts b/ts/sbd-server/src/prom.ts new file mode 100644 index 0000000..8c8ee7f --- /dev/null +++ b/ts/sbd-server/src/prom.ts @@ -0,0 +1,46 @@ +function renderLabels(labels: object): string { + const out = ['{']; + let isFirst = true; + for (const key in labels) { + if (isFirst) { + isFirst = false; + } else { + out.push(','); + } + out.push(key); + out.push('='); + out.push(JSON.stringify(labels[key])); + } + if (isFirst) { + return ''; + } + out.push('}'); + return out.join(''); +} + +export class Prom { + #lines: Array; + + constructor() { + this.#lines = []; + } + + + guage(prepend: boolean, name: string, help: string, labels: object, val: number) { + if (prepend) { + this.#lines.unshift(''); + this.#lines.unshift(`${name}${renderLabels(labels)} ${val}`); + this.#lines.unshift(`# TYPE ${name} guage`); + this.#lines.unshift(`# HELP ${name} ${help}`); + } else { + this.#lines.push(`# HELP ${name} ${help}`); + this.#lines.push(`# TYPE ${name} guage`); + this.#lines.push(`${name}${renderLabels(labels)} ${val}`); + this.#lines.push(''); + } + } + + render(): string { + return this.#lines.join('\n'); + } +} diff --git a/ts/sbd-server/wrangler.toml b/ts/sbd-server/wrangler.toml index 5f083a3..95211ac 100644 --- a/ts/sbd-server/wrangler.toml +++ b/ts/sbd-server/wrangler.toml @@ -5,6 +5,10 @@ route = "sbd.holo.host/*" account_id = "18ff2b4e6205b938652998cfca0d8cff" workers_dev = false +kv_namespaces = [ + { binding = "SBD_COORDINATION", id = "cde857dd4ea745fea55f80daa52a6d5c" } +] + [[durable_objects.bindings]] name = "SIGNAL" class_name = "DoSignal" From b081518a9705039e10c50323a232b51f818a3ffb Mon Sep 17 00:00:00 2001 From: neonphog Date: Fri, 12 Jul 2024 15:46:51 -0600 Subject: [PATCH 27/36] new test style --- ts/sbd-server/package-lock.json | 528 +++++++++++++++++++-- ts/sbd-server/package.json | 14 +- ts/sbd-server/src/common.ts | 19 +- ts/sbd-server/src/env.d.ts | 20 + ts/sbd-server/src/index.ts | 3 +- ts/sbd-server/src/rate-limit.test.ts | 111 ----- ts/sbd-server/src/rate-limit.ts | 181 ++++--- ts/sbd-server/src/signal.ts | 5 +- ts/sbd-server/src/test-rate-limit-index.ts | 2 +- ts/sbd-server/src/tsconfig.json | 4 + ts/sbd-server/test/rate-limit.test.ts | 99 ++++ ts/sbd-server/test/tsconfig.json | 11 + ts/sbd-server/tsconfig.json | 6 +- ts/sbd-server/vitest.config.js | 11 + ts/sbd-server/wrangler.toml | 1 + 15 files changed, 767 insertions(+), 248 deletions(-) create mode 100644 ts/sbd-server/src/env.d.ts delete mode 100644 ts/sbd-server/src/rate-limit.test.ts create mode 100644 ts/sbd-server/src/tsconfig.json create mode 100644 ts/sbd-server/test/rate-limit.test.ts create mode 100644 ts/sbd-server/test/tsconfig.json create mode 100644 ts/sbd-server/vitest.config.js diff --git a/ts/sbd-server/package-lock.json b/ts/sbd-server/package-lock.json index 38d3eb6..a042f81 100644 --- a/ts/sbd-server/package-lock.json +++ b/ts/sbd-server/package-lock.json @@ -8,17 +8,18 @@ "name": "sbd-signal", "version": "0.0.0", "dependencies": { - "@noble/ed25519": "^2.1.0", - "@noble/hashes": "^1.4.0", "js-base64": "^3.7.7" }, "devDependencies": { - "@cloudflare/workers-types": "^4.20240620.0", + "@cloudflare/vitest-pool-workers": "^0.4.11", + "@cloudflare/workers-types": "^4.20240712.0", + "@noble/ed25519": "^2.1.0", + "@noble/hashes": "^1.4.0", "node-cleanup": "^2.1.2", "prettier": "^3.3.2", - "typescript": "^5.5.2", - "vitest": "^1.6.0", - "wrangler": "^3.63.1" + "typescript": "^5.5.3", + "vitest": "1.5.0", + "wrangler": "^3.64.0" } }, "node_modules/@cloudflare/kv-asset-handler": { @@ -33,6 +34,416 @@ "node": ">=16.13" } }, + "node_modules/@cloudflare/vitest-pool-workers": { + "version": "0.4.11", + "resolved": "https://registry.npmjs.org/@cloudflare/vitest-pool-workers/-/vitest-pool-workers-0.4.11.tgz", + "integrity": "sha512-AfRvJZ7H5dpPg6qUmJ/DlfwniwLEb6xliqXuDj/WzJsPcsJ5x3/pFMNbqIavB5QW7rygxh4KmiEyptQizmxc1g==", + "dev": true, + "dependencies": { + "birpc": "0.2.14", + "cjs-module-lexer": "^1.2.3", + "devalue": "^4.3.0", + "esbuild": "0.17.19", + "miniflare": "3.20240701.0", + "semver": "^7.5.1", + "wrangler": "3.64.0", + "zod": "^3.22.3" + }, + "peerDependencies": { + "@vitest/runner": "1.3.x - 1.5.x", + "@vitest/snapshot": "1.3.x - 1.5.x", + "vitest": "1.3.x - 1.5.x" + } + }, + "node_modules/@cloudflare/vitest-pool-workers/node_modules/@esbuild/android-arm": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", + "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@cloudflare/vitest-pool-workers/node_modules/@esbuild/android-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", + "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@cloudflare/vitest-pool-workers/node_modules/@esbuild/android-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", + "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@cloudflare/vitest-pool-workers/node_modules/@esbuild/darwin-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", + "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@cloudflare/vitest-pool-workers/node_modules/@esbuild/darwin-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", + "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@cloudflare/vitest-pool-workers/node_modules/@esbuild/freebsd-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", + "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@cloudflare/vitest-pool-workers/node_modules/@esbuild/freebsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", + "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@cloudflare/vitest-pool-workers/node_modules/@esbuild/linux-arm": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", + "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@cloudflare/vitest-pool-workers/node_modules/@esbuild/linux-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", + "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@cloudflare/vitest-pool-workers/node_modules/@esbuild/linux-ia32": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", + "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@cloudflare/vitest-pool-workers/node_modules/@esbuild/linux-loong64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", + "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@cloudflare/vitest-pool-workers/node_modules/@esbuild/linux-mips64el": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", + "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@cloudflare/vitest-pool-workers/node_modules/@esbuild/linux-ppc64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", + "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@cloudflare/vitest-pool-workers/node_modules/@esbuild/linux-riscv64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", + "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@cloudflare/vitest-pool-workers/node_modules/@esbuild/linux-s390x": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", + "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@cloudflare/vitest-pool-workers/node_modules/@esbuild/linux-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", + "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@cloudflare/vitest-pool-workers/node_modules/@esbuild/netbsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", + "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@cloudflare/vitest-pool-workers/node_modules/@esbuild/openbsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", + "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@cloudflare/vitest-pool-workers/node_modules/@esbuild/sunos-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", + "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@cloudflare/vitest-pool-workers/node_modules/@esbuild/win32-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", + "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@cloudflare/vitest-pool-workers/node_modules/@esbuild/win32-ia32": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", + "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@cloudflare/vitest-pool-workers/node_modules/@esbuild/win32-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", + "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@cloudflare/vitest-pool-workers/node_modules/esbuild": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz", + "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.17.19", + "@esbuild/android-arm64": "0.17.19", + "@esbuild/android-x64": "0.17.19", + "@esbuild/darwin-arm64": "0.17.19", + "@esbuild/darwin-x64": "0.17.19", + "@esbuild/freebsd-arm64": "0.17.19", + "@esbuild/freebsd-x64": "0.17.19", + "@esbuild/linux-arm": "0.17.19", + "@esbuild/linux-arm64": "0.17.19", + "@esbuild/linux-ia32": "0.17.19", + "@esbuild/linux-loong64": "0.17.19", + "@esbuild/linux-mips64el": "0.17.19", + "@esbuild/linux-ppc64": "0.17.19", + "@esbuild/linux-riscv64": "0.17.19", + "@esbuild/linux-s390x": "0.17.19", + "@esbuild/linux-x64": "0.17.19", + "@esbuild/netbsd-x64": "0.17.19", + "@esbuild/openbsd-x64": "0.17.19", + "@esbuild/sunos-x64": "0.17.19", + "@esbuild/win32-arm64": "0.17.19", + "@esbuild/win32-ia32": "0.17.19", + "@esbuild/win32-x64": "0.17.19" + } + }, "node_modules/@cloudflare/workerd-darwin-64": { "version": "1.20240701.0", "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20240701.0.tgz", @@ -114,9 +525,9 @@ } }, "node_modules/@cloudflare/workers-types": { - "version": "4.20240701.0", - "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20240701.0.tgz", - "integrity": "sha512-6Cu6NIAicmb8H6CkzFdQG5Ib+TDs9HU8AKQEGlxnbvEBDmhUNpmL30ETXpLS0asdeyc+rTb2xag0hSv0Z1BflQ==", + "version": "4.20240712.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20240712.0.tgz", + "integrity": "sha512-C+C0ZnkRrxR2tPkZKAXwBsWEse7bWaA7iMbaG6IKaxaPTo/5ilx7Ei3BkI2izxmOJMsC05VS1eFUf95urXzhmw==", "dev": true }, "node_modules/@cspotcode/source-map-support": { @@ -571,6 +982,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/@noble/ed25519/-/ed25519-2.1.0.tgz", "integrity": "sha512-KM4qTyXPinyCgMzeYJH/UudpdL+paJXtY3CHtHYZQtBkS8MZoPr4rOikZllIutJe0d06QDQKisyn02gxZ8TcQA==", + "dev": true, "funding": { "url": "https://paulmillr.com/funding/" } @@ -579,6 +991,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "dev": true, "engines": { "node": ">= 16" }, @@ -825,13 +1238,13 @@ } }, "node_modules/@vitest/expect": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.6.0.tgz", - "integrity": "sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.5.0.tgz", + "integrity": "sha512-0pzuCI6KYi2SIC3LQezmxujU9RK/vwC1U9R0rLuGlNGcOuDWxqWKu6nUdFsX9tH1WU0SXtAxToOsEjeUn1s3hA==", "dev": true, "dependencies": { - "@vitest/spy": "1.6.0", - "@vitest/utils": "1.6.0", + "@vitest/spy": "1.5.0", + "@vitest/utils": "1.5.0", "chai": "^4.3.10" }, "funding": { @@ -839,12 +1252,12 @@ } }, "node_modules/@vitest/runner": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.6.0.tgz", - "integrity": "sha512-P4xgwPjwesuBiHisAVz/LSSZtDjOTPYZVmNAnpHHSR6ONrf8eCJOFRvUwdHn30F5M1fxhqtl7QZQUk2dprIXAg==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.5.0.tgz", + "integrity": "sha512-7HWwdxXP5yDoe7DTpbif9l6ZmDwCzcSIK38kTSIt6CFEpMjX4EpCgT6wUmS0xTXqMI6E/ONmfgRKmaujpabjZQ==", "dev": true, "dependencies": { - "@vitest/utils": "1.6.0", + "@vitest/utils": "1.5.0", "p-limit": "^5.0.0", "pathe": "^1.1.1" }, @@ -853,9 +1266,9 @@ } }, "node_modules/@vitest/snapshot": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.6.0.tgz", - "integrity": "sha512-+Hx43f8Chus+DCmygqqfetcAZrDJwvTj0ymqjQq4CvmpKFSTVteEOBzCusu1x2tt4OJcvBflyHUE0DZSLgEMtQ==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.5.0.tgz", + "integrity": "sha512-qpv3fSEuNrhAO3FpH6YYRdaECnnRjg9VxbhdtPwPRnzSfHVXnNzzrpX4cJxqiwgRMo7uRMWDFBlsBq4Cr+rO3A==", "dev": true, "dependencies": { "magic-string": "^0.30.5", @@ -867,9 +1280,9 @@ } }, "node_modules/@vitest/spy": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.6.0.tgz", - "integrity": "sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.5.0.tgz", + "integrity": "sha512-vu6vi6ew5N5MMHJjD5PoakMRKYdmIrNJmyfkhRpQt5d9Ewhw9nZ5Aqynbi3N61bvk9UvZ5UysMT6ayIrZ8GA9w==", "dev": true, "dependencies": { "tinyspy": "^2.2.0" @@ -879,9 +1292,9 @@ } }, "node_modules/@vitest/utils": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.6.0.tgz", - "integrity": "sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.5.0.tgz", + "integrity": "sha512-BDU0GNL8MWkRkSRdNFvCUCAVOeHaUlVJ9Tx0TYBZyXaaOTmGtUFObzchCivIBrIwKzvZA7A9sCejVhXM2aY98A==", "dev": true, "dependencies": { "diff-sequences": "^29.6.3", @@ -972,6 +1385,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/birpc": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/birpc/-/birpc-0.2.14.tgz", + "integrity": "sha512-37FHE8rqsYM5JEKCnXFyHpBCzvgHEExwVVTq+nUmloInU7l8ezD1TpOhKpS8oe1DTYFqEK27rFZVKG43oTqXRA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, "node_modules/blake3-wasm": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/blake3-wasm/-/blake3-wasm-2.1.5.tgz", @@ -1063,6 +1485,12 @@ "fsevents": "~2.3.2" } }, + "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 + }, "node_modules/confbox": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.7.tgz", @@ -1152,6 +1580,12 @@ "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", "dev": true }, + "node_modules/devalue": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/devalue/-/devalue-4.3.3.tgz", + "integrity": "sha512-UH8EL6H2ifcY8TbD2QsxwCC/pr5xSwPvv85LrLXVihmHVC3T3YqTCIwnR5ak0yO1KYqlxrPVOA/JVZJYPy2ATg==", + "dev": true + }, "node_modules/diff-sequences": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", @@ -1939,6 +2373,18 @@ "node": ">=10" } }, + "node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -2230,9 +2676,9 @@ } }, "node_modules/vite-node": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.6.0.tgz", - "integrity": "sha512-de6HJgzC+TFzOu0NTC4RAIsyf/DY/ibWDYQUcuEA84EMHhcefTUGkjFHKKEJhQN4A+6I0u++kr3l36ZF2d7XRw==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.5.0.tgz", + "integrity": "sha512-tV8h6gMj6vPzVCa7l+VGq9lwoJjW8Y79vst8QZZGiuRAfijU+EEWuc0kFpmndQrWhMMhet1jdSF+40KSZUqIIw==", "dev": true, "dependencies": { "cac": "^6.7.14", @@ -2252,16 +2698,16 @@ } }, "node_modules/vitest": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.6.0.tgz", - "integrity": "sha512-H5r/dN06swuFnzNFhq/dnz37bPXnq8xB2xB5JOVk8K09rUtoeNN+LHWkoQ0A/i3hvbUKKcCei9KpbxqHMLhLLA==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.5.0.tgz", + "integrity": "sha512-d8UKgR0m2kjdxDWX6911uwxout6GHS0XaGH1cksSIVVG8kRlE7G7aBw7myKQCvDI5dT4j7ZMa+l706BIORMDLw==", "dev": true, "dependencies": { - "@vitest/expect": "1.6.0", - "@vitest/runner": "1.6.0", - "@vitest/snapshot": "1.6.0", - "@vitest/spy": "1.6.0", - "@vitest/utils": "1.6.0", + "@vitest/expect": "1.5.0", + "@vitest/runner": "1.5.0", + "@vitest/snapshot": "1.5.0", + "@vitest/spy": "1.5.0", + "@vitest/utils": "1.5.0", "acorn-walk": "^8.3.2", "chai": "^4.3.10", "debug": "^4.3.4", @@ -2275,7 +2721,7 @@ "tinybench": "^2.5.1", "tinypool": "^0.8.3", "vite": "^5.0.0", - "vite-node": "1.6.0", + "vite-node": "1.5.0", "why-is-node-running": "^2.2.2" }, "bin": { @@ -2290,8 +2736,8 @@ "peerDependencies": { "@edge-runtime/vm": "*", "@types/node": "^18.0.0 || >=20.0.0", - "@vitest/browser": "1.6.0", - "@vitest/ui": "1.6.0", + "@vitest/browser": "1.5.0", + "@vitest/ui": "1.5.0", "happy-dom": "*", "jsdom": "*" }, diff --git a/ts/sbd-server/package.json b/ts/sbd-server/package.json index c619b80..b3857b2 100644 --- a/ts/sbd-server/package.json +++ b/ts/sbd-server/package.json @@ -2,22 +2,24 @@ "name": "sbd-signal", "version": "0.0.0", "private": true, + "type": "module", "scripts": { "deploy": "wrangler deploy", "dev": "wrangler dev", "start": "wrangler dev", - "test:fmt": "prettier -w src", - "test:type": "tsc --noEmit", + "test:fmt": "prettier -w src test", + "test:type": "tsc --noEmit --project ./src/tsconfig.json", "test:unit": "vitest run", "test": "npm run test:fmt && npm run test:type && npm run test:unit" }, "devDependencies": { - "@cloudflare/workers-types": "^4.20240620.0", + "@cloudflare/vitest-pool-workers": "^0.4.11", + "@cloudflare/workers-types": "^4.20240712.0", "node-cleanup": "^2.1.2", "prettier": "^3.3.2", - "typescript": "^5.5.2", - "vitest": "^1.6.0", - "wrangler": "^3.63.1" + "typescript": "^5.5.3", + "vitest": "1.5.0", + "wrangler": "^3.64.0" }, "dependencies": { "@noble/ed25519": "^2.1.0", diff --git a/ts/sbd-server/src/common.ts b/ts/sbd-server/src/common.ts index c5ebe3c..6b21560 100644 --- a/ts/sbd-server/src/common.ts +++ b/ts/sbd-server/src/common.ts @@ -19,6 +19,11 @@ export const BATCH_DUR_MS = 0; */ export const LIMIT_NANOS_PER_BYTE = 8000; +/** + * How many nanoseconds of rate limiting burst graceperiod is allowed + */ +export const LIMIT_NANOS_BURST = LIMIT_NANOS_PER_BYTE * 16 * 16 * 1024; + /** * Milliseconds connections are allowed to remain idle before being closed. */ @@ -29,26 +34,28 @@ export const LIMIT_IDLE_MILLIS = 10000; */ export const MAX_MESSAGE_BYTES = 20000; -/** +/* +/ ** * Cloudflare worker environment objects. - */ + * / export interface EnvExplicit { SBD_COORDINATION: KVNamespace; SIGNAL: DurableObjectNamespace; RATE_LIMIT: DurableObjectNamespace; } -/** +/ ** * Cloudflare worker environment variables. - */ + * / export interface EnvVars { [index: string]: string; } -/** +/ ** * Combined Cloudflare Env type. - */ + * / export type Env = EnvExplicit & EnvVars; +*/ /** * Mixin to allow errors with status codes. diff --git a/ts/sbd-server/src/env.d.ts b/ts/sbd-server/src/env.d.ts new file mode 100644 index 0000000..692a6ab --- /dev/null +++ b/ts/sbd-server/src/env.d.ts @@ -0,0 +1,20 @@ +/** + * Cloudflare worker environment objects. + */ +interface EnvExplicit { + SBD_COORDINATION: KVNamespace; + SIGNAL: DurableObjectNamespace; + RATE_LIMIT: DurableObjectNamespace; +} + +/** + * Cloudflare worker environment variables. + */ +interface EnvVars { + [index: string]: string; +} + +/** + * Combined Cloudflare Env type. + */ +type Env = EnvExplicit & EnvVars; diff --git a/ts/sbd-server/src/index.ts b/ts/sbd-server/src/index.ts index 790b56f..1283276 100644 --- a/ts/sbd-server/src/index.ts +++ b/ts/sbd-server/src/index.ts @@ -17,7 +17,7 @@ export { DoSignal }; export default { async fetch( request: Request, - env: common.Env, + env: Env, ctx: ExecutionContext, ): Promise { try { @@ -120,6 +120,7 @@ export default { const ipStub = env.RATE_LIMIT.get(ipId) as DurableObjectStub; const { shouldBlock } = await ipStub.bytesReceived( Date.now(), + ip, pubKeyStr, 1, ); diff --git a/ts/sbd-server/src/rate-limit.test.ts b/ts/sbd-server/src/rate-limit.test.ts deleted file mode 100644 index 7832b74..0000000 --- a/ts/sbd-server/src/rate-limit.test.ts +++ /dev/null @@ -1,111 +0,0 @@ -import { unstable_dev } from 'wrangler'; -import type { UnstableDevWorker } from 'wrangler'; -import { describe, expect, assert, it, beforeEach, afterEach } from 'vitest'; -import { RateLimit } from './rate-limit.ts'; - -describe('RateLimit', () => { - let worker: UnstableDevWorker; - - beforeEach(async () => { - worker = await unstable_dev('./src/test-rate-limit-index.ts', { - experimental: { disableExperimentalWarning: true }, - }); - }); - - afterEach(async () => { - await worker.stop(); - }); - - it('sanity', async () => {}); - - /* - it('check multi-node rate limit', async () => { - const addr1 = 'yada1'; - const addr2 = 'yada2'; - - let now = 100; - - const rate = new RateLimit(8000, 16 * 16 * 1024); - - let limitNanosPerByte = null; - - ({ limitNanosPerByte } = rate.bytesReceived(now, addr1, 1)); - - expect(limitNanosPerByte).equals(8000); - - ({ limitNanosPerByte } = rate.bytesReceived(now, addr2, 1)); - - expect(limitNanosPerByte).equals(16000); - - now += 20000; - - ({ limitNanosPerByte } = rate.bytesReceived(now, addr2, 1)); - expect(limitNanosPerByte).equals(8000); - }); - - it('1 to 1 and prune', async () => { - const addr = 'yada'; - - let now = 100n; - let shouldBlock = null; - - const rate = new RateLimit(1, 1); - - // should always be ok when advancing with time - for (let i = 0; i < 10; ++i) { - now += 1n; - - ({ shouldBlock } = rate.bytesReceived(now, addr, 1)); - - assert(!shouldBlock); - } - - // but one more without a time advance fails - ({ shouldBlock } = rate.bytesReceived(now, addr, 1)); - assert(shouldBlock); - - now += 1n; - - // make sure prune doesn't prune it yet - rate.prune(now); - ({ shouldBlock } = rate.bytesReceived(now, addr, 1)); - assert(shouldBlock); - - now += 1n; - - // make sure prune doesn't prune it even after 10 seconds - rate.prune(now + 10000000000n); - ({ shouldBlock } = rate.bytesReceived(now, addr, 1)); - assert(shouldBlock); - - now += 1n; - - // but it *will* after 10 seconds + 1 nanosecond - rate.prune(now + 10000000001n); - ({ shouldBlock } = rate.bytesReceived(now, addr, 1)); - assert(!shouldBlock); - }); - - it('burst', async () => { - const addr = 'yada'; - - let now = 100n; - let shouldBlock = null; - - const rate = new RateLimit(1, 5); - - for (let i = 0; i < 5; ++i) { - ({ shouldBlock } = rate.bytesReceived(now, addr, 1)); - assert(!shouldBlock); - } - - ({ shouldBlock } = rate.bytesReceived(now, addr, 1)); - assert(shouldBlock); - - now += 2n; - - ({ shouldBlock } = rate.bytesReceived(now, addr, 1)); - assert(!shouldBlock); - }); - */ -}); diff --git a/ts/sbd-server/src/rate-limit.ts b/ts/sbd-server/src/rate-limit.ts index 5a718ce..7d175ae 100644 --- a/ts/sbd-server/src/rate-limit.ts +++ b/ts/sbd-server/src/rate-limit.ts @@ -17,52 +17,79 @@ export interface RateLimitResult { shouldBlock: boolean; } -/** - * If a classic number, milliseconds since epoch. - * If a bigint, nanoseconds since epoch. - */ -function nowNanos(now: number | bigint): bigint { - if (typeof now === 'bigint') { - return now; - } else { - const tmp: bigint = BigInt(now); - return tmp * 1000000n; - } +interface State { + map: { [pk: string]: bigint }; + next: bigint; } +enum BlockCheck { + Unchecked, + Unblocked, + Blocked, +} + +const BLOCKED: RateLimitResult = { + limitNanosPerByte: Number.MAX_SAFE_INTEGER, + shouldBlock: true, +}; + /** - * Ratelimit potentially multiple clients coming from the same ip address. + * "RATE_LIMIT" durable object. + * This is a thin wrapper around the "RateLimit" class. */ -export class RateLimit { - map: { [pk: string]: bigint }; - limitNanosPerByte: bigint; - burst: bigint; +export class DoRateLimit extends DurableObject { + ctx: DurableObjectState; + env: Env; + lastUnblockCheck: number; + blockCheck: BlockCheck; + state: State; - constructor(limitNanosPerByte: number, burst: number) { - this.map = {}; - this.limitNanosPerByte = BigInt(limitNanosPerByte); - this.burst = this.limitNanosPerByte * BigInt(burst); + constructor(ctx: DurableObjectState, env: Env) { + super(ctx, env); + + this.ctx = ctx; + this.env = env; + + this.lastUnblockCheck = 0; + this.blockCheck = BlockCheck.Unchecked; + + // Note, we're making an explicit decision to NOT store this state + // in either the DO transactional storage or KV store. + // It would cost a lot to keep it updated enough to be useful, + // and we are doing our own memory eviction after 10 seconds anyways. + // Assuming we are not evicted within 10 seconds (docs are vague), + // this will work as well as trying to store it anywhere. + this.state = { map: {}, next: 0n }; } /** - * Clear out any connections older that 10s in the past. - * - * - now: if now is a number, it is milliseconds since epoch - * if now is a bigint, it is nanoseconds since epoch + * Update block state from KV for this IP if it is correct to do so. */ - prune(now: number | bigint) { - const nowNs = nowNanos(now); - - const newMap: { [pk: string]: bigint } = {}; - - for (const pk in this.map) { - const cur = this.map[pk]; - if (nowNs <= cur || nowNs - cur < 10000000000n) { - newMap[pk] = cur; + async checkBlockState(ip: string) { + if (this.blockCheck === BlockCheck.Unblocked) { + // do not check the KV if we are currently unblocked + return; + } else if (this.blockCheck === BlockCheck.Blocked) { + if (Date.now() - this.lastUnblockCheck < 1000 * 60 * 2) { + // if we are blocked, and have checked within the past 2 minutes + // don't bother checking again + return; } + this.lastUnblockCheck = Date.now(); } - this.map = newMap; + // if we made it past the above checks, go ahead and check the kv + const block = await this.env.SBD_COORDINATION.get(`block:${ip}`, { + type: 'json', + }); + + // if we get a `true` back from the kv, mark blocked + // otherwise mark unblocked + if (typeof block === 'boolean' && block) { + this.blockCheck = BlockCheck.Blocked; + } else { + this.blockCheck = BlockCheck.Unblocked; + } } /** @@ -70,66 +97,64 @@ export class RateLimit { * Return a bitrate limit this connection should be following, and * whether that ip has already breached the limit. * - * - now: if now is a number, it is milliseconds since epoch - * if now is a bigint, it is nanoseconds since epoch + * - now: milliseconds since epoch */ - bytesReceived( - now: number | bigint, + async bytesReceived( + now: number, + ip: string, pk: string, bytes: number, - ): RateLimitResult { - this.prune(now); + ): Promise { + return await this.ctx.blockConcurrencyWhile(async () => { + await this.checkBlockState(ip); - const nowNs = nowNanos(now); + if (this.blockCheck === BlockCheck.Blocked) { + return BLOCKED; + } - const rateAdd = BigInt(bytes) * this.limitNanosPerByte; + const nowN = BigInt(now) * 1000000n; - if (!(pk in this.map)) { - this.map[pk] = nowNs; - } + // prune the map - let cur = this.map[pk]; + const newMap: { [pk: string]: bigint } = {}; - if (nowNs > cur) { - cur = nowNs; - } + for (const pk in this.state.map) { + const last = this.state.map[pk]; + // keep if it is newer than 10 seconds + if (last >= nowN - 10000000000n) { + newMap[pk] = last; + } + } - cur += rateAdd; + this.state.map = newMap; - this.map[pk] = cur; + // log the pk last access time - const nextActionInNanos = cur - nowNs; + this.state.map[pk] = nowN; - const shouldBlock = nextActionInNanos > this.burst; + // log the additional bytes - const nodeCount: bigint = BigInt(Object.keys(this.map).length); - const limitNanosPerByte = Number(this.limitNanosPerByte * nodeCount); + if (this.state.next < nowN) { + this.state.next = nowN; + } - return { limitNanosPerByte, shouldBlock }; - } -} + const rateAdd = BigInt(bytes) * BigInt(common.LIMIT_NANOS_PER_BYTE); -/** - * "RATE_LIMIT" durable object. - * This is a thin wrapper around the "RateLimit" class. - */ -export class DoRateLimit extends DurableObject { - ctx: DurableObjectState; - env: common.Env; - rl: RateLimit; + this.state.next += rateAdd; - constructor(ctx: DurableObjectState, env: common.Env) { - super(ctx, env); - this.ctx = ctx; - this.env = env; - this.rl = new RateLimit(common.LIMIT_NANOS_PER_BYTE, 16 * 16 * 1024); - } + const shouldBlock = this.state.next - nowN > common.LIMIT_NANOS_BURST; + const limitNanosPerByte = + common.LIMIT_NANOS_PER_BYTE * Object.keys(this.state.map).length; - async bytesReceived( - now: number, - pk: string, - bytes: number, - ): Promise { - return this.rl.bytesReceived(now, pk, bytes); + if (shouldBlock) { + this.blockCheck = BlockCheck.Blocked; + await this.env.SBD_COORDINATION.put(`block:${ip}`, 'true', { + expirationTtl: 60 * 10, + }); + return BLOCKED; + } + + return { limitNanosPerByte, shouldBlock }; + }); } } diff --git a/ts/sbd-server/src/signal.ts b/ts/sbd-server/src/signal.ts index 94f689d..a416ce9 100644 --- a/ts/sbd-server/src/signal.ts +++ b/ts/sbd-server/src/signal.ts @@ -20,7 +20,7 @@ import { */ export class DoSignal extends DurableObject { ctx: DurableObjectState; - env: common.Env; + env: Env; queue: { [index: string]: Array }; alarmLock: boolean; curLimit: number; @@ -28,7 +28,7 @@ export class DoSignal extends DurableObject { lastCoord: number; activeBytesReceived: number; - constructor(ctx: DurableObjectState, env: common.Env) { + constructor(ctx: DurableObjectState, env: Env) { super(ctx, env); this.ctx = ctx; this.env = env; @@ -134,6 +134,7 @@ export class DoSignal extends DurableObject { ) as DurableObjectStub; const { limitNanosPerByte, shouldBlock } = await ipStub.bytesReceived( Date.now(), + ip, pk, bytes, ); diff --git a/ts/sbd-server/src/test-rate-limit-index.ts b/ts/sbd-server/src/test-rate-limit-index.ts index fabb517..1ff68cf 100644 --- a/ts/sbd-server/src/test-rate-limit-index.ts +++ b/ts/sbd-server/src/test-rate-limit-index.ts @@ -12,7 +12,7 @@ export { DoSignal }; export default { async fetch( request: Request, - env: common.Env, + env: Env, ctx: ExecutionContext, ): Promise { return new Response('bob'); diff --git a/ts/sbd-server/src/tsconfig.json b/ts/sbd-server/src/tsconfig.json new file mode 100644 index 0000000..5197ce2 --- /dev/null +++ b/ts/sbd-server/src/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../tsconfig.json", + "include": ["./**/*.ts"] +} diff --git a/ts/sbd-server/test/rate-limit.test.ts b/ts/sbd-server/test/rate-limit.test.ts new file mode 100644 index 0000000..a0c0721 --- /dev/null +++ b/ts/sbd-server/test/rate-limit.test.ts @@ -0,0 +1,99 @@ +import { + env, + //createExecutionContext, + //waitOnExecutionContext, + runInDurableObject, + //SELF +} from 'cloudflare:test'; +import { describe, it, expect } from 'vitest'; +import { DoRateLimit } from '../src'; + +it('rate-limit sanity', async () => { + const test = '1'; + const ip = `ip${test}`; + const pk = `pk${test}`; + + const id = env.RATE_LIMIT.idFromName(ip); + const stub = env.RATE_LIMIT.get(id); + await runInDurableObject(stub, async (inst: DoRateLimit) => { + const res = await inst.bytesReceived(Date.now(), ip, pk, 1); + expect(res.shouldBlock).equals(false); + }); +}); + +it('rate-limit causes block', async () => { + const test = '2'; + const ip = `ip${test}`; + const pk = `pk${test}`; + + const id = env.RATE_LIMIT.idFromName(ip); + const stub = env.RATE_LIMIT.get(id); + await runInDurableObject(stub, async (inst: DoRateLimit) => { + const res = await inst.bytesReceived( + Date.now(), + ip, + pk, + Number.MAX_SAFE_INTEGER, + ); + expect(res.shouldBlock).equals(true); + }); + + const kvBlock = await env.SBD_COORDINATION.get(`block:${ip}`, { + type: 'json', + }); + expect(kvBlock).equals(true); +}); + +it('rate-limit load checks kv block', async () => { + const test = '3'; + const ip = `ip${test}`; + const pk = `pk${test}`; + + await env.SBD_COORDINATION.put(`block:${ip}`, 'true', { + expirationTtl: 60 * 10, + }); + + const id = env.RATE_LIMIT.idFromName(ip); + const stub = env.RATE_LIMIT.get(id); + await runInDurableObject(stub, async (inst: DoRateLimit) => { + const res = await inst.bytesReceived(Date.now(), ip, pk, 1); + expect(res.shouldBlock).equals(true); + }); +}); + +it('rate-limit slower for multi-con ips', async () => { + const test = '4'; + const ip = `ip${test}`; + + const id = env.RATE_LIMIT.idFromName(ip); + const stub = env.RATE_LIMIT.get(id); + + const rate1 = await runInDurableObject(stub, async (inst: DoRateLimit) => { + const res = await inst.bytesReceived(Date.now(), ip, 'pkA', 1); + return res.limitNanosPerByte; + }); + + const rate2 = await runInDurableObject(stub, async (inst: DoRateLimit) => { + const res = await inst.bytesReceived(Date.now(), ip, 'pkB', 1); + return res.limitNanosPerByte; + }); + + expect(rate2).equals(rate1 * 2); + + const rate3 = await runInDurableObject(stub, async (inst: DoRateLimit) => { + const res = await inst.bytesReceived(Date.now(), ip, 'pkC', 1); + return res.limitNanosPerByte; + }); + + expect(rate3).equals(rate1 * 3); + + const rate1Again = await runInDurableObject( + stub, + async (inst: DoRateLimit) => { + const res = await inst.bytesReceived(Date.now(), ip, 'pkA', 1); + return res.limitNanosPerByte; + }, + ); + + expect(rate1Again).equals(rate3); +}); diff --git a/ts/sbd-server/test/tsconfig.json b/ts/sbd-server/test/tsconfig.json new file mode 100644 index 0000000..21fc1b6 --- /dev/null +++ b/ts/sbd-server/test/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "moduleResolution": "bundler", + "types": [ + "@cloudflare/workers-types/experimental", + "@cloudflare/vitest-pool-workers" + ] + }, + "include": ["./**/*.ts", "../src/env.d.ts"] +} diff --git a/ts/sbd-server/tsconfig.json b/ts/sbd-server/tsconfig.json index 38f988f..9edf8ed 100644 --- a/ts/sbd-server/tsconfig.json +++ b/ts/sbd-server/tsconfig.json @@ -5,7 +5,8 @@ "module": "es2022", "moduleResolution": "node", "types": [ - "@cloudflare/workers-types/2023-07-01" + "@cloudflare/workers-types/2023-07-01", + "@cloudflare/vitest-pool-workers" ], "resolveJsonModule": true, "allowImportingTsExtensions": true, @@ -17,5 +18,6 @@ "forceConsistentCasingInFileNames": true, "strict": true, "skipLibCheck": true - } + }, + "include": ["./*.ts"] } diff --git a/ts/sbd-server/vitest.config.js b/ts/sbd-server/vitest.config.js new file mode 100644 index 0000000..973627c --- /dev/null +++ b/ts/sbd-server/vitest.config.js @@ -0,0 +1,11 @@ +import { defineWorkersConfig } from "@cloudflare/vitest-pool-workers/config"; + +export default defineWorkersConfig({ + test: { + poolOptions: { + workers: { + wrangler: { configPath: "./wrangler.toml" }, + }, + }, + }, +}); diff --git a/ts/sbd-server/wrangler.toml b/ts/sbd-server/wrangler.toml index 7bc543f..d645952 100644 --- a/ts/sbd-server/wrangler.toml +++ b/ts/sbd-server/wrangler.toml @@ -1,6 +1,7 @@ name = "sbd" main = "src/index.ts" compatibility_date = "2024-06-03" +compatibility_flags = [ "nodejs_compat" ] route = "sbd.holo.host/*" account_id = "18ff2b4e6205b938652998cfca0d8cff" minify = true From ebefd7702b8a92c57aa968dcec0ebbf7f3c52c3a Mon Sep 17 00:00:00 2001 From: neonphog Date: Fri, 12 Jul 2024 17:02:17 -0600 Subject: [PATCH 28/36] checkpoint --- ts/sbd-server/package-lock.json | 6 ++---- ts/sbd-server/src/test-rate-limit-index.ts | 20 -------------------- 2 files changed, 2 insertions(+), 24 deletions(-) delete mode 100644 ts/sbd-server/src/test-rate-limit-index.ts diff --git a/ts/sbd-server/package-lock.json b/ts/sbd-server/package-lock.json index a042f81..9e7df03 100644 --- a/ts/sbd-server/package-lock.json +++ b/ts/sbd-server/package-lock.json @@ -8,13 +8,13 @@ "name": "sbd-signal", "version": "0.0.0", "dependencies": { + "@noble/ed25519": "^2.1.0", + "@noble/hashes": "^1.4.0", "js-base64": "^3.7.7" }, "devDependencies": { "@cloudflare/vitest-pool-workers": "^0.4.11", "@cloudflare/workers-types": "^4.20240712.0", - "@noble/ed25519": "^2.1.0", - "@noble/hashes": "^1.4.0", "node-cleanup": "^2.1.2", "prettier": "^3.3.2", "typescript": "^5.5.3", @@ -982,7 +982,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/@noble/ed25519/-/ed25519-2.1.0.tgz", "integrity": "sha512-KM4qTyXPinyCgMzeYJH/UudpdL+paJXtY3CHtHYZQtBkS8MZoPr4rOikZllIutJe0d06QDQKisyn02gxZ8TcQA==", - "dev": true, "funding": { "url": "https://paulmillr.com/funding/" } @@ -991,7 +990,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", - "dev": true, "engines": { "node": ">= 16" }, diff --git a/ts/sbd-server/src/test-rate-limit-index.ts b/ts/sbd-server/src/test-rate-limit-index.ts deleted file mode 100644 index 1ff68cf..0000000 --- a/ts/sbd-server/src/test-rate-limit-index.ts +++ /dev/null @@ -1,20 +0,0 @@ -// THIS IS A FAKE index.ts to be used for unit testing the -// DoRateLimit durable object. - -import * as common from './common.ts'; - -import { DoRateLimit } from './rate-limit.ts'; -export { DoRateLimit }; - -import { DoSignal } from './signal.ts'; -export { DoSignal }; - -export default { - async fetch( - request: Request, - env: Env, - ctx: ExecutionContext, - ): Promise { - return new Response('bob'); - }, -}; From 1429022abd7bdc1a6d4808b7bb2287dee4253b6b Mon Sep 17 00:00:00 2001 From: neonphog Date: Mon, 15 Jul 2024 14:17:30 -0600 Subject: [PATCH 29/36] add dead state tracking to signal DO --- ts/sbd-server/src/signal.ts | 49 ++++++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/ts/sbd-server/src/signal.ts b/ts/sbd-server/src/signal.ts index a416ce9..0e81553 100644 --- a/ts/sbd-server/src/signal.ts +++ b/ts/sbd-server/src/signal.ts @@ -27,6 +27,7 @@ export class DoSignal extends DurableObject { active: number; lastCoord: number; activeBytesReceived: number; + status: number; constructor(ctx: DurableObjectState, env: Env) { super(ctx, env); @@ -38,6 +39,7 @@ export class DoSignal extends DurableObject { this.active = common.timestamp(); this.lastCoord = common.timestamp(); this.activeBytesReceived = 0; + this.status = 200; } /** @@ -47,9 +49,25 @@ export class DoSignal extends DurableObject { * This is the api for those messages to be forwarded. */ async forward(messageList: Array) { + if (this.status !== 200) { + return; + } + + // MAYBE: buffer messages until handshake complete? + // might not be needed since clients shouldn't publish the address + // until handshake is complete + + // This loop not technically needed, since our fetch ensures there + // is only ever one websocket connected. for (const ws of this.ctx.getWebSockets()) { for (const message of messageList) { - ws.send(message); + try { + ws.send(message); + } catch (e: any) { + console.error('forward error', e); + this.status = 500; + return; + } } } } @@ -61,6 +79,12 @@ export class DoSignal extends DurableObject { * to a websocket. */ async fetch(request: Request): Promise { + if (this.status !== 200) { + return new Response(JSON.stringify({ err: 'dead' }), { + status: this.status, + }); + } + let cleanServer = null; try { const ip = request.headers.get('cf-connecting-ip') || 'no-ip'; @@ -112,8 +136,15 @@ export class DoSignal extends DurableObject { return new Response(null, { status: 101, webSocket: client }); } catch (e: any) { + // Note: one might be tempted to set this.status here, but then bad + // actors could maliciously drop other peer connections just + // by trying (and failing) to connect to them. + console.error('error', e.toString()); if (cleanServer) { + // Note: HERE it's okay to set this.status, since we know we're + // the original connecting websocket. + this.status = e.status || 500; cleanServer.close(4000 + (e.status || 500), e.toString()); } return new Response(JSON.stringify({ err: e.toString() }), { @@ -155,6 +186,11 @@ export class DoSignal extends DurableObject { * First handshake the connection, then start handling forwarding messages. */ async webSocketMessage(ws: WebSocket, message: ArrayBuffer | string) { + if (this.status !== 200) { + ws.close(4000 + this.status, 'dead'); + return; + } + await this.ctx.blockConcurrencyWhile(async () => { try { const { pubKey, ip, nonce, valid, opened } = ws.deserializeAttachment(); @@ -214,6 +250,7 @@ export class DoSignal extends DurableObject { }), ); + this.lastCoord = common.timestamp(); const metadata = { op: opened, ac: this.active, @@ -225,8 +262,6 @@ export class DoSignal extends DurableObject { JSON.stringify(metadata), { expirationTtl: 60, metadata }, ); - - this.lastCoord = common.timestamp(); } else { if (msg instanceof MsgForward) { throw common.err(`invalid forward before handshake`); @@ -235,6 +270,7 @@ export class DoSignal extends DurableObject { } } else { if (common.timestamp() - this.lastCoord >= 30) { + this.lastCoord = common.timestamp(); const metadata = { op: opened, ac: this.active, @@ -281,7 +317,8 @@ export class DoSignal extends DurableObject { } } catch (e: any) { console.error('error', e.toString()); - ws.close(4000 + (e.status || 500), e.toString()); + this.status = e.status || 500; + ws.close(4000 + this.status, e.toString()); } }); } @@ -293,6 +330,10 @@ export class DoSignal extends DurableObject { * that happened to try to forward messages to each other at the same moment. */ async alarm() { + if (this.status !== 200) { + return; + } + const { shouldReturn, queue } = await this.ctx.blockConcurrencyWhile( async () => { if (this.alarmLock || Object.keys(this.queue).length === 0) { From 37f5c2592f11b9967f887ff9ea45e121441b1adf Mon Sep 17 00:00:00 2001 From: neonphog Date: Mon, 15 Jul 2024 14:21:57 -0600 Subject: [PATCH 30/36] cleanup --- ts/sbd-server/src/common.ts | 23 ----------------------- ts/sbd-server/test/rate-limit.test.ts | 8 +------- 2 files changed, 1 insertion(+), 30 deletions(-) diff --git a/ts/sbd-server/src/common.ts b/ts/sbd-server/src/common.ts index 6b21560..126de58 100644 --- a/ts/sbd-server/src/common.ts +++ b/ts/sbd-server/src/common.ts @@ -34,29 +34,6 @@ export const LIMIT_IDLE_MILLIS = 10000; */ export const MAX_MESSAGE_BYTES = 20000; -/* -/ ** - * Cloudflare worker environment objects. - * / -export interface EnvExplicit { - SBD_COORDINATION: KVNamespace; - SIGNAL: DurableObjectNamespace; - RATE_LIMIT: DurableObjectNamespace; -} - -/ ** - * Cloudflare worker environment variables. - * / -export interface EnvVars { - [index: string]: string; -} - -/ ** - * Combined Cloudflare Env type. - * / -export type Env = EnvExplicit & EnvVars; -*/ - /** * Mixin to allow errors with status codes. */ diff --git a/ts/sbd-server/test/rate-limit.test.ts b/ts/sbd-server/test/rate-limit.test.ts index a0c0721..14f51a2 100644 --- a/ts/sbd-server/test/rate-limit.test.ts +++ b/ts/sbd-server/test/rate-limit.test.ts @@ -1,10 +1,4 @@ -import { - env, - //createExecutionContext, - //waitOnExecutionContext, - runInDurableObject, - //SELF -} from 'cloudflare:test'; +import { env, runInDurableObject } from 'cloudflare:test'; import { describe, it, expect } from 'vitest'; import { DoRateLimit } from '../src'; From 68fde2c1f15e41f600f531d83c459bb98babe9b7 Mon Sep 17 00:00:00 2001 From: neonphog Date: Mon, 15 Jul 2024 14:29:06 -0600 Subject: [PATCH 31/36] docs --- ts/sbd-server/src/prom.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/ts/sbd-server/src/prom.ts b/ts/sbd-server/src/prom.ts index 517ec54..3a54968 100644 --- a/ts/sbd-server/src/prom.ts +++ b/ts/sbd-server/src/prom.ts @@ -1,3 +1,6 @@ +/** + * Prometheus label rendering helper. + */ function renderLabels(labels: { [index: string]: any }): string { const out = ['{']; let isFirst = true; @@ -18,6 +21,11 @@ function renderLabels(labels: { [index: string]: any }): string { return out.join(''); } +/** + * Hand-rolled simplistic prometheus metrics renderer. + * All the npm modules I could find out there depended on nodejs apis. + * I just need a simple protocol renderer that can be used in cloudflare. + */ export class Prom { #lines: Array; @@ -25,6 +33,9 @@ export class Prom { this.#lines = []; } + /** + * Generate a "guage" item. + */ guage( prepend: boolean, name: string, @@ -45,6 +56,9 @@ export class Prom { } } + /** + * Render the previous generated prometheus line items into a single string. + */ render(): string { return this.#lines.join('\n'); } From 2e42ad6706b76c89bc27ff9aa47ce8b5a2c1553d Mon Sep 17 00:00:00 2001 From: David Braden Date: Thu, 18 Jul 2024 12:32:05 -0600 Subject: [PATCH 32/36] Update ts/sbd-server/src/prom.ts --- ts/sbd-server/src/prom.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ts/sbd-server/src/prom.ts b/ts/sbd-server/src/prom.ts index 3a54968..b3451ba 100644 --- a/ts/sbd-server/src/prom.ts +++ b/ts/sbd-server/src/prom.ts @@ -21,10 +21,11 @@ function renderLabels(labels: { [index: string]: any }): string { return out.join(''); } +// All the npm modules I could find out there depended on nodejs apis. +// I just need a simple protocol renderer that can be used in cloudflare. + /** * Hand-rolled simplistic prometheus metrics renderer. - * All the npm modules I could find out there depended on nodejs apis. - * I just need a simple protocol renderer that can be used in cloudflare. */ export class Prom { #lines: Array; From 022e1373c36998152cc52fcb4a09db1e17301483 Mon Sep 17 00:00:00 2001 From: neonphog Date: Thu, 18 Jul 2024 12:36:09 -0600 Subject: [PATCH 33/36] update --- ts/sbd-server/package-lock.json | 1824 +++++++++++++------------------ 1 file changed, 748 insertions(+), 1076 deletions(-) diff --git a/ts/sbd-server/package-lock.json b/ts/sbd-server/package-lock.json index 9e7df03..2f760da 100644 --- a/ts/sbd-server/package-lock.json +++ b/ts/sbd-server/package-lock.json @@ -35,18 +35,18 @@ } }, "node_modules/@cloudflare/vitest-pool-workers": { - "version": "0.4.11", - "resolved": "https://registry.npmjs.org/@cloudflare/vitest-pool-workers/-/vitest-pool-workers-0.4.11.tgz", - "integrity": "sha512-AfRvJZ7H5dpPg6qUmJ/DlfwniwLEb6xliqXuDj/WzJsPcsJ5x3/pFMNbqIavB5QW7rygxh4KmiEyptQizmxc1g==", + "version": "0.4.12", + "resolved": "https://registry.npmjs.org/@cloudflare/vitest-pool-workers/-/vitest-pool-workers-0.4.12.tgz", + "integrity": "sha512-i+ja4xJKPJv07DF1Q6zRGgRDHCMIJc39T+uXBU8DBaF+bjWPe+e589uTG27jCxVHuBvHxOiOv1KDt99EAZ/mpw==", "dev": true, "dependencies": { "birpc": "0.2.14", "cjs-module-lexer": "^1.2.3", "devalue": "^4.3.0", "esbuild": "0.17.19", - "miniflare": "3.20240701.0", + "miniflare": "3.20240712.0", "semver": "^7.5.1", - "wrangler": "3.64.0", + "wrangler": "3.65.0", "zod": "^3.22.3" }, "peerDependencies": { @@ -55,7 +55,143 @@ "vitest": "1.3.x - 1.5.x" } }, - "node_modules/@cloudflare/vitest-pool-workers/node_modules/@esbuild/android-arm": { + "node_modules/@cloudflare/workerd-darwin-64": { + "version": "1.20240712.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20240712.0.tgz", + "integrity": "sha512-KB1vbOhr62BCAwVr3VaRcngzPeSCQ7zPA9VGrfwYXIxo0Y4zlW1z0EVtcewFSz5XXKr3BtNnJXxdjDPUNkguQw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@cloudflare/workerd-darwin-arm64": { + "version": "1.20240712.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20240712.0.tgz", + "integrity": "sha512-UDwFnCfQGFVCNxOeHxKNEc1ANQk/3OIiFWpVsxgZqJqU/22XM88JHxJW+YcBKsaUGUlpLyImaYUn2/rG+i+9UQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@cloudflare/workerd-linux-64": { + "version": "1.20240712.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20240712.0.tgz", + "integrity": "sha512-MxpMHSJcZRUL66TO7BEnEim9WgZ8wJEVOB1Rq7a/IF2hI4/8f+N+02PChh62NkBlWxDfTXAtZy0tyQMm0EGjHg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@cloudflare/workerd-linux-arm64": { + "version": "1.20240712.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20240712.0.tgz", + "integrity": "sha512-DtLYZsFFFAMgn+6YCHoQS6nYY4nbdAtcAFa4PhWTjLJDbvQEn3IoK9Bi4ajCL7xG36FeuBdZliSbBiiv7CJjfQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@cloudflare/workerd-windows-64": { + "version": "1.20240712.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20240712.0.tgz", + "integrity": "sha512-u8zoT9PQiiwxuz9npquLBFWrC/RlBWGGZ1aylarZNFlM4sFrRm+bRr6i+KtS+fltHIVXj3teuoKYytA1ppf9Yw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@cloudflare/workers-types": { + "version": "4.20240712.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20240712.0.tgz", + "integrity": "sha512-C+C0ZnkRrxR2tPkZKAXwBsWEse7bWaA7iMbaG6IKaxaPTo/5ilx7Ei3BkI2izxmOJMsC05VS1eFUf95urXzhmw==", + "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/@esbuild-plugins/node-globals-polyfill": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@esbuild-plugins/node-globals-polyfill/-/node-globals-polyfill-0.2.3.tgz", + "integrity": "sha512-r3MIryXDeXDOZh7ih1l/yE9ZLORCd5e8vWg02azWRGj5SPTuoh69A2AIyn0Z31V/kHBfZ4HgWJ+OK3GTTwLmnw==", + "dev": true, + "peerDependencies": { + "esbuild": "*" + } + }, + "node_modules/@esbuild-plugins/node-modules-polyfill": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@esbuild-plugins/node-modules-polyfill/-/node-modules-polyfill-0.2.2.tgz", + "integrity": "sha512-LXV7QsWJxRuMYvKbiznh+U1ilIop3g2TeKRzUxOG5X3YITc8JyyTa90BmLwqqv0YnX4v32CSlG+vsziZp9dMvA==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^4.0.0", + "rollup-plugin-node-polyfills": "^0.2.1" + }, + "peerDependencies": { + "esbuild": "*" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", @@ -71,7 +207,7 @@ "node": ">=12" } }, - "node_modules/@cloudflare/vitest-pool-workers/node_modules/@esbuild/android-arm64": { + "node_modules/@esbuild/android-arm64": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", @@ -87,7 +223,7 @@ "node": ">=12" } }, - "node_modules/@cloudflare/vitest-pool-workers/node_modules/@esbuild/android-x64": { + "node_modules/@esbuild/android-x64": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", @@ -103,7 +239,7 @@ "node": ">=12" } }, - "node_modules/@cloudflare/vitest-pool-workers/node_modules/@esbuild/darwin-arm64": { + "node_modules/@esbuild/darwin-arm64": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==", @@ -119,7 +255,7 @@ "node": ">=12" } }, - "node_modules/@cloudflare/vitest-pool-workers/node_modules/@esbuild/darwin-x64": { + "node_modules/@esbuild/darwin-x64": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", @@ -135,7 +271,7 @@ "node": ">=12" } }, - "node_modules/@cloudflare/vitest-pool-workers/node_modules/@esbuild/freebsd-arm64": { + "node_modules/@esbuild/freebsd-arm64": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", @@ -151,7 +287,7 @@ "node": ">=12" } }, - "node_modules/@cloudflare/vitest-pool-workers/node_modules/@esbuild/freebsd-x64": { + "node_modules/@esbuild/freebsd-x64": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", @@ -167,7 +303,7 @@ "node": ">=12" } }, - "node_modules/@cloudflare/vitest-pool-workers/node_modules/@esbuild/linux-arm": { + "node_modules/@esbuild/linux-arm": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", @@ -183,7 +319,7 @@ "node": ">=12" } }, - "node_modules/@cloudflare/vitest-pool-workers/node_modules/@esbuild/linux-arm64": { + "node_modules/@esbuild/linux-arm64": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", @@ -199,7 +335,7 @@ "node": ">=12" } }, - "node_modules/@cloudflare/vitest-pool-workers/node_modules/@esbuild/linux-ia32": { + "node_modules/@esbuild/linux-ia32": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", @@ -215,7 +351,7 @@ "node": ">=12" } }, - "node_modules/@cloudflare/vitest-pool-workers/node_modules/@esbuild/linux-loong64": { + "node_modules/@esbuild/linux-loong64": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", @@ -231,7 +367,7 @@ "node": ">=12" } }, - "node_modules/@cloudflare/vitest-pool-workers/node_modules/@esbuild/linux-mips64el": { + "node_modules/@esbuild/linux-mips64el": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", @@ -247,7 +383,7 @@ "node": ">=12" } }, - "node_modules/@cloudflare/vitest-pool-workers/node_modules/@esbuild/linux-ppc64": { + "node_modules/@esbuild/linux-ppc64": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", @@ -263,7 +399,7 @@ "node": ">=12" } }, - "node_modules/@cloudflare/vitest-pool-workers/node_modules/@esbuild/linux-riscv64": { + "node_modules/@esbuild/linux-riscv64": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", @@ -279,7 +415,7 @@ "node": ">=12" } }, - "node_modules/@cloudflare/vitest-pool-workers/node_modules/@esbuild/linux-s390x": { + "node_modules/@esbuild/linux-s390x": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", @@ -295,7 +431,7 @@ "node": ">=12" } }, - "node_modules/@cloudflare/vitest-pool-workers/node_modules/@esbuild/linux-x64": { + "node_modules/@esbuild/linux-x64": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", @@ -311,7 +447,7 @@ "node": ">=12" } }, - "node_modules/@cloudflare/vitest-pool-workers/node_modules/@esbuild/netbsd-x64": { + "node_modules/@esbuild/netbsd-x64": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", @@ -327,7 +463,7 @@ "node": ">=12" } }, - "node_modules/@cloudflare/vitest-pool-workers/node_modules/@esbuild/openbsd-x64": { + "node_modules/@esbuild/openbsd-x64": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", @@ -343,7 +479,7 @@ "node": ">=12" } }, - "node_modules/@cloudflare/vitest-pool-workers/node_modules/@esbuild/sunos-x64": { + "node_modules/@esbuild/sunos-x64": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", @@ -359,7 +495,7 @@ "node": ">=12" } }, - "node_modules/@cloudflare/vitest-pool-workers/node_modules/@esbuild/win32-arm64": { + "node_modules/@esbuild/win32-arm64": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", @@ -375,7 +511,7 @@ "node": ">=12" } }, - "node_modules/@cloudflare/vitest-pool-workers/node_modules/@esbuild/win32-ia32": { + "node_modules/@esbuild/win32-ia32": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", @@ -391,7 +527,7 @@ "node": ">=12" } }, - "node_modules/@cloudflare/vitest-pool-workers/node_modules/@esbuild/win32-x64": { + "node_modules/@esbuild/win32-x64": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", @@ -407,790 +543,265 @@ "node": ">=12" } }, - "node_modules/@cloudflare/vitest-pool-workers/node_modules/esbuild": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz", - "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==", + "node_modules/@fastify/busboy": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", + "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", "dev": true, - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, "engines": { - "node": ">=12" + "node": ">=14" + } + }, + "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, + "dependencies": { + "@sinclair/typebox": "^0.27.8" }, - "optionalDependencies": { - "@esbuild/android-arm": "0.17.19", - "@esbuild/android-arm64": "0.17.19", - "@esbuild/android-x64": "0.17.19", - "@esbuild/darwin-arm64": "0.17.19", - "@esbuild/darwin-x64": "0.17.19", - "@esbuild/freebsd-arm64": "0.17.19", - "@esbuild/freebsd-x64": "0.17.19", - "@esbuild/linux-arm": "0.17.19", - "@esbuild/linux-arm64": "0.17.19", - "@esbuild/linux-ia32": "0.17.19", - "@esbuild/linux-loong64": "0.17.19", - "@esbuild/linux-mips64el": "0.17.19", - "@esbuild/linux-ppc64": "0.17.19", - "@esbuild/linux-riscv64": "0.17.19", - "@esbuild/linux-s390x": "0.17.19", - "@esbuild/linux-x64": "0.17.19", - "@esbuild/netbsd-x64": "0.17.19", - "@esbuild/openbsd-x64": "0.17.19", - "@esbuild/sunos-x64": "0.17.19", - "@esbuild/win32-arm64": "0.17.19", - "@esbuild/win32-ia32": "0.17.19", - "@esbuild/win32-x64": "0.17.19" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@cloudflare/workerd-darwin-64": { - "version": "1.20240701.0", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20240701.0.tgz", - "integrity": "sha512-XAZa4ZP+qyTn6JQQACCPH09hGZXP2lTnWKkmg5mPwT8EyRzCKLkczAf98vPP5bq7JZD/zORdFWRY0dOTap8zTQ==", - "cpu": [ - "x64" - ], + "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, - "optional": true, - "os": [ - "darwin" - ], "engines": { - "node": ">=16" + "node": ">=6.0.0" } }, - "node_modules/@cloudflare/workerd-darwin-arm64": { - "version": "1.20240701.0", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20240701.0.tgz", - "integrity": "sha512-w80ZVAgfH4UwTz7fXZtk7KmS2FzlXniuQm4ku4+cIgRTilBAuKqjpOjwUCbx5g13Gqcm9NuiHce+IDGtobRTIQ==", - "cpu": [ - "arm64" - ], + "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 + }, + "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, - "optional": true, - "os": [ - "darwin" - ], + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@noble/ed25519": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@noble/ed25519/-/ed25519-2.1.0.tgz", + "integrity": "sha512-KM4qTyXPinyCgMzeYJH/UudpdL+paJXtY3CHtHYZQtBkS8MZoPr4rOikZllIutJe0d06QDQKisyn02gxZ8TcQA==", + "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" + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" } }, - "node_modules/@cloudflare/workerd-linux-64": { - "version": "1.20240701.0", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20240701.0.tgz", - "integrity": "sha512-UWLr/Anxwwe/25nGv451MNd2jhREmPt/ws17DJJqTLAx6JxwGWA15MeitAIzl0dbxRFAJa+0+R8ag2WR3F/D6g==", + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.1.tgz", + "integrity": "sha512-lncuC4aHicncmbORnx+dUaAgzee9cm/PbIqgWz1PpXuwc+sa1Ct83tnqUDy/GFKleLiN7ZIeytM6KJ4cAn1SxA==", "cpu": [ - "x64" + "arm" ], "dev": true, "optional": true, "os": [ - "linux" - ], - "engines": { - "node": ">=16" - } + "android" + ] }, - "node_modules/@cloudflare/workerd-linux-arm64": { - "version": "1.20240701.0", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20240701.0.tgz", - "integrity": "sha512-3kCnF9kYgov1ggpuWbgpXt4stPOIYtVmPCa7MO2xhhA0TWP6JDUHRUOsnmIgKrvDjXuXqlK16cdg3v+EWsaPJg==", + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.18.1.tgz", + "integrity": "sha512-F/tkdw0WSs4ojqz5Ovrw5r9odqzFjb5LIgHdHZG65dFI1lWTWRVy32KDJLKRISHgJvqUeUhdIvy43fX41znyDg==", "cpu": [ "arm64" ], "dev": true, "optional": true, "os": [ - "linux" - ], - "engines": { - "node": ">=16" - } + "android" + ] }, - "node_modules/@cloudflare/workerd-windows-64": { - "version": "1.20240701.0", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20240701.0.tgz", - "integrity": "sha512-6IPGITRAeS67j3BH1rN4iwYWDt47SqJG7KlZJ5bB4UaNAia4mvMBSy/p2p4vA89bbXoDRjMtEvRu7Robu6O7hQ==", + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.18.1.tgz", + "integrity": "sha512-vk+ma8iC1ebje/ahpxpnrfVQJibTMyHdWpOGZ3JpQ7Mgn/3QNHmPq7YwjZbIE7km73dH5M1e6MRRsnEBW7v5CQ==", "cpu": [ - "x64" + "arm64" ], "dev": true, "optional": true, "os": [ - "win32" - ], - "engines": { - "node": ">=16" - } - }, - "node_modules/@cloudflare/workers-types": { - "version": "4.20240712.0", - "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20240712.0.tgz", - "integrity": "sha512-C+C0ZnkRrxR2tPkZKAXwBsWEse7bWaA7iMbaG6IKaxaPTo/5ilx7Ei3BkI2izxmOJMsC05VS1eFUf95urXzhmw==", - "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/@esbuild-plugins/node-globals-polyfill": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@esbuild-plugins/node-globals-polyfill/-/node-globals-polyfill-0.2.3.tgz", - "integrity": "sha512-r3MIryXDeXDOZh7ih1l/yE9ZLORCd5e8vWg02azWRGj5SPTuoh69A2AIyn0Z31V/kHBfZ4HgWJ+OK3GTTwLmnw==", - "dev": true, - "peerDependencies": { - "esbuild": "*" - } + "darwin" + ] }, - "node_modules/@esbuild-plugins/node-modules-polyfill": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@esbuild-plugins/node-modules-polyfill/-/node-modules-polyfill-0.2.2.tgz", - "integrity": "sha512-LXV7QsWJxRuMYvKbiznh+U1ilIop3g2TeKRzUxOG5X3YITc8JyyTa90BmLwqqv0YnX4v32CSlG+vsziZp9dMvA==", + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.18.1.tgz", + "integrity": "sha512-IgpzXKauRe1Tafcej9STjSSuG0Ghu/xGYH+qG6JwsAUxXrnkvNHcq/NL6nz1+jzvWAnQkuAJ4uIwGB48K9OCGA==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "escape-string-regexp": "^4.0.0", - "rollup-plugin-node-polyfills": "^0.2.1" - }, - "peerDependencies": { - "esbuild": "*" - } + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", - "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.18.1.tgz", + "integrity": "sha512-P9bSiAUnSSM7EmyRK+e5wgpqai86QOSv8BwvkGjLwYuOpaeomiZWifEos517CwbG+aZl1T4clSE1YqqH2JRs+g==", "cpu": [ - "ppc64" + "arm" ], "dev": true, "optional": true, "os": [ - "aix" - ], - "engines": { - "node": ">=12" - } + "linux" + ] }, - "node_modules/@esbuild/android-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", - "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.18.1.tgz", + "integrity": "sha512-5RnjpACoxtS+aWOI1dURKno11d7krfpGDEn19jI8BuWmSBbUC4ytIADfROM1FZrFhQPSoP+KEa3NlEScznBTyQ==", "cpu": [ "arm" ], "dev": true, "optional": true, "os": [ - "android" - ], - "engines": { - "node": ">=12" - } + "linux" + ] }, - "node_modules/@esbuild/android-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", - "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.18.1.tgz", + "integrity": "sha512-8mwmGD668m8WaGbthrEYZ9CBmPug2QPGWxhJxh/vCgBjro5o96gL04WLlg5BA233OCWLqERy4YUzX3bJGXaJgQ==", "cpu": [ "arm64" ], "dev": true, "optional": true, "os": [ - "android" - ], - "engines": { - "node": ">=12" - } + "linux" + ] }, - "node_modules/@esbuild/android-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", - "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.18.1.tgz", + "integrity": "sha512-dJX9u4r4bqInMGOAQoGYdwDP8lQiisWb9et+T84l2WXk41yEej8v2iGKodmdKimT8cTAYt0jFb+UEBxnPkbXEQ==", "cpu": [ - "x64" + "arm64" ], "dev": true, "optional": true, "os": [ - "android" - ], - "engines": { - "node": ">=12" - } + "linux" + ] }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", - "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.18.1.tgz", + "integrity": "sha512-V72cXdTl4EI0x6FNmho4D502sy7ed+LuVW6Ym8aI6DRQ9hQZdp5sj0a2usYOlqvFBNKQnLQGwmYnujo2HvjCxQ==", "cpu": [ - "arm64" + "ppc64" ], "dev": true, "optional": true, "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } + "linux" + ] }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", - "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.18.1.tgz", + "integrity": "sha512-f+pJih7sxoKmbjghrM2RkWo2WHUW8UbfxIQiWo5yeCaCM0TveMEuAzKJte4QskBp1TIinpnRcxkquY+4WuY/tg==", "cpu": [ - "x64" + "riscv64" ], "dev": true, "optional": true, "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } + "linux" + ] }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", - "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.18.1.tgz", + "integrity": "sha512-qb1hMMT3Fr/Qz1OKovCuUM11MUNLUuHeBC2DPPAWUYYUAOFWaxInaTwTQmc7Fl5La7DShTEpmYwgdt2hG+4TEg==", "cpu": [ - "arm64" + "s390x" ], "dev": true, "optional": true, "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } + "linux" + ] }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", - "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.18.1.tgz", + "integrity": "sha512-7O5u/p6oKUFYjRbZkL2FLbwsyoJAjyeXHCU3O4ndvzg2OFO2GinFPSJFGbiwFDaCFc+k7gs9CF243PwdPQFh5g==", "cpu": [ "x64" ], "dev": true, "optional": true, "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } + "linux" + ] }, - "node_modules/@esbuild/linux-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", - "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.18.1.tgz", + "integrity": "sha512-pDLkYITdYrH/9Cv/Vlj8HppDuLMDUBmgsM0+N+xLtFd18aXgM9Nyqupb/Uw+HeidhfYg2lD6CXvz6CjoVOaKjQ==", "cpu": [ - "arm" + "x64" ], "dev": true, "optional": true, "os": [ "linux" - ], - "engines": { - "node": ">=12" - } + ] }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", - "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.18.1.tgz", + "integrity": "sha512-W2ZNI323O/8pJdBGil1oCauuCzmVd9lDmWBBqxYZcOqWD6aWqJtVBQ1dFrF4dYpZPks6F+xCZHfzG5hYlSHZ6g==", "cpu": [ "arm64" ], "dev": true, "optional": true, "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } + "win32" + ] }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", - "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.18.1.tgz", + "integrity": "sha512-ELfEX1/+eGZYMaCIbK4jqLxO1gyTSOIlZr6pbC4SRYFaSIDVKOnZNMdoZ+ON0mrFDp4+H5MhwNC1H/AhE3zQLg==", "cpu": [ "ia32" ], "dev": true, "optional": true, "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", - "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", - "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", - "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", - "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", - "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", - "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", - "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", - "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", - "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", - "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", - "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", - "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@fastify/busboy": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", - "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", - "dev": true, - "engines": { - "node": ">=14" - } - }, - "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, - "dependencies": { - "@sinclair/typebox": "^0.27.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "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, - "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 - }, - "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/@noble/ed25519": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@noble/ed25519/-/ed25519-2.1.0.tgz", - "integrity": "sha512-KM4qTyXPinyCgMzeYJH/UudpdL+paJXtY3CHtHYZQtBkS8MZoPr4rOikZllIutJe0d06QDQKisyn02gxZ8TcQA==", - "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/@rollup/rollup-android-arm-eabi": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.1.tgz", - "integrity": "sha512-lncuC4aHicncmbORnx+dUaAgzee9cm/PbIqgWz1PpXuwc+sa1Ct83tnqUDy/GFKleLiN7ZIeytM6KJ4cAn1SxA==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.18.1.tgz", - "integrity": "sha512-F/tkdw0WSs4ojqz5Ovrw5r9odqzFjb5LIgHdHZG65dFI1lWTWRVy32KDJLKRISHgJvqUeUhdIvy43fX41znyDg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.18.1.tgz", - "integrity": "sha512-vk+ma8iC1ebje/ahpxpnrfVQJibTMyHdWpOGZ3JpQ7Mgn/3QNHmPq7YwjZbIE7km73dH5M1e6MRRsnEBW7v5CQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.18.1.tgz", - "integrity": "sha512-IgpzXKauRe1Tafcej9STjSSuG0Ghu/xGYH+qG6JwsAUxXrnkvNHcq/NL6nz1+jzvWAnQkuAJ4uIwGB48K9OCGA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.18.1.tgz", - "integrity": "sha512-P9bSiAUnSSM7EmyRK+e5wgpqai86QOSv8BwvkGjLwYuOpaeomiZWifEos517CwbG+aZl1T4clSE1YqqH2JRs+g==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.18.1.tgz", - "integrity": "sha512-5RnjpACoxtS+aWOI1dURKno11d7krfpGDEn19jI8BuWmSBbUC4ytIADfROM1FZrFhQPSoP+KEa3NlEScznBTyQ==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.18.1.tgz", - "integrity": "sha512-8mwmGD668m8WaGbthrEYZ9CBmPug2QPGWxhJxh/vCgBjro5o96gL04WLlg5BA233OCWLqERy4YUzX3bJGXaJgQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.18.1.tgz", - "integrity": "sha512-dJX9u4r4bqInMGOAQoGYdwDP8lQiisWb9et+T84l2WXk41yEej8v2iGKodmdKimT8cTAYt0jFb+UEBxnPkbXEQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.18.1.tgz", - "integrity": "sha512-V72cXdTl4EI0x6FNmho4D502sy7ed+LuVW6Ym8aI6DRQ9hQZdp5sj0a2usYOlqvFBNKQnLQGwmYnujo2HvjCxQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.18.1.tgz", - "integrity": "sha512-f+pJih7sxoKmbjghrM2RkWo2WHUW8UbfxIQiWo5yeCaCM0TveMEuAzKJte4QskBp1TIinpnRcxkquY+4WuY/tg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.18.1.tgz", - "integrity": "sha512-qb1hMMT3Fr/Qz1OKovCuUM11MUNLUuHeBC2DPPAWUYYUAOFWaxInaTwTQmc7Fl5La7DShTEpmYwgdt2hG+4TEg==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.18.1.tgz", - "integrity": "sha512-7O5u/p6oKUFYjRbZkL2FLbwsyoJAjyeXHCU3O4ndvzg2OFO2GinFPSJFGbiwFDaCFc+k7gs9CF243PwdPQFh5g==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.18.1.tgz", - "integrity": "sha512-pDLkYITdYrH/9Cv/Vlj8HppDuLMDUBmgsM0+N+xLtFd18aXgM9Nyqupb/Uw+HeidhfYg2lD6CXvz6CjoVOaKjQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.18.1.tgz", - "integrity": "sha512-W2ZNI323O/8pJdBGil1oCauuCzmVd9lDmWBBqxYZcOqWD6aWqJtVBQ1dFrF4dYpZPks6F+xCZHfzG5hYlSHZ6g==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.18.1.tgz", - "integrity": "sha512-ELfEX1/+eGZYMaCIbK4jqLxO1gyTSOIlZr6pbC4SRYFaSIDVKOnZNMdoZ+ON0mrFDp4+H5MhwNC1H/AhE3zQLg==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] + "win32" + ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { "version": "4.18.1", @@ -1218,9 +829,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.14.10", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.10.tgz", - "integrity": "sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ==", + "version": "20.14.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.11.tgz", + "integrity": "sha512-kprQpL8MMeszbz6ojB5/tU8PLN4kesnN8Gjzw349rDlNgsSzg90lAVj3llK99Dh7JON+t9AuscPPFW6mPbTnSA==", "dev": true, "dependencies": { "undici-types": "~5.26.4" @@ -1249,13 +860,29 @@ "url": "https://opencollective.com/vitest" } }, - "node_modules/@vitest/runner": { + "node_modules/@vitest/expect/node_modules/@vitest/utils": { "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.5.0.tgz", - "integrity": "sha512-7HWwdxXP5yDoe7DTpbif9l6ZmDwCzcSIK38kTSIt6CFEpMjX4EpCgT6wUmS0xTXqMI6E/ONmfgRKmaujpabjZQ==", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.5.0.tgz", + "integrity": "sha512-BDU0GNL8MWkRkSRdNFvCUCAVOeHaUlVJ9Tx0TYBZyXaaOTmGtUFObzchCivIBrIwKzvZA7A9sCejVhXM2aY98A==", "dev": true, "dependencies": { - "@vitest/utils": "1.5.0", + "diff-sequences": "^29.6.3", + "estree-walker": "^3.0.3", + "loupe": "^2.3.7", + "pretty-format": "^29.7.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.5.3.tgz", + "integrity": "sha512-7PlfuReN8692IKQIdCxwir1AOaP5THfNkp0Uc4BKr2na+9lALNit7ub9l3/R7MP8aV61+mHKRGiqEKRIwu6iiQ==", + "dev": true, + "peer": true, + "dependencies": { + "@vitest/utils": "1.5.3", "p-limit": "^5.0.0", "pathe": "^1.1.1" }, @@ -1264,10 +891,11 @@ } }, "node_modules/@vitest/snapshot": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.5.0.tgz", - "integrity": "sha512-qpv3fSEuNrhAO3FpH6YYRdaECnnRjg9VxbhdtPwPRnzSfHVXnNzzrpX4cJxqiwgRMo7uRMWDFBlsBq4Cr+rO3A==", + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.5.3.tgz", + "integrity": "sha512-K3mvIsjyKYBhNIDujMD2gfQEzddLe51nNOAf45yKRt/QFJcUIeTQd2trRvv6M6oCBHNVnZwFWbQ4yj96ibiDsA==", "dev": true, + "peer": true, "dependencies": { "magic-string": "^0.30.5", "pathe": "^1.1.1", @@ -1290,10 +918,11 @@ } }, "node_modules/@vitest/utils": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.5.0.tgz", - "integrity": "sha512-BDU0GNL8MWkRkSRdNFvCUCAVOeHaUlVJ9Tx0TYBZyXaaOTmGtUFObzchCivIBrIwKzvZA7A9sCejVhXM2aY98A==", + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.5.3.tgz", + "integrity": "sha512-rE9DTN1BRhzkzqNQO+kw8ZgfeEBCLXiHJwetk668shmNBpSagQxneT5eSqEBLP+cqSiAeecvQmbpFfdMyLcIQA==", "dev": true, + "peer": true, "dependencies": { "diff-sequences": "^29.6.3", "estree-walker": "^3.0.3", @@ -1594,9 +1223,9 @@ } }, "node_modules/esbuild": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", - "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz", + "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==", "dev": true, "hasInstallScript": true, "bin": { @@ -1606,29 +1235,28 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.21.5", - "@esbuild/android-arm": "0.21.5", - "@esbuild/android-arm64": "0.21.5", - "@esbuild/android-x64": "0.21.5", - "@esbuild/darwin-arm64": "0.21.5", - "@esbuild/darwin-x64": "0.21.5", - "@esbuild/freebsd-arm64": "0.21.5", - "@esbuild/freebsd-x64": "0.21.5", - "@esbuild/linux-arm": "0.21.5", - "@esbuild/linux-arm64": "0.21.5", - "@esbuild/linux-ia32": "0.21.5", - "@esbuild/linux-loong64": "0.21.5", - "@esbuild/linux-mips64el": "0.21.5", - "@esbuild/linux-ppc64": "0.21.5", - "@esbuild/linux-riscv64": "0.21.5", - "@esbuild/linux-s390x": "0.21.5", - "@esbuild/linux-x64": "0.21.5", - "@esbuild/netbsd-x64": "0.21.5", - "@esbuild/openbsd-x64": "0.21.5", - "@esbuild/sunos-x64": "0.21.5", - "@esbuild/win32-arm64": "0.21.5", - "@esbuild/win32-ia32": "0.21.5", - "@esbuild/win32-x64": "0.21.5" + "@esbuild/android-arm": "0.17.19", + "@esbuild/android-arm64": "0.17.19", + "@esbuild/android-x64": "0.17.19", + "@esbuild/darwin-arm64": "0.17.19", + "@esbuild/darwin-x64": "0.17.19", + "@esbuild/freebsd-arm64": "0.17.19", + "@esbuild/freebsd-x64": "0.17.19", + "@esbuild/linux-arm": "0.17.19", + "@esbuild/linux-arm64": "0.17.19", + "@esbuild/linux-ia32": "0.17.19", + "@esbuild/linux-loong64": "0.17.19", + "@esbuild/linux-mips64el": "0.17.19", + "@esbuild/linux-ppc64": "0.17.19", + "@esbuild/linux-riscv64": "0.17.19", + "@esbuild/linux-s390x": "0.17.19", + "@esbuild/linux-x64": "0.17.19", + "@esbuild/netbsd-x64": "0.17.19", + "@esbuild/openbsd-x64": "0.17.19", + "@esbuild/sunos-x64": "0.17.19", + "@esbuild/win32-arm64": "0.17.19", + "@esbuild/win32-ia32": "0.17.19", + "@esbuild/win32-x64": "0.17.19" } }, "node_modules/escape-string-regexp": { @@ -1805,9 +1433,9 @@ } }, "node_modules/is-core-module": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.14.0.tgz", - "integrity": "sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A==", + "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, "dependencies": { "hasown": "^2.0.2" @@ -1943,9 +1571,9 @@ } }, "node_modules/miniflare": { - "version": "3.20240701.0", - "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-3.20240701.0.tgz", - "integrity": "sha512-m9+I+7JNyqDGftCMKp9cK9pCZkK72hAL2mM9IWwhct+ZmucLBA8Uu6+rHQqA5iod86cpwOkrB2PrPA3wx9YNgw==", + "version": "3.20240712.0", + "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-3.20240712.0.tgz", + "integrity": "sha512-zVbsMX2phvJS1uTPmjK6CvVBq4ON2UkmvTw9IMfNPACsWJmHEdsBDxsYEG1vKAduJdI5gULLuJf7qpFxByDhGw==", "dev": true, "dependencies": { "@cspotcode/source-map-support": "0.8.1", @@ -1956,7 +1584,7 @@ "glob-to-regexp": "^0.4.1", "stoppable": "^1.1.0", "undici": "^5.28.4", - "workerd": "1.20240701.0", + "workerd": "1.20240712.0", "ws": "^8.17.1", "youch": "^3.2.2", "zod": "^3.22.3" @@ -2194,9 +1822,9 @@ } }, "node_modules/prettier": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz", - "integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", + "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", "dev": true, "bin": { "prettier": "bin/prettier.cjs" @@ -2372,9 +2000,9 @@ } }, "node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -2580,9 +2208,9 @@ } }, "node_modules/ufo": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.3.tgz", - "integrity": "sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw==", + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.4.tgz", + "integrity": "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==", "dev": true }, "node_modules/undici": { @@ -2615,248 +2243,90 @@ "mime": "^3.0.0", "node-fetch-native": "^1.6.4", "pathe": "^1.1.2", - "ufo": "^1.5.3" - } - }, - "node_modules/vite": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.3.3.tgz", - "integrity": "sha512-NPQdeCU0Dv2z5fu+ULotpuq5yfCS1BzKUIPhNbP3YBfAMGJXbt2nS+sbTFu+qchaqWTD+H3JK++nRwr6XIcp6A==", - "dev": true, - "dependencies": { - "esbuild": "^0.21.3", - "postcss": "^8.4.39", - "rollup": "^4.13.0" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^18.0.0 || >=20.0.0", - "less": "*", - "lightningcss": "^1.21.0", - "sass": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.4.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - } - } - }, - "node_modules/vite-node": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.5.0.tgz", - "integrity": "sha512-tV8h6gMj6vPzVCa7l+VGq9lwoJjW8Y79vst8QZZGiuRAfijU+EEWuc0kFpmndQrWhMMhet1jdSF+40KSZUqIIw==", - "dev": true, - "dependencies": { - "cac": "^6.7.14", - "debug": "^4.3.4", - "pathe": "^1.1.1", - "picocolors": "^1.0.0", - "vite": "^5.0.0" - }, - "bin": { - "vite-node": "vite-node.mjs" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/vitest": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.5.0.tgz", - "integrity": "sha512-d8UKgR0m2kjdxDWX6911uwxout6GHS0XaGH1cksSIVVG8kRlE7G7aBw7myKQCvDI5dT4j7ZMa+l706BIORMDLw==", + "ufo": "^1.5.3" + } + }, + "node_modules/vite": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.3.4.tgz", + "integrity": "sha512-Cw+7zL3ZG9/NZBB8C+8QbQZmR54GwqIz+WMI4b3JgdYJvX+ny9AjJXqkGQlDXSXRP9rP0B4tbciRMOVEKulVOA==", "dev": true, "dependencies": { - "@vitest/expect": "1.5.0", - "@vitest/runner": "1.5.0", - "@vitest/snapshot": "1.5.0", - "@vitest/spy": "1.5.0", - "@vitest/utils": "1.5.0", - "acorn-walk": "^8.3.2", - "chai": "^4.3.10", - "debug": "^4.3.4", - "execa": "^8.0.1", - "local-pkg": "^0.5.0", - "magic-string": "^0.30.5", - "pathe": "^1.1.1", - "picocolors": "^1.0.0", - "std-env": "^3.5.0", - "strip-literal": "^2.0.0", - "tinybench": "^2.5.1", - "tinypool": "^0.8.3", - "vite": "^5.0.0", - "vite-node": "1.5.0", - "why-is-node-running": "^2.2.2" + "esbuild": "^0.21.3", + "postcss": "^8.4.39", + "rollup": "^4.13.0" }, "bin": { - "vitest": "vitest.mjs" + "vite": "bin/vite.js" }, "engines": { "node": "^18.0.0 || >=20.0.0" }, "funding": { - "url": "https://opencollective.com/vitest" + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" }, "peerDependencies": { - "@edge-runtime/vm": "*", "@types/node": "^18.0.0 || >=20.0.0", - "@vitest/browser": "1.5.0", - "@vitest/ui": "1.5.0", - "happy-dom": "*", - "jsdom": "*" + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" }, "peerDependenciesMeta": { - "@edge-runtime/vm": { + "@types/node": { "optional": true }, - "@types/node": { + "less": { "optional": true }, - "@vitest/browser": { + "lightningcss": { "optional": true }, - "@vitest/ui": { + "sass": { "optional": true }, - "happy-dom": { + "stylus": { "optional": true }, - "jsdom": { + "sugarss": { + "optional": true + }, + "terser": { "optional": true } } }, - "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/why-is-node-running": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", - "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", - "dev": true, - "dependencies": { - "siginfo": "^2.0.0", - "stackback": "0.0.2" - }, - "bin": { - "why-is-node-running": "cli.js" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/workerd": { - "version": "1.20240701.0", - "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20240701.0.tgz", - "integrity": "sha512-qSgNVqauqzNCij9MaJLF2c2ko3AnFioVSIxMSryGbRK+LvtGr9BKBt6JOxCb24DoJASoJDx3pe3DJHBVydUiBg==", - "dev": true, - "hasInstallScript": true, - "bin": { - "workerd": "bin/workerd" - }, - "engines": { - "node": ">=16" - }, - "optionalDependencies": { - "@cloudflare/workerd-darwin-64": "1.20240701.0", - "@cloudflare/workerd-darwin-arm64": "1.20240701.0", - "@cloudflare/workerd-linux-64": "1.20240701.0", - "@cloudflare/workerd-linux-arm64": "1.20240701.0", - "@cloudflare/workerd-windows-64": "1.20240701.0" - } - }, - "node_modules/wrangler": { - "version": "3.64.0", - "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-3.64.0.tgz", - "integrity": "sha512-q2VQADJXzuOkXs9KIfPSx7UCZHBoxsqSNbJDLkc2pHpGmsyNQXsJRqjMoTg/Kls7O3K9A7EGnzGr7+Io2vE6AQ==", + "node_modules/vite-node": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.5.0.tgz", + "integrity": "sha512-tV8h6gMj6vPzVCa7l+VGq9lwoJjW8Y79vst8QZZGiuRAfijU+EEWuc0kFpmndQrWhMMhet1jdSF+40KSZUqIIw==", "dev": true, "dependencies": { - "@cloudflare/kv-asset-handler": "0.3.4", - "@esbuild-plugins/node-globals-polyfill": "^0.2.3", - "@esbuild-plugins/node-modules-polyfill": "^0.2.2", - "blake3-wasm": "^2.1.5", - "chokidar": "^3.5.3", - "date-fns": "^3.6.0", - "esbuild": "0.17.19", - "miniflare": "3.20240701.0", - "nanoid": "^3.3.3", - "path-to-regexp": "^6.2.0", - "resolve": "^1.22.8", - "resolve.exports": "^2.0.2", - "selfsigned": "^2.0.1", - "source-map": "^0.6.1", - "unenv": "npm:unenv-nightly@1.10.0-1717606461.a117952", - "xxhash-wasm": "^1.0.1" + "cac": "^6.7.14", + "debug": "^4.3.4", + "pathe": "^1.1.1", + "picocolors": "^1.0.0", + "vite": "^5.0.0" }, "bin": { - "wrangler": "bin/wrangler.js", - "wrangler2": "bin/wrangler.js" + "vite-node": "vite-node.mjs" }, "engines": { - "node": ">=16.17.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - }, - "peerDependencies": { - "@cloudflare/workers-types": "^4.20240620.0" + "node": "^18.0.0 || >=20.0.0" }, - "peerDependenciesMeta": { - "@cloudflare/workers-types": { - "optional": true - } + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/wrangler/node_modules/@esbuild/android-arm": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", - "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", + "node_modules/vite/node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", "cpu": [ "arm" ], @@ -2869,10 +2339,10 @@ "node": ">=12" } }, - "node_modules/wrangler/node_modules/@esbuild/android-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", - "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", + "node_modules/vite/node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", "cpu": [ "arm64" ], @@ -2885,10 +2355,10 @@ "node": ">=12" } }, - "node_modules/wrangler/node_modules/@esbuild/android-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", - "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", + "node_modules/vite/node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", "cpu": [ "x64" ], @@ -2901,10 +2371,10 @@ "node": ">=12" } }, - "node_modules/wrangler/node_modules/@esbuild/darwin-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", - "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==", + "node_modules/vite/node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", "cpu": [ "arm64" ], @@ -2917,10 +2387,10 @@ "node": ">=12" } }, - "node_modules/wrangler/node_modules/@esbuild/darwin-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", - "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", + "node_modules/vite/node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", "cpu": [ "x64" ], @@ -2933,10 +2403,10 @@ "node": ">=12" } }, - "node_modules/wrangler/node_modules/@esbuild/freebsd-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", - "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", + "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", "cpu": [ "arm64" ], @@ -2949,10 +2419,10 @@ "node": ">=12" } }, - "node_modules/wrangler/node_modules/@esbuild/freebsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", - "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", + "node_modules/vite/node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", "cpu": [ "x64" ], @@ -2965,10 +2435,10 @@ "node": ">=12" } }, - "node_modules/wrangler/node_modules/@esbuild/linux-arm": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", - "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", + "node_modules/vite/node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", "cpu": [ "arm" ], @@ -2981,10 +2451,10 @@ "node": ">=12" } }, - "node_modules/wrangler/node_modules/@esbuild/linux-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", - "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", + "node_modules/vite/node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", "cpu": [ "arm64" ], @@ -2997,10 +2467,10 @@ "node": ">=12" } }, - "node_modules/wrangler/node_modules/@esbuild/linux-ia32": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", - "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", + "node_modules/vite/node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", "cpu": [ "ia32" ], @@ -3013,10 +2483,10 @@ "node": ">=12" } }, - "node_modules/wrangler/node_modules/@esbuild/linux-loong64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", - "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", + "node_modules/vite/node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", "cpu": [ "loong64" ], @@ -3029,10 +2499,10 @@ "node": ">=12" } }, - "node_modules/wrangler/node_modules/@esbuild/linux-mips64el": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", - "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", + "node_modules/vite/node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", "cpu": [ "mips64el" ], @@ -3045,10 +2515,10 @@ "node": ">=12" } }, - "node_modules/wrangler/node_modules/@esbuild/linux-ppc64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", - "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", + "node_modules/vite/node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", "cpu": [ "ppc64" ], @@ -3061,10 +2531,10 @@ "node": ">=12" } }, - "node_modules/wrangler/node_modules/@esbuild/linux-riscv64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", - "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", + "node_modules/vite/node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", "cpu": [ "riscv64" ], @@ -3077,10 +2547,10 @@ "node": ">=12" } }, - "node_modules/wrangler/node_modules/@esbuild/linux-s390x": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", - "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", + "node_modules/vite/node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", "cpu": [ "s390x" ], @@ -3093,10 +2563,10 @@ "node": ">=12" } }, - "node_modules/wrangler/node_modules/@esbuild/linux-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", - "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", + "node_modules/vite/node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", "cpu": [ "x64" ], @@ -3109,10 +2579,10 @@ "node": ">=12" } }, - "node_modules/wrangler/node_modules/@esbuild/netbsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", - "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", + "node_modules/vite/node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", "cpu": [ "x64" ], @@ -3125,10 +2595,10 @@ "node": ">=12" } }, - "node_modules/wrangler/node_modules/@esbuild/openbsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", - "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", + "node_modules/vite/node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", "cpu": [ "x64" ], @@ -3141,10 +2611,10 @@ "node": ">=12" } }, - "node_modules/wrangler/node_modules/@esbuild/sunos-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", - "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", + "node_modules/vite/node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", "cpu": [ "x64" ], @@ -3157,10 +2627,10 @@ "node": ">=12" } }, - "node_modules/wrangler/node_modules/@esbuild/win32-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", - "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", + "node_modules/vite/node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", "cpu": [ "arm64" ], @@ -3173,10 +2643,10 @@ "node": ">=12" } }, - "node_modules/wrangler/node_modules/@esbuild/win32-ia32": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", - "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", + "node_modules/vite/node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", "cpu": [ "ia32" ], @@ -3189,10 +2659,10 @@ "node": ">=12" } }, - "node_modules/wrangler/node_modules/@esbuild/win32-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", - "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", + "node_modules/vite/node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", "cpu": [ "x64" ], @@ -3205,10 +2675,10 @@ "node": ">=12" } }, - "node_modules/wrangler/node_modules/esbuild": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz", - "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==", + "node_modules/vite/node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", "dev": true, "hasInstallScript": true, "bin": { @@ -3218,28 +2688,230 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/android-arm": "0.17.19", - "@esbuild/android-arm64": "0.17.19", - "@esbuild/android-x64": "0.17.19", - "@esbuild/darwin-arm64": "0.17.19", - "@esbuild/darwin-x64": "0.17.19", - "@esbuild/freebsd-arm64": "0.17.19", - "@esbuild/freebsd-x64": "0.17.19", - "@esbuild/linux-arm": "0.17.19", - "@esbuild/linux-arm64": "0.17.19", - "@esbuild/linux-ia32": "0.17.19", - "@esbuild/linux-loong64": "0.17.19", - "@esbuild/linux-mips64el": "0.17.19", - "@esbuild/linux-ppc64": "0.17.19", - "@esbuild/linux-riscv64": "0.17.19", - "@esbuild/linux-s390x": "0.17.19", - "@esbuild/linux-x64": "0.17.19", - "@esbuild/netbsd-x64": "0.17.19", - "@esbuild/openbsd-x64": "0.17.19", - "@esbuild/sunos-x64": "0.17.19", - "@esbuild/win32-arm64": "0.17.19", - "@esbuild/win32-ia32": "0.17.19", - "@esbuild/win32-x64": "0.17.19" + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/vitest": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.5.0.tgz", + "integrity": "sha512-d8UKgR0m2kjdxDWX6911uwxout6GHS0XaGH1cksSIVVG8kRlE7G7aBw7myKQCvDI5dT4j7ZMa+l706BIORMDLw==", + "dev": true, + "dependencies": { + "@vitest/expect": "1.5.0", + "@vitest/runner": "1.5.0", + "@vitest/snapshot": "1.5.0", + "@vitest/spy": "1.5.0", + "@vitest/utils": "1.5.0", + "acorn-walk": "^8.3.2", + "chai": "^4.3.10", + "debug": "^4.3.4", + "execa": "^8.0.1", + "local-pkg": "^0.5.0", + "magic-string": "^0.30.5", + "pathe": "^1.1.1", + "picocolors": "^1.0.0", + "std-env": "^3.5.0", + "strip-literal": "^2.0.0", + "tinybench": "^2.5.1", + "tinypool": "^0.8.3", + "vite": "^5.0.0", + "vite-node": "1.5.0", + "why-is-node-running": "^2.2.2" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/node": "^18.0.0 || >=20.0.0", + "@vitest/browser": "1.5.0", + "@vitest/ui": "1.5.0", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/vitest/node_modules/@vitest/runner": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.5.0.tgz", + "integrity": "sha512-7HWwdxXP5yDoe7DTpbif9l6ZmDwCzcSIK38kTSIt6CFEpMjX4EpCgT6wUmS0xTXqMI6E/ONmfgRKmaujpabjZQ==", + "dev": true, + "dependencies": { + "@vitest/utils": "1.5.0", + "p-limit": "^5.0.0", + "pathe": "^1.1.1" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vitest/node_modules/@vitest/snapshot": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.5.0.tgz", + "integrity": "sha512-qpv3fSEuNrhAO3FpH6YYRdaECnnRjg9VxbhdtPwPRnzSfHVXnNzzrpX4cJxqiwgRMo7uRMWDFBlsBq4Cr+rO3A==", + "dev": true, + "dependencies": { + "magic-string": "^0.30.5", + "pathe": "^1.1.1", + "pretty-format": "^29.7.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vitest/node_modules/@vitest/utils": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.5.0.tgz", + "integrity": "sha512-BDU0GNL8MWkRkSRdNFvCUCAVOeHaUlVJ9Tx0TYBZyXaaOTmGtUFObzchCivIBrIwKzvZA7A9sCejVhXM2aY98A==", + "dev": true, + "dependencies": { + "diff-sequences": "^29.6.3", + "estree-walker": "^3.0.3", + "loupe": "^2.3.7", + "pretty-format": "^29.7.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "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/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/workerd": { + "version": "1.20240712.0", + "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20240712.0.tgz", + "integrity": "sha512-hdIHZif82hBDy9YnMtcmDGgbLU5f2P2aGpi/X8EKhTSLDppVUGrkY3XB536J4jGjA2D5dS0FUEXCl5bAJEed8Q==", + "dev": true, + "hasInstallScript": true, + "bin": { + "workerd": "bin/workerd" + }, + "engines": { + "node": ">=16" + }, + "optionalDependencies": { + "@cloudflare/workerd-darwin-64": "1.20240712.0", + "@cloudflare/workerd-darwin-arm64": "1.20240712.0", + "@cloudflare/workerd-linux-64": "1.20240712.0", + "@cloudflare/workerd-linux-arm64": "1.20240712.0", + "@cloudflare/workerd-windows-64": "1.20240712.0" + } + }, + "node_modules/wrangler": { + "version": "3.65.0", + "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-3.65.0.tgz", + "integrity": "sha512-IDy4ttyJZssazAd5CXHw4NWeZFGxngdNF5m2ogltdT3CV7uHfCvPVdMcr4uNMpRZd0toHmAE3LtQeXxDFFp88A==", + "dev": true, + "dependencies": { + "@cloudflare/kv-asset-handler": "0.3.4", + "@esbuild-plugins/node-globals-polyfill": "^0.2.3", + "@esbuild-plugins/node-modules-polyfill": "^0.2.2", + "blake3-wasm": "^2.1.5", + "chokidar": "^3.5.3", + "date-fns": "^3.6.0", + "esbuild": "0.17.19", + "miniflare": "3.20240712.0", + "nanoid": "^3.3.3", + "path-to-regexp": "^6.2.0", + "resolve": "^1.22.8", + "resolve.exports": "^2.0.2", + "selfsigned": "^2.0.1", + "source-map": "^0.6.1", + "unenv": "npm:unenv-nightly@1.10.0-1717606461.a117952", + "xxhash-wasm": "^1.0.1" + }, + "bin": { + "wrangler": "bin/wrangler.js", + "wrangler2": "bin/wrangler.js" + }, + "engines": { + "node": ">=16.17.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + }, + "peerDependencies": { + "@cloudflare/workers-types": "^4.20240712.0" + }, + "peerDependenciesMeta": { + "@cloudflare/workers-types": { + "optional": true + } } }, "node_modules/ws": { From ef515d84cb7ebfdfb33b3893ad276f374d4398eb Mon Sep 17 00:00:00 2001 From: neonphog Date: Thu, 18 Jul 2024 14:56:17 -0600 Subject: [PATCH 34/36] npm --verbose ci --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index c964ef2..622836d 100644 --- a/Makefile +++ b/Makefile @@ -65,7 +65,7 @@ cf-test: static: cargo fmt -- --check cargo clippy -- -Dwarnings - cd ts/sbd-server && npm ci + cd ts/sbd-server && npm --verbose ci cd ts/sbd-server && npm run test:fmt cd ts/sbd-server && npm run test:type @if [ "${CI}x" != "x" ]; then git diff --exit-code; fi From 89bcc6660a3bc70804b713d2fc1e0a161459f94c Mon Sep 17 00:00:00 2001 From: neonphog Date: Thu, 18 Jul 2024 14:58:53 -0600 Subject: [PATCH 35/36] npm install --- Makefile | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 622836d..9acb0fc 100644 --- a/Makefile +++ b/Makefile @@ -58,14 +58,18 @@ test: RUST_BACKTRACE=1 cargo test cf-test: - cd ts/sbd-server && npm ci + #npm ci is temporarrily broken + #cd ts/sbd-server && npm ci + cd ts/sbd-server && npm install cd ts/sbd-server && npm run test:unit cd ts/sbd-server && cargo run --manifest-path ../../rust/sbd-o-bahn-server-tester/Cargo.toml -- node ./server-o-bahn-runner.mjs static: cargo fmt -- --check cargo clippy -- -Dwarnings - cd ts/sbd-server && npm --verbose ci + #npm ci is temporarrily broken + #cd ts/sbd-server && npm --verbose ci + cd ts/sbd-server && npm install cd ts/sbd-server && npm run test:fmt cd ts/sbd-server && npm run test:type @if [ "${CI}x" != "x" ]; then git diff --exit-code; fi From 2ec013693dca22afb3a0166f291bc02d2b330e1a Mon Sep 17 00:00:00 2001 From: neonphog Date: Thu, 18 Jul 2024 15:00:50 -0600 Subject: [PATCH 36/36] older node --- .github/workflows/static.yml | 2 +- .github/workflows/test.yml | 2 +- Makefile | 8 ++------ 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/.github/workflows/static.yml b/.github/workflows/static.yml index 2f1ebef..3c50c83 100644 --- a/.github/workflows/static.yml +++ b/.github/workflows/static.yml @@ -33,7 +33,7 @@ jobs: - name: NodeJS Setup uses: actions/setup-node@v4 with: - node-version: latest + node-version: '20.x' cache: 'npm' cache-dependency-path: ts/sbd-server/package-lock.json diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b80d953..11ecb86 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -33,7 +33,7 @@ jobs: - name: NodeJS Setup uses: actions/setup-node@v4 with: - node-version: latest + node-version: '20.x' cache: 'npm' cache-dependency-path: ts/sbd-server/package-lock.json diff --git a/Makefile b/Makefile index 9acb0fc..c964ef2 100644 --- a/Makefile +++ b/Makefile @@ -58,18 +58,14 @@ test: RUST_BACKTRACE=1 cargo test cf-test: - #npm ci is temporarrily broken - #cd ts/sbd-server && npm ci - cd ts/sbd-server && npm install + cd ts/sbd-server && npm ci cd ts/sbd-server && npm run test:unit cd ts/sbd-server && cargo run --manifest-path ../../rust/sbd-o-bahn-server-tester/Cargo.toml -- node ./server-o-bahn-runner.mjs static: cargo fmt -- --check cargo clippy -- -Dwarnings - #npm ci is temporarrily broken - #cd ts/sbd-server && npm --verbose ci - cd ts/sbd-server && npm install + cd ts/sbd-server && npm ci cd ts/sbd-server && npm run test:fmt cd ts/sbd-server && npm run test:type @if [ "${CI}x" != "x" ]; then git diff --exit-code; fi