diff --git a/.github/workflows/test-azd-deployment.yaml b/.github/workflows/test-azd-deployment.yaml new file mode 100644 index 00000000..5196d29a --- /dev/null +++ b/.github/workflows/test-azd-deployment.yaml @@ -0,0 +1,160 @@ +# composite workflow to test the azd deployment of the app +# uses a github federated identity +name: Test AZD Deployment + +on: + push: + branches: + - main + +permissions: + id-token: write + contents: read + +jobs: + deploy: + outputs: + storeAdminIp: ${{ steps.kubectl_get_service.outputs.STORE_ADMIN_IP }} + storeFrontIp: ${{ steps.kubectl_get_service.outputs.STORE_FRONT_IP }} + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + + - uses: actions/cache@v3 + with: + path: | + .azure/ + key: ${{ runner.os }}-azd-${{ hashFiles('infra/**') }}-${{ env.BUST_CACHE }}-${{ github.sha }} + + - name: Install azd + uses: Azure/setup-azd@v0.1.0 + + - name: Install Nodejs + uses: actions/setup-node@v3 + with: + node-version: 18 + + - name: Login az + uses: azure/login@v1 + with: + creds: ${{ secrets.AZURE_CREDENTIALS }} + + - name: Set az account + uses: azure/CLI@v1 + with: + inlineScript: | + az account set --subscription ${{vars.AZURE_SUBSCRIPTION_ID}} + + - name: Log in with Azure + run: | + $info = $Env:AZURE_CREDENTIALS | ConvertFrom-Json -AsHashtable; + Write-Host "::add-mask::$($info.clientSecret)" + + azd auth login ` + --client-id "$($info.clientId)" ` + --client-secret "$($info.clientSecret)" ` + --tenant-id "$($info.tenantId)" + shell: pwsh + env: + AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }} + + - name: Provision Infrastructure + run: azd provision --no-prompt + env: + AZURE_ENV_NAME: ${{ vars.AZURE_ENV_NAME }} + AZURE_LOCATION: ${{ vars.AZURE_LOCATION }} + AZURE_SUBSCRIPTION_ID: ${{ vars.AZURE_SUBSCRIPTION_ID }} + ARM_TENANT_ID: ${{ vars.ARM_TENANT_ID }} + ARM_CLIENT_ID: ${{ vars.ARM_CLIENT_ID }} + ARM_CLIENT_SECRET: ${{ secrets.ARM_CLIENT_SECRET }} + + - name: Deploy Application + run: azd deploy --no-prompt + env: + AZURE_ENV_NAME: ${{ vars.AZURE_ENV_NAME }} + AZURE_LOCATION: ${{ vars.AZURE_LOCATION }} + AZURE_SUBSCRIPTION_ID: ${{ vars.AZURE_SUBSCRIPTION_ID }} + + - name: Get Store IPs + id: kubectl_get_service + run: | + eval $(azd env get-values) + az aks get-credentials --resource-group $AZURE_RESOURCEGROUP_NAME --name $AZURE_AKS_CLUSTER_NAME + storeAdminIp=$(kubectl get service store-admin -o jsonpath='{.status.loadBalancer.ingress[0].ip}') + while [ -z "$storeAdminIp" ]; do + sleep 60 + storeAdminIp=$(kubectl get service store-admin -o jsonpath='{.status.loadBalancer.ingress[0].ip}') + done + echo "STORE_ADMIN_IP=${storeAdminIp}" + echo "STORE_ADMIN_IP=${storeAdminIp}" >> "$GITHUB_OUTPUT" + storeFrontIp=$(kubectl get service store-front -o jsonpath='{.status.loadBalancer.ingress[0].ip}') + while [ -z "$storeFrontIp" ]; do + sleep 60 + storeFrontIp=$(kubectl get service store-front -o jsonpath='{.status.loadBalancer.ingress[0].ip}') + done + echo "STORE_FRONT_IP=${storeFrontIp}" + echo "STORE_FRONT_IP=${storeFrontIp}" >> "$GITHUB_OUTPUT" + + playwright-tests: + needs: deploy + uses: ./.github/workflows/test-playwright.yaml + with: + storeAdminUrl: 'http://${{ needs.deploy.outputs.storeAdminIp }}' + storeFrontUrl: 'http://${{ needs.deploy.outputs.storeFrontIp }}' + + teardown: + if: always() + needs: playwright-tests + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + + - uses: actions/cache@v3 + with: + path: | + .azure/ + key: ${{ runner.os }}-azd-${{ hashFiles('infra/**') }}-${{ env.BUST_CACHE }}-${{ github.sha }} + + - name: Install azd + uses: Azure/setup-azd@v0.1.0 + + - name: Install Nodejs + uses: actions/setup-node@v3 + with: + node-version: 18 + + - name: Login az + uses: azure/login@v1 + with: + creds: ${{ secrets.AZURE_CREDENTIALS }} + + - name: Set az account + uses: azure/CLI@v1 + with: + inlineScript: | + az account set --subscription ${{vars.AZURE_SUBSCRIPTION_ID}} + + - name: Log in with Azure + run: | + $info = $Env:AZURE_CREDENTIALS | ConvertFrom-Json -AsHashtable; + Write-Host "::add-mask::$($info.clientSecret)" + + azd auth login ` + --client-id "$($info.clientId)" ` + --client-secret "$($info.clientSecret)" ` + --tenant-id "$($info.tenantId)" + shell: pwsh + env: + AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }} + + - name: Azd down + run: azd down --no-prompt --force --purge + env: + AZURE_ENV_NAME: ${{ vars.AZURE_ENV_NAME }} + AZURE_LOCATION: ${{ vars.AZURE_LOCATION }} + AZURE_SUBSCRIPTION_ID: ${{ vars.AZURE_SUBSCRIPTION_ID }} + ARM_TENANT_ID: ${{ vars.ARM_TENANT_ID }} + ARM_CLIENT_ID: ${{ vars.ARM_CLIENT_ID }} + ARM_CLIENT_SECRET: ${{ secrets.ARM_CLIENT_SECRET }} \ No newline at end of file diff --git a/.github/workflows/test-playwright.yaml b/.github/workflows/test-playwright.yaml new file mode 100644 index 00000000..44abb195 --- /dev/null +++ b/.github/workflows/test-playwright.yaml @@ -0,0 +1,40 @@ +name: Playwright Tests +on: + workflow_call: + inputs: + storeAdminUrl: + required: true + type: string + storeFrontUrl: + required: true + type: string + +jobs: + playwright-tests: + timeout-minutes: 60 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: 18 + cache: npm + cache-dependency-path: tests/package-lock.json + - name: Install dependencies + run: npm ci + working-directory: tests/ + - name: Install Playwright Browsers + run: npx playwright install --with-deps + working-directory: tests/ + - name: Run Playwright tests + run: npx playwright test + working-directory: tests/ + env: + STORE_ADMIN_URL: ${{ inputs.storeAdminUrl }} + STORE_FRONT_URL: ${{ inputs.storeFrontUrl }} + - uses: actions/upload-artifact@v3 + if: always() + with: + name: playwright-report-store-admin + path: tests/playwright-report/ + retention-days: 30 diff --git a/.gitignore b/.gitignore index 62204235..65cf1454 100644 --- a/.gitignore +++ b/.gitignore @@ -138,4 +138,8 @@ __pycache__/ .vscode **/.vscode .azure -.terraform \ No newline at end of file +.terraform +test-results/ +playwright-report/ +playwright/.cache/ +.env.playwright.local diff --git a/src/product-service/Cargo.lock b/src/product-service/Cargo.lock index 60bbc79a..6656aec8 100644 --- a/src/product-service/Cargo.lock +++ b/src/product-service/Cargo.lock @@ -4,11 +4,11 @@ version = 3 [[package]] name = "actix-codec" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "617a8268e3537fe1d8c9ead925fca49ef6400927ee7bc26750e90ecee14ce4b8" +checksum = "5f7b0a21988c1bf877cf4759ef5ddaac04c1c9fe808c9142ecb78ba97d97a28a" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.2", "bytes", "futures-core", "futures-sink", @@ -21,9 +21,9 @@ dependencies = [ [[package]] name = "actix-cors" -version = "0.6.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b340e9cfa5b08690aae90fb61beb44e9b06f44fe3d0f93781aaa58cfba86245e" +checksum = "0346d8c1f762b41b458ed3145eea914966bb9ad20b9be0d6d463b20d45586370" dependencies = [ "actix-utils", "actix-web", @@ -36,17 +36,17 @@ dependencies = [ [[package]] name = "actix-http" -version = "3.3.1" +version = "3.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2079246596c18b4a33e274ae10c0e50613f4d32a4198e09c7b93771013fed74" +checksum = "129d4c88e98860e1758c5de288d1632b07970a16d59bdf7b8d66053d582bb71f" dependencies = [ "actix-codec", "actix-rt", "actix-service", "actix-utils", - "ahash 0.8.3", + "ahash", "base64", - "bitflags 1.3.2", + "bitflags 2.4.2", "brotli", "bytes", "bytestring", @@ -70,24 +70,24 @@ dependencies = [ "tokio", "tokio-util", "tracing", - "zstd", + "zstd 0.13.0", ] [[package]] name = "actix-macros" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "465a6172cf69b960917811022d8f29bc0b7fa1398bc4f78b3c466673db1213b6" +checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ "quote", - "syn 1.0.109", + "syn 2.0.48", ] [[package]] name = "actix-router" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d66ff4d247d2b160861fa2866457e85706833527840e4133f8f49aa423a38799" +checksum = "d22475596539443685426b6bdadb926ad0ecaefdfc5fb05e5e3441f15463c511" dependencies = [ "bytestring", "http", @@ -98,9 +98,9 @@ dependencies = [ [[package]] name = "actix-rt" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15265b6b8e2347670eb363c47fc8c75208b4a4994b27192f345fcbe707804f3e" +checksum = "28f32d40287d3f402ae0028a9d54bef51af15c8769492826a69d28f81893151d" dependencies = [ "futures-core", "tokio", @@ -108,9 +108,9 @@ dependencies = [ [[package]] name = "actix-server" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e8613a75dd50cc45f473cee3c34d59ed677c0f7b44480ce3b8247d7dc519327" +checksum = "3eb13e7eef0423ea6eab0e59f6c72e7cb46d33691ad56a726b3cd07ddec2c2d4" dependencies = [ "actix-rt", "actix-service", @@ -118,7 +118,6 @@ dependencies = [ "futures-core", "futures-util", "mio", - "num_cpus", "socket2", "tokio", "tracing", @@ -147,9 +146,9 @@ dependencies = [ [[package]] name = "actix-web" -version = "4.3.1" +version = "4.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd3cb42f9566ab176e1ef0b8b3a896529062b4efc6be0123046095914c4c1c96" +checksum = "e43428f3bf11dee6d166b00ec2df4e3aa8cc1606aaa0b7433c146852e2f4e03b" dependencies = [ "actix-codec", "actix-http", @@ -160,7 +159,7 @@ dependencies = [ "actix-service", "actix-utils", "actix-web-codegen", - "ahash 0.7.6", + "ahash", "bytes", "bytestring", "cfg-if", @@ -169,7 +168,6 @@ dependencies = [ "encoding_rs", "futures-core", "futures-util", - "http", "itoa", "language-tags", "log", @@ -188,50 +186,49 @@ dependencies = [ [[package]] name = "actix-web-codegen" -version = "4.2.0" +version = "4.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2262160a7ae29e3415554a3f1fc04c764b1540c116aa524683208078b7a75bc9" +checksum = "eb1f50ebbb30eca122b188319a4398b3f7bb4a8cdf50ecfb73bfc6a3c3ce54f5" dependencies = [ "actix-router", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.48", ] [[package]] -name = "adler" -version = "1.0.2" +name = "addr2line" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] [[package]] -name = "ahash" -version = "0.7.6" +name = "adler" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" -dependencies = [ - "getrandom", - "once_cell", - "version_check", -] +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "ahash" -version = "0.8.3" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01" dependencies = [ "cfg-if", "getrandom", "once_cell", "version_check", + "zerocopy", ] [[package]] name = "aho-corasick" -version = "1.0.2" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" dependencies = [ "memchr", ] @@ -251,17 +248,79 @@ dependencies = [ "alloc-no-stdlib", ] +[[package]] +name = "ambient-authority" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9d4ee0d472d1cd2e28c97dfa124b3d8d992e10eb0a035f33f5d12e3a177ba3b" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" + +[[package]] +name = "arbitrary" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" + +[[package]] +name = "async-trait" +version = "0.1.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + [[package]] name = "base64" -version = "0.21.2" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "bincode" +version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] [[package]] name = "bitflags" @@ -286,9 +345,9 @@ dependencies = [ [[package]] name = "brotli" -version = "3.3.4" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1a0b1dbcc8ae29329621f8d4f0d835787c1c38bb1401979b49d13b0b305ff68" +checksum = "516074a47ef4bce09577a3b379392300159ce5b1ba2e501ff1c819950066100f" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -297,9 +356,9 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "2.3.4" +version = "2.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b6561fd3f895a11e8f72af2cb7d22e08366bebc2b6b57f7744c4bda27034744" +checksum = "4e2e4afe60d7dd600fdd3de8d0f08c2b7ec039712e3b6137ff98b7004e82de4f" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -311,28 +370,112 @@ version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "bytes" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "bytestring" -version = "1.3.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "238e4886760d98c4f899360c834fa93e62cf7f721ac3c2da375cbdf4b8679aae" +checksum = "74d80203ea6b29df88012294f62733de21cfeab47f17b41af3a38bc30a03ee72" dependencies = [ "bytes", ] +[[package]] +name = "cap-fs-ext" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88e341d15ac1029aadce600be764a1a1edafe40e03cde23285bc1d261b3a4866" +dependencies = [ + "cap-primitives", + "cap-std", + "io-lifetimes", + "windows-sys 0.52.0", +] + +[[package]] +name = "cap-net-ext" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "434168fe6533055f0f4204039abe3ff6d7db338ef46872a5fa39e9d5ad5ab7a9" +dependencies = [ + "cap-primitives", + "cap-std", + "rustix", + "smallvec", +] + +[[package]] +name = "cap-primitives" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe16767ed8eee6d3f1f00d6a7576b81c226ab917eb54b96e5f77a5216ef67abb" +dependencies = [ + "ambient-authority", + "fs-set-times", + "io-extras", + "io-lifetimes", + "ipnet", + "maybe-owned", + "rustix", + "windows-sys 0.52.0", + "winx", +] + +[[package]] +name = "cap-rand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20e5695565f0cd7106bc3c7170323597540e772bb73e0be2cd2c662a0f8fa4ca" +dependencies = [ + "ambient-authority", + "rand", +] + +[[package]] +name = "cap-std" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "593db20e4c51f62d3284bae7ee718849c3214f93a3b94ea1899ad85ba119d330" +dependencies = [ + "cap-primitives", + "io-extras", + "io-lifetimes", + "rustix", +] + +[[package]] +name = "cap-time-ext" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03261630f291f425430a36f38c847828265bc928f517cdd2004c56f4b02f002b" +dependencies = [ + "ambient-authority", + "cap-primitives", + "iana-time-zone", + "once_cell", + "rustix", + "winx", +] + [[package]] name = "cc" -version = "1.0.79" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" dependencies = [ "jobserver", + "libc", ] [[package]] @@ -374,13 +517,121 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +[[package]] +name = "cpp_demangle" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eeaa953eaad386a53111e47172c2fedba671e5684c8dd601a5f474f4f118710f" +dependencies = [ + "cfg-if", +] + [[package]] name = "cpufeatures" -version = "0.2.7" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e4c1eaa2012c47becbbad2ab175484c2a84d1185b566fb2cc5b8707343dfe58" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "cranelift-bforest" +version = "0.102.1" +source = "git+https://github.com/bytecodealliance/wasmtime?branch=release-15.0.0#d2d52de0884cc79216920831dd1fc5b75ba6739e" +dependencies = [ + "cranelift-entity", +] + +[[package]] +name = "cranelift-codegen" +version = "0.102.1" +source = "git+https://github.com/bytecodealliance/wasmtime?branch=release-15.0.0#d2d52de0884cc79216920831dd1fc5b75ba6739e" +dependencies = [ + "bumpalo", + "cranelift-bforest", + "cranelift-codegen-meta", + "cranelift-codegen-shared", + "cranelift-control", + "cranelift-entity", + "cranelift-isle", + "gimli", + "hashbrown 0.14.3", + "log", + "regalloc2", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cranelift-codegen-meta" +version = "0.102.1" +source = "git+https://github.com/bytecodealliance/wasmtime?branch=release-15.0.0#d2d52de0884cc79216920831dd1fc5b75ba6739e" +dependencies = [ + "cranelift-codegen-shared", +] + +[[package]] +name = "cranelift-codegen-shared" +version = "0.102.1" +source = "git+https://github.com/bytecodealliance/wasmtime?branch=release-15.0.0#d2d52de0884cc79216920831dd1fc5b75ba6739e" + +[[package]] +name = "cranelift-control" +version = "0.102.1" +source = "git+https://github.com/bytecodealliance/wasmtime?branch=release-15.0.0#d2d52de0884cc79216920831dd1fc5b75ba6739e" +dependencies = [ + "arbitrary", +] + +[[package]] +name = "cranelift-entity" +version = "0.102.1" +source = "git+https://github.com/bytecodealliance/wasmtime?branch=release-15.0.0#d2d52de0884cc79216920831dd1fc5b75ba6739e" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "cranelift-frontend" +version = "0.102.1" +source = "git+https://github.com/bytecodealliance/wasmtime?branch=release-15.0.0#d2d52de0884cc79216920831dd1fc5b75ba6739e" +dependencies = [ + "cranelift-codegen", + "log", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cranelift-isle" +version = "0.102.1" +source = "git+https://github.com/bytecodealliance/wasmtime?branch=release-15.0.0#d2d52de0884cc79216920831dd1fc5b75ba6739e" + +[[package]] +name = "cranelift-native" +version = "0.102.1" +source = "git+https://github.com/bytecodealliance/wasmtime?branch=release-15.0.0#d2d52de0884cc79216920831dd1fc5b75ba6739e" dependencies = [ + "cranelift-codegen", "libc", + "target-lexicon", +] + +[[package]] +name = "cranelift-wasm" +version = "0.102.1" +source = "git+https://github.com/bytecodealliance/wasmtime?branch=release-15.0.0#d2d52de0884cc79216920831dd1fc5b75ba6739e" +dependencies = [ + "cranelift-codegen", + "cranelift-entity", + "cranelift-frontend", + "itertools", + "log", + "smallvec", + "wasmparser 0.116.1", + "wasmtime-types", ] [[package]] @@ -392,6 +643,31 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" + [[package]] name = "crypto-common" version = "0.1.6" @@ -402,6 +678,34 @@ dependencies = [ "typenum", ] +[[package]] +name = "ctor" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "debugid" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d" +dependencies = [ + "uuid", +] + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + [[package]] name = "derive_more" version = "0.99.17" @@ -425,20 +729,67 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "directories-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "339ee130d97a610ea5a5872d2bbb130fdf68884ff09d3028b81bec8a1ac23bbc" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + [[package]] name = "encoding_rs" -version = "0.8.32" +version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" dependencies = [ "cfg-if", ] [[package]] name = "env_logger" -version = "0.10.0" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" +checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" dependencies = [ "humantime", "is-terminal", @@ -455,24 +806,19 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.1" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" dependencies = [ - "errno-dragonfly", "libc", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] -name = "errno-dragonfly" -version = "0.1.2" +name = "fallible-iterator" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" -dependencies = [ - "cc", - "libc", -] +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" [[package]] name = "fastrand" @@ -480,11 +826,22 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +[[package]] +name = "fd-lock" +version = "4.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e5768da2206272c81ef0b5e951a41862938a6070da63bcea197899942d3b947" +dependencies = [ + "cfg-if", + "rustix", + "windows-sys 0.52.0", +] + [[package]] name = "flate2" -version = "1.0.26" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" +checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" dependencies = [ "crc32fast", "miniz_oxide", @@ -513,65 +870,120 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] [[package]] -name = "futures-channel" -version = "0.3.28" +name = "fs-set-times" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +checksum = "033b337d725b97690d86893f9de22b67b80dcc4e9ad815f348254c38119db8fb" dependencies = [ - "futures-core", + "io-lifetimes", + "rustix", + "windows-sys 0.52.0", ] [[package]] -name = "futures-core" -version = "0.3.28" +name = "futures" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" [[package]] name = "futures-macro" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.48", ] [[package]] name = "futures-sink" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" [[package]] name = "futures-task" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" [[package]] name = "futures-util" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures-core", "futures-macro", + "futures-sink", "futures-task", "pin-project-lite", "pin-utils", "slab", ] +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "fxprof-processed-profile" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27d12c0aed7f1e24276a241aadc4cb8ea9f83000f34bc062b7cc2d51e3b0fabd" +dependencies = [ + "bitflags 2.4.2", + "debugid", + "fxhash", + "serde", + "serde_json", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -584,15 +996,26 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.10" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" dependencies = [ "cfg-if", "libc", "wasi", ] +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +dependencies = [ + "fallible-iterator", + "indexmap", + "stable_deref_trait", +] + [[package]] name = "h2" version = "0.3.24" @@ -614,30 +1037,39 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash", +] [[package]] -name = "hermit-abi" -version = "0.2.6" +name = "hashbrown" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" dependencies = [ - "libc", + "ahash", ] +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "hermit-abi" -version = "0.3.1" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" +checksum = "5d3d0e0f38255e7fa3cf31335b3a56f05febd18025f4db5ef7a0cfb4f8da651f" [[package]] name = "http" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" dependencies = [ "bytes", "fnv", @@ -663,9 +1095,9 @@ checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" [[package]] name = "httpdate" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "humantime" @@ -710,11 +1142,40 @@ dependencies = [ "tokio-native-tls", ] +[[package]] +name = "iana-time-zone" +version = "0.1.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6a67363e2aa4443928ce15e57ebae94fd8949958fd1223c4cfc0cd473ad7539" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "id-arena" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" + [[package]] name = "idna" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -722,25 +1183,31 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.1.0" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +checksum = "824b2ae422412366ba479e8111fd301f7b5faece8149317bb81925979a53f520" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.14.3", + "serde", ] [[package]] -name = "io-lifetimes" -version = "1.0.11" +name = "io-extras" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +checksum = "c301e73fb90e8a29e600a9f402d095765f74310d582916a952f618836a1bd1ed" dependencies = [ - "hermit-abi 0.3.1", - "libc", - "windows-sys 0.48.0", + "io-lifetimes", + "windows-sys 0.52.0", ] +[[package]] +name = "io-lifetimes" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a611371471e98973dbcab4e0ec66c31a10bc356eeb4d54a0e05eac8158fe38c" + [[package]] name = "ipnet" version = "2.9.0" @@ -749,27 +1216,55 @@ checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" [[package]] name = "is-terminal" -version = "0.4.7" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" +checksum = "0bad00257d07be169d870ab665980b06cdb366d792ad690bf2e76876dc503455" dependencies = [ - "hermit-abi 0.3.1", - "io-lifetimes", - "rustix 0.37.25", - "windows-sys 0.48.0", + "hermit-abi", + "rustix", + "windows-sys 0.52.0", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", ] [[package]] name = "itoa" -version = "1.0.6" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" + +[[package]] +name = "ittapi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b996fe614c41395cdaedf3cf408a9534851090959d90d54a535f675550b64b1" +dependencies = [ + "anyhow", + "ittapi-sys", + "log", +] + +[[package]] +name = "ittapi-sys" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" +checksum = "52f5385394064fa2c886205dba02598013ce83d3e92d33dbdc0c52fe0e7bf4fc" +dependencies = [ + "cc", +] [[package]] name = "jobserver" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" +checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" dependencies = [ "libc", ] @@ -795,17 +1290,28 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +[[package]] +name = "leb128" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" + [[package]] name = "libc" -version = "0.2.146" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] -name = "linux-raw-sys" -version = "0.3.8" +name = "libredox" +version = "0.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" +checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +dependencies = [ + "bitflags 2.4.2", + "libc", + "redox_syscall", +] [[package]] name = "linux-raw-sys" @@ -815,27 +1321,26 @@ checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" [[package]] name = "local-channel" -version = "0.1.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f303ec0e94c6c54447f84f3b0ef7af769858a9c4ef56ef2a986d3dcd4c3fc9c" +checksum = "b6cbc85e69b8df4b8bb8b89ec634e7189099cea8927a276b7384ce5488e53ec8" dependencies = [ "futures-core", "futures-sink", - "futures-util", "local-waker", ] [[package]] name = "local-waker" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e34f76eb3611940e0e7d53a9aaa4e6a3151f69541a282fd0dad5571420c53ff1" +checksum = "4d873d7c67ce09b42110d801813efbc9364414e356be9935700d368351657487" [[package]] name = "lock_api" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" dependencies = [ "autocfg", "scopeguard", @@ -843,15 +1348,48 @@ dependencies = [ [[package]] name = "log" -version = "0.4.19" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "mach" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" +dependencies = [ + "libc", +] + +[[package]] +name = "maybe-owned" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" +checksum = "4facc753ae494aeb6e3c22f839b158aebd4f9270f55cd3c79906c45476c47ab4" [[package]] name = "memchr" -version = "2.5.0" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" + +[[package]] +name = "memfd" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2cffa4ad52c6f791f4f8b15f0c05f9824b2ced1160e88cc393d64fff9a8ac64" +dependencies = [ + "rustix", +] + +[[package]] +name = "memoffset" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +dependencies = [ + "autocfg", +] [[package]] name = "mime" @@ -870,9 +1408,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.8" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" dependencies = [ "libc", "log", @@ -898,27 +1436,45 @@ dependencies = [ "tempfile", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num_cpus" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.2.6", + "hermit-abi", "libc", ] +[[package]] +name = "object" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "crc32fast", + "hashbrown 0.14.3", + "indexmap", + "memchr", +] + [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "openssl" -version = "0.10.62" +version = "0.10.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cde4d2d9200ad5909f8dac647e29482e07c3a35de8a13fce7c9c7747ad9f671" +checksum = "15c9d69dd87a29568d4d017cfe8ec518706046a05184e5aea92d0af890b803c8" dependencies = [ "bitflags 2.4.2", "cfg-if", @@ -937,7 +1493,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.48", ] [[package]] @@ -948,9 +1504,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.98" +version = "0.9.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1665caf8ab2dc9aef43d1c0023bd904633a6a05cb30b0ad59bec2ae986e57a7" +checksum = "22e1bf214306098e4832460f797824c05d25aacdf896f64a985fb0fd992454ae" dependencies = [ "cc", "libc", @@ -970,34 +1526,34 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.8" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-targets 0.48.0", + "windows-targets 0.48.5", ] [[package]] name = "paste" -version = "1.0.12" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" [[package]] name = "percent-encoding" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "pin-utils" @@ -1007,9 +1563,15 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.27" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb" + +[[package]] +name = "powerfmt" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" @@ -1019,9 +1581,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.60" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" dependencies = [ "unicode-ident", ] @@ -1032,18 +1594,32 @@ version = "0.1.0" dependencies = [ "actix-cors", "actix-web", + "anyhow", + "ctor", "env_logger", "futures-util", + "log", "reqwest", "serde", "serde_json", + "wasmtime", + "wasmtime-wasi", +] + +[[package]] +name = "psm" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874" +dependencies = [ + "cc", ] [[package]] name = "quote" -version = "1.0.28" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -1078,20 +1654,76 @@ dependencies = [ "getrandom", ] +[[package]] +name = "rayon" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7237101a77a10773db45d62004a272517633fbcc3df19d96455ede1122e051" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + [[package]] name = "redox_syscall" -version = "0.3.5" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "redox_users" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" +dependencies = [ + "getrandom", + "libredox", + "thiserror", +] + +[[package]] +name = "regalloc2" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad156d539c879b7a24a363a2016d77961786e71f48f2e2fc8302a92abd2429a6" +dependencies = [ + "hashbrown 0.13.2", + "log", + "rustc-hash", + "slice-group-by", + "smallvec", +] + [[package]] name = "regex" -version = "1.8.4" +version = "1.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" +checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" dependencies = [ "aho-corasick", "memchr", @@ -1100,15 +1732,15 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.7.2" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "reqwest" -version = "0.11.23" +version = "0.11.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41" +checksum = "c6920094eb85afde5e4a138be3f2de8bbdf28000f0029e72c45025a56b042251" dependencies = [ "base64", "bytes", @@ -1128,9 +1760,11 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", + "rustls-pemfile", "serde", "serde_json", "serde_urlencoded", + "sync_wrapper", "system-configuration", "tokio", "tokio-native-tls", @@ -1142,6 +1776,18 @@ dependencies = [ "winreg", ] +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustc_version" version = "0.4.0" @@ -1153,36 +1799,33 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.25" +version = "0.38.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4eb579851244c2c03e7c24f501c3432bed80b8f720af1d6e5b0e0f01555a035" +checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.2", "errno", - "io-lifetimes", + "itoa", "libc", - "linux-raw-sys 0.3.8", - "windows-sys 0.48.0", + "linux-raw-sys", + "once_cell", + "windows-sys 0.52.0", ] [[package]] -name = "rustix" -version = "0.38.3" +name = "rustls-pemfile" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac5ffa1efe7548069688cd7028f32591853cd7b5b756d41bcffd2353e4fc75b4" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ - "bitflags 2.4.2", - "errno", - "libc", - "linux-raw-sys 0.4.13", - "windows-sys 0.48.0", + "base64", ] [[package]] name = "ryu" -version = "1.0.13" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" +checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" [[package]] name = "schannel" @@ -1195,9 +1838,9 @@ dependencies = [ [[package]] name = "scopeguard" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "security-framework" @@ -1224,35 +1867,35 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.17" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" +checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" [[package]] name = "serde" -version = "1.0.164" +version = "1.0.196" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" +checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.164" +version = "1.0.196" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" +checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.48", ] [[package]] name = "serde_json" -version = "1.0.96" +version = "1.0.113" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" +checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79" dependencies = [ "itoa", "ryu", @@ -1273,15 +1916,35 @@ dependencies = [ [[package]] name = "sha1" -version = "0.10.5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", "digest", ] +[[package]] +name = "shellexpand" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ccc8076840c4da029af4f87e4e8daeb0fca6b87bbb02e10cb60b791450e11e4" +dependencies = [ + "dirs", +] + [[package]] name = "signal-hook-registry" version = "1.4.1" @@ -1293,32 +1956,50 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] +[[package]] +name = "slice-group-by" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "826167069c09b99d56f31e9ae5c99049e932a98c9dc2dac47645b08dbbf76ba7" + [[package]] name = "smallvec" -version = "1.10.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" [[package]] name = "socket2" -version = "0.4.9" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" dependencies = [ "libc", - "winapi", + "windows-sys 0.48.0", ] [[package]] -name = "syn" -version = "1.0.109" +name = "sptr" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b9b39299b249ad65f3b7e96443bad61c02ca5cd3589f46cb6d610a0fd6c0d6a" + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "syn" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ @@ -1329,15 +2010,21 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.18" +version = "2.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + [[package]] name = "system-configuration" version = "0.5.1" @@ -1359,35 +2046,80 @@ dependencies = [ "libc", ] +[[package]] +name = "system-interface" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0682e006dd35771e392a6623ac180999a9a854b1d4a6c12fb2e804941c2b1f58" +dependencies = [ + "bitflags 2.4.2", + "cap-fs-ext", + "cap-std", + "fd-lock", + "io-lifetimes", + "rustix", + "windows-sys 0.52.0", + "winx", +] + +[[package]] +name = "target-lexicon" +version = "0.12.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69758bda2e78f098e4ccb393021a0963bb3442eac05f135c30f61b7370bbafae" + [[package]] name = "tempfile" -version = "3.8.0" +version = "3.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" +checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa" dependencies = [ "cfg-if", "fastrand", "redox_syscall", - "rustix 0.38.3", - "windows-sys 0.48.0", + "rustix", + "windows-sys 0.52.0", ] [[package]] name = "termcolor" -version = "1.2.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ "winapi-util", ] +[[package]] +name = "thiserror" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "time" -version = "0.3.22" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea9e1b3cf1243ae005d9e74085d4d542f3125458f3a81af210d901dcd7411efd" +checksum = "fe80ced77cbfb4cb91a94bf72b378b4b6791a0d9b7f09d0be747d1bdff4e68bd" dependencies = [ + "deranged", "itoa", + "num-conv", + "powerfmt", "serde", "time-core", "time-macros", @@ -1395,16 +2127,17 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.9" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b" +checksum = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774" dependencies = [ + "num-conv", "time-core", ] @@ -1425,14 +2158,15 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.28.2" +version = "1.35.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94d7b1cfd2aa4011f2de74c2c4c63665e27a71006b0a192dcd2710272e73dfa2" +checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104" dependencies = [ - "autocfg", + "backtrace", "bytes", "libc", "mio", + "num_cpus", "parking_lot", "pin-project-lite", "signal-hook-registry", @@ -1452,9 +2186,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.8" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" dependencies = [ "bytes", "futures-core", @@ -1464,6 +2198,15 @@ dependencies = [ "tracing", ] +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + [[package]] name = "tower-service" version = "0.3.2" @@ -1472,21 +2215,32 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "cfg-if", "log", "pin-project-lite", + "tracing-attributes", "tracing-core", ] +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "tracing-core" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", ] @@ -1499,21 +2253,21 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "typenum" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicode-bidi" -version = "0.3.13" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-ident" -version = "1.0.9" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" @@ -1524,17 +2278,35 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-width" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + [[package]] name = "url" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", "idna", "percent-encoding", ] +[[package]] +name = "uuid" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a" + [[package]] name = "vcpkg" version = "0.2.15" @@ -1562,6 +2334,47 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasi-cap-std-sync" +version = "15.0.1" +source = "git+https://github.com/bytecodealliance/wasmtime?branch=release-15.0.0#d2d52de0884cc79216920831dd1fc5b75ba6739e" +dependencies = [ + "anyhow", + "async-trait", + "cap-fs-ext", + "cap-rand", + "cap-std", + "cap-time-ext", + "fs-set-times", + "io-extras", + "io-lifetimes", + "once_cell", + "rustix", + "system-interface", + "tracing", + "wasi-common", + "windows-sys 0.48.0", +] + +[[package]] +name = "wasi-common" +version = "15.0.1" +source = "git+https://github.com/bytecodealliance/wasmtime?branch=release-15.0.0#d2d52de0884cc79216920831dd1fc5b75ba6739e" +dependencies = [ + "anyhow", + "bitflags 2.4.2", + "cap-rand", + "cap-std", + "io-extras", + "log", + "rustix", + "thiserror", + "tracing", + "wasmtime", + "wiggle", + "windows-sys 0.48.0", +] + [[package]] name = "wasm-bindgen" version = "0.2.90" @@ -1583,7 +2396,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.48", "wasm-bindgen-shared", ] @@ -1617,7 +2430,7 @@ checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.48", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -1628,6 +2441,410 @@ version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b" +[[package]] +name = "wasm-encoder" +version = "0.36.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "822b645bf4f2446b949776ffca47e2af60b167209ffb70814ef8779d299cd421" +dependencies = [ + "leb128", +] + +[[package]] +name = "wasm-encoder" +version = "0.41.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e09bca7d6388637d27fb5edbeab11f56bfabcef8743c55ae34370e1e5030a071" +dependencies = [ + "leb128", +] + +[[package]] +name = "wasmparser" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a58e28b80dd8340cb07b8242ae654756161f6fc8d0038123d679b7b99964fa50" +dependencies = [ + "indexmap", + "semver", +] + +[[package]] +name = "wasmparser" +version = "0.121.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "953cf6a7606ab31382cb1caa5ae403e77ba70c7f8e12eeda167e7040d42bfda8" +dependencies = [ + "bitflags 2.4.2", + "indexmap", + "semver", +] + +[[package]] +name = "wasmprinter" +version = "0.2.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05e32c13c59fdc64d3f6998a1d52eb1d362b6904a88b754190ccb85661ad577a" +dependencies = [ + "anyhow", + "wasmparser 0.121.0", +] + +[[package]] +name = "wasmtime" +version = "15.0.1" +source = "git+https://github.com/bytecodealliance/wasmtime?branch=release-15.0.0#d2d52de0884cc79216920831dd1fc5b75ba6739e" +dependencies = [ + "anyhow", + "async-trait", + "bincode", + "bumpalo", + "cfg-if", + "encoding_rs", + "fxprof-processed-profile", + "indexmap", + "libc", + "log", + "object", + "once_cell", + "paste", + "psm", + "rayon", + "serde", + "serde_derive", + "serde_json", + "target-lexicon", + "wasm-encoder 0.36.2", + "wasmparser 0.116.1", + "wasmtime-cache", + "wasmtime-component-macro", + "wasmtime-component-util", + "wasmtime-cranelift", + "wasmtime-environ", + "wasmtime-fiber", + "wasmtime-jit", + "wasmtime-runtime", + "wasmtime-winch", + "wat", + "windows-sys 0.48.0", +] + +[[package]] +name = "wasmtime-asm-macros" +version = "15.0.1" +source = "git+https://github.com/bytecodealliance/wasmtime?branch=release-15.0.0#d2d52de0884cc79216920831dd1fc5b75ba6739e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "wasmtime-cache" +version = "15.0.1" +source = "git+https://github.com/bytecodealliance/wasmtime?branch=release-15.0.0#d2d52de0884cc79216920831dd1fc5b75ba6739e" +dependencies = [ + "anyhow", + "base64", + "bincode", + "directories-next", + "log", + "rustix", + "serde", + "serde_derive", + "sha2", + "toml", + "windows-sys 0.48.0", + "zstd 0.11.2+zstd.1.5.2", +] + +[[package]] +name = "wasmtime-component-macro" +version = "15.0.1" +source = "git+https://github.com/bytecodealliance/wasmtime?branch=release-15.0.0#d2d52de0884cc79216920831dd1fc5b75ba6739e" +dependencies = [ + "anyhow", + "proc-macro2", + "quote", + "syn 2.0.48", + "wasmtime-component-util", + "wasmtime-wit-bindgen", + "wit-parser", +] + +[[package]] +name = "wasmtime-component-util" +version = "15.0.1" +source = "git+https://github.com/bytecodealliance/wasmtime?branch=release-15.0.0#d2d52de0884cc79216920831dd1fc5b75ba6739e" + +[[package]] +name = "wasmtime-cranelift" +version = "15.0.1" +source = "git+https://github.com/bytecodealliance/wasmtime?branch=release-15.0.0#d2d52de0884cc79216920831dd1fc5b75ba6739e" +dependencies = [ + "anyhow", + "cfg-if", + "cranelift-codegen", + "cranelift-control", + "cranelift-entity", + "cranelift-frontend", + "cranelift-native", + "cranelift-wasm", + "gimli", + "log", + "object", + "target-lexicon", + "thiserror", + "wasmparser 0.116.1", + "wasmtime-cranelift-shared", + "wasmtime-environ", + "wasmtime-versioned-export-macros", +] + +[[package]] +name = "wasmtime-cranelift-shared" +version = "15.0.1" +source = "git+https://github.com/bytecodealliance/wasmtime?branch=release-15.0.0#d2d52de0884cc79216920831dd1fc5b75ba6739e" +dependencies = [ + "anyhow", + "cranelift-codegen", + "cranelift-control", + "cranelift-native", + "gimli", + "object", + "target-lexicon", + "wasmtime-environ", +] + +[[package]] +name = "wasmtime-environ" +version = "15.0.1" +source = "git+https://github.com/bytecodealliance/wasmtime?branch=release-15.0.0#d2d52de0884cc79216920831dd1fc5b75ba6739e" +dependencies = [ + "anyhow", + "cranelift-entity", + "gimli", + "indexmap", + "log", + "object", + "serde", + "serde_derive", + "target-lexicon", + "thiserror", + "wasm-encoder 0.36.2", + "wasmparser 0.116.1", + "wasmprinter", + "wasmtime-component-util", + "wasmtime-types", +] + +[[package]] +name = "wasmtime-fiber" +version = "15.0.1" +source = "git+https://github.com/bytecodealliance/wasmtime?branch=release-15.0.0#d2d52de0884cc79216920831dd1fc5b75ba6739e" +dependencies = [ + "anyhow", + "cc", + "cfg-if", + "rustix", + "wasmtime-asm-macros", + "wasmtime-versioned-export-macros", + "windows-sys 0.48.0", +] + +[[package]] +name = "wasmtime-jit" +version = "15.0.1" +source = "git+https://github.com/bytecodealliance/wasmtime?branch=release-15.0.0#d2d52de0884cc79216920831dd1fc5b75ba6739e" +dependencies = [ + "addr2line", + "anyhow", + "bincode", + "cfg-if", + "cpp_demangle", + "gimli", + "ittapi", + "log", + "object", + "rustc-demangle", + "rustix", + "serde", + "serde_derive", + "target-lexicon", + "wasmtime-environ", + "wasmtime-jit-debug", + "wasmtime-jit-icache-coherence", + "wasmtime-runtime", + "windows-sys 0.48.0", +] + +[[package]] +name = "wasmtime-jit-debug" +version = "15.0.1" +source = "git+https://github.com/bytecodealliance/wasmtime?branch=release-15.0.0#d2d52de0884cc79216920831dd1fc5b75ba6739e" +dependencies = [ + "object", + "once_cell", + "rustix", + "wasmtime-versioned-export-macros", +] + +[[package]] +name = "wasmtime-jit-icache-coherence" +version = "15.0.1" +source = "git+https://github.com/bytecodealliance/wasmtime?branch=release-15.0.0#d2d52de0884cc79216920831dd1fc5b75ba6739e" +dependencies = [ + "cfg-if", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "wasmtime-runtime" +version = "15.0.1" +source = "git+https://github.com/bytecodealliance/wasmtime?branch=release-15.0.0#d2d52de0884cc79216920831dd1fc5b75ba6739e" +dependencies = [ + "anyhow", + "cc", + "cfg-if", + "encoding_rs", + "indexmap", + "libc", + "log", + "mach", + "memfd", + "memoffset", + "paste", + "rand", + "rustix", + "sptr", + "wasm-encoder 0.36.2", + "wasmtime-asm-macros", + "wasmtime-environ", + "wasmtime-fiber", + "wasmtime-jit-debug", + "wasmtime-versioned-export-macros", + "wasmtime-wmemcheck", + "windows-sys 0.48.0", +] + +[[package]] +name = "wasmtime-types" +version = "15.0.1" +source = "git+https://github.com/bytecodealliance/wasmtime?branch=release-15.0.0#d2d52de0884cc79216920831dd1fc5b75ba6739e" +dependencies = [ + "cranelift-entity", + "serde", + "serde_derive", + "thiserror", + "wasmparser 0.116.1", +] + +[[package]] +name = "wasmtime-versioned-export-macros" +version = "15.0.1" +source = "git+https://github.com/bytecodealliance/wasmtime?branch=release-15.0.0#d2d52de0884cc79216920831dd1fc5b75ba6739e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "wasmtime-wasi" +version = "15.0.1" +source = "git+https://github.com/bytecodealliance/wasmtime?branch=release-15.0.0#d2d52de0884cc79216920831dd1fc5b75ba6739e" +dependencies = [ + "anyhow", + "async-trait", + "bitflags 2.4.2", + "bytes", + "cap-fs-ext", + "cap-net-ext", + "cap-rand", + "cap-std", + "cap-time-ext", + "fs-set-times", + "futures", + "io-extras", + "io-lifetimes", + "libc", + "log", + "once_cell", + "rustix", + "system-interface", + "thiserror", + "tokio", + "tracing", + "url", + "wasi-cap-std-sync", + "wasi-common", + "wasmtime", + "wiggle", + "windows-sys 0.48.0", +] + +[[package]] +name = "wasmtime-winch" +version = "15.0.1" +source = "git+https://github.com/bytecodealliance/wasmtime?branch=release-15.0.0#d2d52de0884cc79216920831dd1fc5b75ba6739e" +dependencies = [ + "anyhow", + "cranelift-codegen", + "gimli", + "object", + "target-lexicon", + "wasmparser 0.116.1", + "wasmtime-cranelift-shared", + "wasmtime-environ", + "winch-codegen", +] + +[[package]] +name = "wasmtime-wit-bindgen" +version = "15.0.1" +source = "git+https://github.com/bytecodealliance/wasmtime?branch=release-15.0.0#d2d52de0884cc79216920831dd1fc5b75ba6739e" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "wit-parser", +] + +[[package]] +name = "wasmtime-wmemcheck" +version = "15.0.1" +source = "git+https://github.com/bytecodealliance/wasmtime?branch=release-15.0.0#d2d52de0884cc79216920831dd1fc5b75ba6739e" + +[[package]] +name = "wast" +version = "35.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ef140f1b49946586078353a453a1d28ba90adfc54dde75710bc1931de204d68" +dependencies = [ + "leb128", +] + +[[package]] +name = "wast" +version = "70.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3d5061300042ff5065123dae1e27d00c03f567d34a2937c8472255148a216dc" +dependencies = [ + "bumpalo", + "leb128", + "memchr", + "unicode-width", + "wasm-encoder 0.41.0", +] + +[[package]] +name = "wat" +version = "1.0.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afd7357b6cc46d46a2509c43dcb1dd4131dafbf4e75562d87017b5a05ffad2d6" +dependencies = [ + "wast 70.0.2", +] + [[package]] name = "web-sys" version = "0.3.67" @@ -1638,6 +2855,45 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "wiggle" +version = "15.0.1" +source = "git+https://github.com/bytecodealliance/wasmtime?branch=release-15.0.0#d2d52de0884cc79216920831dd1fc5b75ba6739e" +dependencies = [ + "anyhow", + "async-trait", + "bitflags 2.4.2", + "thiserror", + "tracing", + "wasmtime", + "wiggle-macro", +] + +[[package]] +name = "wiggle-generate" +version = "15.0.1" +source = "git+https://github.com/bytecodealliance/wasmtime?branch=release-15.0.0#d2d52de0884cc79216920831dd1fc5b75ba6739e" +dependencies = [ + "anyhow", + "heck", + "proc-macro2", + "quote", + "shellexpand", + "syn 2.0.48", + "witx", +] + +[[package]] +name = "wiggle-macro" +version = "15.0.1" +source = "git+https://github.com/bytecodealliance/wasmtime?branch=release-15.0.0#d2d52de0884cc79216920831dd1fc5b75ba6739e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", + "wiggle-generate", +] + [[package]] name = "winapi" version = "0.3.9" @@ -1656,9 +2912,9 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" dependencies = [ "winapi", ] @@ -1669,13 +2925,37 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "winch-codegen" +version = "0.13.1" +source = "git+https://github.com/bytecodealliance/wasmtime?branch=release-15.0.0#d2d52de0884cc79216920831dd1fc5b75ba6739e" +dependencies = [ + "anyhow", + "cranelift-codegen", + "gimli", + "regalloc2", + "smallvec", + "target-lexicon", + "wasmparser 0.116.1", + "wasmtime-environ", +] + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.0", +] + [[package]] name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets 0.48.0", + "windows-targets 0.48.5", ] [[package]] @@ -1689,17 +2969,17 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm 0.48.0", - "windows_aarch64_msvc 0.48.0", - "windows_i686_gnu 0.48.0", - "windows_i686_msvc 0.48.0", - "windows_x86_64_gnu 0.48.0", - "windows_x86_64_gnullvm 0.48.0", - "windows_x86_64_msvc 0.48.0", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] [[package]] @@ -1719,9 +2999,9 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" @@ -1731,9 +3011,9 @@ checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" [[package]] name = "windows_aarch64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" @@ -1743,9 +3023,9 @@ checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" [[package]] name = "windows_i686_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" @@ -1755,9 +3035,9 @@ checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" [[package]] name = "windows_i686_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" @@ -1767,9 +3047,9 @@ checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" [[package]] name = "windows_x86_64_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" @@ -1779,9 +3059,9 @@ checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" @@ -1791,9 +3071,9 @@ checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" [[package]] name = "windows_x86_64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" @@ -1811,32 +3091,107 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "winx" +version = "0.36.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9643b83820c0cd246ecabe5fa454dd04ba4fa67996369466d0747472d337346" +dependencies = [ + "bitflags 2.4.2", + "windows-sys 0.52.0", +] + +[[package]] +name = "wit-parser" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df4913a2219096373fd6512adead1fb77ecdaa59d7fc517972a7d30b12f625be" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", +] + +[[package]] +name = "witx" +version = "0.9.1" +source = "git+https://github.com/bytecodealliance/wasmtime?branch=release-15.0.0#d2d52de0884cc79216920831dd1fc5b75ba6739e" +dependencies = [ + "anyhow", + "log", + "thiserror", + "wast 35.0.2", +] + +[[package]] +name = "zerocopy" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "zstd" +version = "0.11.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +dependencies = [ + "zstd-safe 5.0.2+zstd.1.5.2", +] + [[package]] name = "zstd" -version = "0.12.3+zstd.1.5.2" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76eea132fb024e0e13fd9c2f5d5d595d8a967aa72382ac2f9d39fcc95afd0806" +checksum = "bffb3309596d527cfcba7dfc6ed6052f1d39dfbd7c867aa2e865e4a449c10110" dependencies = [ - "zstd-safe", + "zstd-safe 7.0.0", ] [[package]] name = "zstd-safe" -version = "6.0.5+zstd.1.5.4" +version = "5.0.2+zstd.1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d56d9e60b4b1758206c238a10165fbcae3ca37b01744e394c463463f6529d23b" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" dependencies = [ "libc", "zstd-sys", ] +[[package]] +name = "zstd-safe" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43747c7422e2924c11144d5229878b98180ef8b06cca4ab5af37afc8a8d8ea3e" +dependencies = [ + "zstd-sys", +] + [[package]] name = "zstd-sys" -version = "2.0.8+zstd.1.5.5" +version = "2.0.9+zstd.1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5556e6ee25d32df2586c098bbfa278803692a20d0ab9565e049480d52707ec8c" +checksum = "9e16efa8a874a0481a574084d34cc26fdb3b99627480f785888deb6386506656" dependencies = [ "cc", - "libc", "pkg-config", ] diff --git a/src/product-service/Cargo.toml b/src/product-service/Cargo.toml index 1cb1e8f5..1ff48b9f 100644 --- a/src/product-service/Cargo.toml +++ b/src/product-service/Cargo.toml @@ -3,13 +3,25 @@ name = "product-service" version = "0.1.0" edition = "2021" +[[bin]] +path = "src/main.rs" +name = "product-service" + +[lib] +name = "product_service" +path = "src/lib.rs" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] actix-cors = "0.6.4" actix-web = "4.3.1" +log = "0.4.20" env_logger = "0.10.0" futures-util = "0.3.28" reqwest = { version = "0.11.23", features = ["json"] } serde = { version = "1.0.164", features = ["derive"] } serde_json = "1.0.96" +anyhow = "1.0.72" +wasmtime = { git = "https://github.com/bytecodealliance/wasmtime", branch = "release-15.0.0", features = ["component-model"] } +wasmtime-wasi = { git = "https://github.com/bytecodealliance/wasmtime", branch = "release-15.0.0" } +ctor = "0.1.21" diff --git a/src/product-service/WASM_RULES_ENGINE.md b/src/product-service/WASM_RULES_ENGINE.md new file mode 100644 index 00000000..64a08133 --- /dev/null +++ b/src/product-service/WASM_RULES_ENGINE.md @@ -0,0 +1,26 @@ +# Try it + +## Pre-Reqs + +- Rust (tested with v1.74.0) and the correct toolchain for your local system and wasm32-wasi +- cargo component 0.5.0 (`cargo install cargo-component`) +- wasm-tools 1.0.54 compiled locally with the wasmtime dependency set to version = "15.0.1" - it may work as it sits in the repo, but I wanted to make sure all the things were using the same version of wasmtime. + + +## The Commands + +``` +pushd ../sample_rule +cargo component build --release +popd +pushd ../second_rule +cargo component build --release +popd +wasm-tools compose -o rule_engine.wasm -c config.yml ../second-rule/target/wasm32-wasi/release/second_rule.wasm + +cargo run +``` + +Then, using the REST Client extention and the http file in the root of the product-service source, add a product. + +Then, try to update the product with a cost over 100 (the last example in the http file). The action will error. diff --git a/src/product-service/config.yml b/src/product-service/config.yml new file mode 100644 index 00000000..33adf025 --- /dev/null +++ b/src/product-service/config.yml @@ -0,0 +1,3 @@ +dependencies: + aksstoredemo:rules/engine@0.1.1: + path: ../sample-rule/target/wasm32-wasi/release/sample_rule.wasm diff --git a/src/product-service/crates/sample-rule/.gitignore b/src/product-service/crates/sample-rule/.gitignore new file mode 100644 index 00000000..73fab072 --- /dev/null +++ b/src/product-service/crates/sample-rule/.gitignore @@ -0,0 +1,10 @@ +# Generated by Cargo +# will have compiled files and executables +debug/ +target/ + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information +*.pdb diff --git a/src/product-service/crates/sample-rule/Cargo.lock b/src/product-service/crates/sample-rule/Cargo.lock new file mode 100644 index 00000000..fc6af36f --- /dev/null +++ b/src/product-service/crates/sample-rule/Cargo.lock @@ -0,0 +1,81 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "bitflags" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" + +[[package]] +name = "cargo-component-bindings" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab3cf2350ce4e1aaf711114952eb135081d936b76da37f3fe09e87f0a28cabfa" +dependencies = [ + "cargo-component-macro", + "wit-bindgen", +] + +[[package]] +name = "cargo-component-macro" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9149c8ce53e8348be7b673f09a89503077721e9ff6321761d3bba40abefd7b2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "sample-rule" +version = "0.1.0" +dependencies = [ + "cargo-component-bindings", +] + +[[package]] +name = "syn" +version = "2.0.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "wit-bindgen" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0205c6e67438f9d657318e0d7ee407a8017cd7bc5f1636cd4a280d4ccbc8d4a0" +dependencies = [ + "bitflags", +] diff --git a/src/product-service/crates/sample-rule/Cargo.toml b/src/product-service/crates/sample-rule/Cargo.toml new file mode 100644 index 00000000..2b20dd56 --- /dev/null +++ b/src/product-service/crates/sample-rule/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "sample-rule" +version = "0.1.0" +edition = "2021" + +[package.metadata.component] +package = "component:sample-rule" +target = { path = "../product-service/rule_engine.wit", world="rule" } + +[package.metadata.component.dependencies] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +cargo-component-bindings = "0.5.0" + +[lib] +crate-type = ["cdylib"] \ No newline at end of file diff --git a/src/product-service/crates/sample-rule/src/lib.rs b/src/product-service/crates/sample-rule/src/lib.rs new file mode 100644 index 00000000..4e21c1a7 --- /dev/null +++ b/src/product-service/crates/sample-rule/src/lib.rs @@ -0,0 +1,19 @@ +cargo_component_bindings::generate!(); + +use bindings::aksstoredemo::rules::logging; +use bindings::exports::aksstoredemo::rules::engine::{Guest, Product, Error}; + +struct Component; + +impl Guest for Component { + fn execute(input: Product) -> Result { + let logger = logging::get_logger(); + logger.log("Hello from the WASM Rules Engine!"); + logger.log("Checking if the product description is longer than 10 characters..."); + if input.description.len() < 10 { + logger.log("The product description is too short!"); + return Err(Error::InvalidProduct("The product description is too short!".to_string())); + }; + Ok(input) + } +} \ No newline at end of file diff --git a/src/product-service/crates/second-rule/.gitignore b/src/product-service/crates/second-rule/.gitignore new file mode 100644 index 00000000..73fab072 --- /dev/null +++ b/src/product-service/crates/second-rule/.gitignore @@ -0,0 +1,10 @@ +# Generated by Cargo +# will have compiled files and executables +debug/ +target/ + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information +*.pdb diff --git a/src/product-service/crates/second-rule/Cargo.lock b/src/product-service/crates/second-rule/Cargo.lock new file mode 100644 index 00000000..6e6aee0c --- /dev/null +++ b/src/product-service/crates/second-rule/Cargo.lock @@ -0,0 +1,81 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "bitflags" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" + +[[package]] +name = "cargo-component-bindings" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab3cf2350ce4e1aaf711114952eb135081d936b76da37f3fe09e87f0a28cabfa" +dependencies = [ + "cargo-component-macro", + "wit-bindgen", +] + +[[package]] +name = "cargo-component-macro" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9149c8ce53e8348be7b673f09a89503077721e9ff6321761d3bba40abefd7b2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "second-rule" +version = "0.1.0" +dependencies = [ + "cargo-component-bindings", +] + +[[package]] +name = "syn" +version = "2.0.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "wit-bindgen" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0205c6e67438f9d657318e0d7ee407a8017cd7bc5f1636cd4a280d4ccbc8d4a0" +dependencies = [ + "bitflags", +] diff --git a/src/product-service/crates/second-rule/Cargo.toml b/src/product-service/crates/second-rule/Cargo.toml new file mode 100644 index 00000000..76833547 --- /dev/null +++ b/src/product-service/crates/second-rule/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "second-rule" +version = "0.1.0" +edition = "2021" + +[package.metadata.component] +package = "component:second-rule" +target = { path = "../product-service/rule_engine.wit", world="rule-extension" } + +[package.metadata.component.dependencies] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +cargo-component-bindings = "0.5.0" + +[lib] +crate-type = ["cdylib"] \ No newline at end of file diff --git a/src/product-service/crates/second-rule/src/lib.rs b/src/product-service/crates/second-rule/src/lib.rs new file mode 100644 index 00000000..c38a8aad --- /dev/null +++ b/src/product-service/crates/second-rule/src/lib.rs @@ -0,0 +1,17 @@ +cargo_component_bindings::generate!(); + +use bindings::aksstoredemo::rules::{logging, engine as downstream}; +use bindings::exports::aksstoredemo::rules::engine::{Guest, Product, Error}; + +struct Component; + +impl Guest for Component { + fn execute(input: Product) -> Result { + logging::get_logger().log("Checking price to ensure it is lower than $100.00"); + if input.price > 100.0 { + return Err(Error::PricingStandardsViolation("Price is too high!".to_string())); + } + + downstream::execute(&input) + } +} \ No newline at end of file diff --git a/src/product-service/rule_engine.wit b/src/product-service/rule_engine.wit new file mode 100644 index 00000000..79cc24d3 --- /dev/null +++ b/src/product-service/rule_engine.wit @@ -0,0 +1,48 @@ +package aksstoredemo:rules@0.1.1; + +interface types { + record product { + id: s32, + name: string, + price: float32, + description: string, + image: string, + } + + variant error { + engine-internal-error(string), + invalid-product(string), + naming-standards-violation(string), + pricing-standards-violation(string) + } +} + +interface engine { + use types.{product, error}; + + execute: func(input: product) -> result; +} + +interface logging { + resource logger { + log: func(msg: string); + } + + get-logger: func() -> logger; +} + +world service-host { + import logging; + export engine; +} + +world rule { + import logging; + export engine; +} + +world rule-extension { + import logging; + import engine; + export engine; +} diff --git a/src/product-service/src/configuration.rs b/src/product-service/src/configuration.rs new file mode 100644 index 00000000..583e5e0d --- /dev/null +++ b/src/product-service/src/configuration.rs @@ -0,0 +1,64 @@ +use std::env::var; +use std::path::PathBuf; +use std::net::TcpListener; +pub struct Settings { + pub max_size: usize, + pub log_level: String, + pub port: u16, + pub wasm_rules_engine_enabled: bool, + pub wasm_bin_path: PathBuf, + tcp_listener: Option, + pub ai_service_url: String, +} + +impl Settings { + pub fn new() -> Self { + let wasm_bin_path_env = var("WASM_RULE_ENGINE_PATH").unwrap_or_else(|_| "./tests/rule_engine.wasm".to_string()); + let ai_service_url = std::env::var("AI_SERVICE_URL").unwrap_or_else(|_| "http://127.0.0.1:5001".to_string()); + Settings { + max_size: 262_144, + log_level: "info".to_string(), + port: 3002, + wasm_rules_engine_enabled: false, + wasm_bin_path: PathBuf::from(wasm_bin_path_env), + tcp_listener: None, + ai_service_url: ai_service_url.trim_end_matches('/').to_string() + } + } + + pub fn set_wasm_rules_engine(mut self, enable: bool) -> Self { + self.wasm_rules_engine_enabled = self.wasm_rules_engine_enabled || enable; + return self; + } + + pub fn set_port(mut self, port: u16) -> Self { + self.port = port; + return self; + } + + pub fn set_max_size(mut self, max_size: usize) -> Self { + self.max_size = max_size; + return self; + } + + pub fn set_log_level(mut self, log_level: String) -> Self { + self.log_level = log_level; + return self; + } + + pub fn get_tcp_listener(&mut self) -> std::io::Result { + if let Some(listener) = &self.tcp_listener { + return Ok(listener.try_clone()?); + } + else { + let listener = TcpListener::bind(format!("0.0.0.0:{}", self.port))?; + self.tcp_listener = Some(listener.try_clone()?); + return Ok(listener); + } + + } + + + + +} diff --git a/src/product-service/src/data.rs b/src/product-service/src/data.rs new file mode 100644 index 00000000..2e2c9684 --- /dev/null +++ b/src/product-service/src/data.rs @@ -0,0 +1,77 @@ +use crate::model::Product; +use crate::configuration::Settings; + +pub fn fetch_products(_settings: &Settings) -> Vec { + vec![ + Product { + id: 1, + name: "Contoso Catnip's Friend".to_string(), + price: 9.99, + description: "Watch your feline friend embark on a fishing adventure with Contoso Catnip's Friend toy. Packed with irresistible catnip and dangling fish lure.".to_string(), + image: "/placeholder.png".to_string() + }, + Product { + id: 2, + name: "Salty Sailor's Squeaky Squid".to_string(), + price: 6.99, + description: "Let your dog set sail with the Salty Sailor's Squeaky Squid. This interactive toy provides hours of fun, featuring multiple squeakers and crinkle tentacles.".to_string(), + image: "/placeholder.png".to_string() + }, + Product { + id: 3, + name: "Mermaid's Mice Trio".to_string(), + price: 12.99, + description: "Entertain your kitty with the Mermaid's Mice Trio. These adorable plush mice are dressed as mermaids and filled with catnip to captivate their curiosity.".to_string(), + image: "/placeholder.png".to_string() + }, + Product { + id: 4, + name: "Ocean Explorer's Puzzle Ball".to_string(), + price: 11.99, + description: "Challenge your pet's problem-solving skills with the Ocean Explorer's Puzzle Ball. This interactive toy features hidden compartments and treats, providing mental stimulation and entertainment.".to_string(), + image: "/placeholder.png".to_string() + }, + Product { + id: 5, + name: "Pirate Parrot Teaser Wand".to_string(), + price: 8.99, + description: "Engage your cat in a playful pursuit with the Pirate Parrot Teaser Wand. The colorful feathers and jingling bells mimic the mischievous charm of a pirate's parrot.".to_string(), + image: "/placeholder.png".to_string() + }, + Product { + id: 6, + name: "Seafarer's Tug Rope".to_string(), + price: 14.99, + description: "Tug-of-war meets nautical adventure with the Seafarer's Tug Rope. Made from marine-grade rope, it's perfect for interactive play and promoting dental health in dogs.".to_string(), + image: "/placeholder.png".to_string() + }, + Product { + id: 7, + name: "Seashell Snuggle Bed".to_string(), + price: 19.99, + description: "Give your furry friend a cozy spot to curl up with the Seashell Snuggle Bed. Shaped like a seashell, this plush bed provides comfort and relaxation for cats and small dogs.".to_string(), + image: "/placeholder.png".to_string() + }, + Product { + id: 8, + name: "Nautical Knot Ball".to_string(), + price: 7.99, + description: "Unleash your dog's inner sailor with the Nautical Knot Ball. Made from sturdy ropes, it's perfect for fetching, tugging, and satisfying their chewing needs.".to_string(), + image: "/placeholder.png".to_string() + }, + Product { + id: 9, + name: "Contoso Claw's Crabby Cat Toy".to_string(), + price: 3.99, + description: "Watch your cat go crazy for Contoso Claw's Crabby Cat Toy. This crinkly and catnip-filled toy will awaken their hunting instincts and provide endless entertainment.".to_string(), + image: "/placeholder.png".to_string() + }, + Product { + id: 10, + name: "Ahoy Doggy Life Jacket".to_string(), + price: 5.99, + description: "Ensure your furry friend stays safe during water adventures with the Ahoy Doggy Life Jacket. Designed for dogs, this flotation device offers buoyancy and visibility in style.".to_string(), + image: "/placeholder.png".to_string() + } + ] +} \ No newline at end of file diff --git a/src/product-service/src/lib.rs b/src/product-service/src/lib.rs new file mode 100644 index 00000000..6864f675 --- /dev/null +++ b/src/product-service/src/lib.rs @@ -0,0 +1,6 @@ +pub mod startup; +pub mod routes; +pub mod configuration; +pub mod localwasmtime; +pub mod model; +pub mod data; \ No newline at end of file diff --git a/src/product-service/src/localwasmtime/host.rs b/src/product-service/src/localwasmtime/host.rs new file mode 100644 index 00000000..72f5c816 --- /dev/null +++ b/src/product-service/src/localwasmtime/host.rs @@ -0,0 +1,147 @@ +use std::path::Path; + +use log::debug; +use wasmtime::{component::*, Config, Engine, Store}; +use wasmtime_wasi::preview2::command; + +use super::{RulesEngineState, WasmProduct, Error}; + +/// This struct is responsible for hosting the rules engine +/// it consists of a wasmtime component, store, and linker. +/// The store and linker are generics and used to wrap a State struct +/// that is used to store the state of the wasmtime runtime. +pub struct LocalWasmtimeHost { + component: Component, + store: Store, + linker: Linker, +} + +/// The implementation of the LocalWasmtimeHost struct +/// and provides a constructor and execute method. +/// The execute method is a wrapper around a call into the WASM component. +impl LocalWasmtimeHost { + pub fn new(actor_component_path: &Path) -> anyhow::Result { + let config = Self::create_wasmtime_config(); + let engine = Self::create_wasmtime_engine(&config)?; + let component = Self::create_wasmtime_component(&engine, actor_component_path)?; + let store = Store::new( + &engine, + RulesEngineState::new(), + ); + let mut linker:Linker = Linker::new(&engine); + command::sync::add_to_linker(&mut linker)?; + super::ServiceHost::add_to_linker(&mut linker, |state: &mut RulesEngineState| state)?; + Ok(Self { + component, + store, + linker, + }) + } + + /// This method is a wrapper around a call into the WASM component. + /// It takes a Product as an input and returns a Result + /// An EngineInternalError is returned if there is an error instantiating the rules engine + /// Otherwise, the result of the rules engine is returned. + pub fn execute(&mut self, product: WasmProduct) -> Result { + + debug!("Instantiating the rules engine"); + let (bindings, _) = match super::ServiceHost::instantiate(&mut self.store, &self.component, &self.linker) { + Ok(bindings) => bindings, + Err(e) => return Err(Error::EngineInternalError(e.to_string())), + }; + + debug!("Executing rules engine"); + let result = match bindings.aksstoredemo_rules_engine().call_execute(&mut self.store, &product) { + Ok(result) => result, + Err(e) => return Err(Error::EngineInternalError(e.to_string())), + }; + + match result { + Ok(result) => return Ok(result), + Err(e) => return Err(e), + }; + } + + fn create_wasmtime_config() -> Config { + let mut config = Config::new(); + config.wasm_component_model(true); + return config; + } + + fn create_wasmtime_engine(config: &Config) -> anyhow::Result { + return Engine::new(config); + } + + fn create_wasmtime_component(engine: &Engine, actor_component_path: &Path) -> anyhow::Result { + return Component::from_file(&engine, actor_component_path); + } +} + +#[cfg(test)] +mod tests { + use super::*; + use super::super::{WasmProduct, Error}; + use std::path::PathBuf; + use std::env; + + fn setup() -> LocalWasmtimeHost { + let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + path.push("./tests/rule_engine.wasm"); + LocalWasmtimeHost::new(&path).unwrap() + + } + + #[test] + fn test_execute() { + let mut host = setup(); + let product = WasmProduct { + id: 123, + name: "Test Product".to_string(), + price: 15.0, + description: "This is longer than 10 characters".to_string(), + image: "/placeholder.png".to_string(), + }; + let result = host.execute(product).unwrap(); + assert_eq!(result.id, 123); + assert_eq!(result.name, "Test Product".to_string()); + assert_eq!(result.price, 15.0); + assert_eq!(result.description, "This is longer than 10 characters".to_string()); + assert_eq!(result.image, "/placeholder.png".to_string()); + } + + #[test] + fn test_execute_too_short_description() { + let mut host = setup(); + let product = WasmProduct { + id: 123, + name: "Test Product".to_string(), + price: 15.0, + description: "Too short".to_string(), + image: "/placeholder.png".to_string(), + }; + let result = host.execute(product); + assert!(result.is_err()); + match result.unwrap_err() { + Error::InvalidProduct(error_message) => assert_eq!(error_message, "The product description is too short!"), + _ => panic!("Unexpected error type"), + } + } + + #[test] + fn test_execute_too_high_price() { + let mut host = setup(); + let product = WasmProduct { + id: 123, + name: "Test Product".to_string(), + price: 1000.0, + description: "This is longer than 10 characters".to_string(), + image: "/placeholder.png".to_string(), + }; + let result = host.execute(product); + assert!(result.is_err()); + match result.unwrap_err() { + Error::PricingStandardsViolation(error_message) => assert_eq!(error_message, "Price is too high!"), + _ => panic!("Unexpected error type"), + } + } +} \ No newline at end of file diff --git a/src/product-service/src/localwasmtime/mod.rs b/src/product-service/src/localwasmtime/mod.rs new file mode 100644 index 00000000..14caf253 --- /dev/null +++ b/src/product-service/src/localwasmtime/mod.rs @@ -0,0 +1,42 @@ +mod rules_engine_state; +mod host; + +wasmtime::component::bindgen!({ + path: "rule_engine.wit", + world: "service-host" +}); + +use std::path::Path; + +use log::info; +use crate::model::Product; +use crate::configuration::Settings; + +pub use rules_engine_state::RulesEngineState; +pub use host::LocalWasmtimeHost; +pub use aksstoredemo::rules::types::{Product as WasmProduct, Error}; + + +fn wasm_bin_path_exists(wasm_bin_path: &Path) -> bool { + let wasm_bin_path_exists = wasm_bin_path.exists(); + info!("WASM rules engine path exists: {}", wasm_bin_path_exists); + return wasm_bin_path_exists; +} + +pub fn validate_product(settings: &Settings, product: &Product) -> Result{ + + let wasm_bin_path = settings.wasm_bin_path.clone(); + + if settings.wasm_rules_engine_enabled && wasm_bin_path_exists(&wasm_bin_path) { + let mut host = LocalWasmtimeHost::new(&wasm_bin_path).unwrap(); + let wasm_product: WasmProduct = product.clone().into(); + let wasm_product = host.execute(wasm_product)?; + let validated_product = wasm_product.into(); + return Ok(validated_product); + } + else { + return Ok(product.clone()) + } +} + + diff --git a/src/product-service/src/localwasmtime/rules_engine_state.rs b/src/product-service/src/localwasmtime/rules_engine_state.rs new file mode 100644 index 00000000..e69fe0ae --- /dev/null +++ b/src/product-service/src/localwasmtime/rules_engine_state.rs @@ -0,0 +1,79 @@ + +use wasmtime_wasi::preview2::{WasiView, Table, WasiCtx, WasiCtxBuilder}; +use wasmtime::component::*; + +use super::aksstoredemo::rules::logging::{self, HostLogger}; +use super::aksstoredemo::rules::types::Host as HostTypes; +use log::info; + +pub struct RulesEngineState { + table: Table, + wasi_ctx: WasiCtx, +} + +impl RulesEngineState { + pub fn new() -> Self { + let wasi_ctx = WasiCtxBuilder::new().inherit_stdio().build(); + let table = Table::new(); + Self { + table, + wasi_ctx, + } + } +} + +impl WasiView for RulesEngineState { + fn table(&self) -> &Table { + return &self.table; + } + + fn table_mut(&mut self) -> &mut Table { + return &mut self.table; + } + + fn ctx(&self) -> &WasiCtx { + return &self.wasi_ctx; + } + + fn ctx_mut(&mut self) -> &mut WasiCtx { + return &mut self.wasi_ctx; + } +} + + +impl HostLogger for RulesEngineState { + fn log(&mut self, + this: Resource, + message: String + ) -> anyhow::Result<()> { + let resource: Resource = Resource::new_own(this.rep()); + self + .table() + .get::(&resource)?; + + info!("{}", message); + Ok(()) + } + fn drop(&mut self, this: Resource) -> anyhow::Result<()> { + let resource: Resource = Resource::new_own(this.rep()); + Ok(self + .table_mut() + .delete::(resource) + .map(|_| ())?) + } +} + +impl HostTypes for RulesEngineState { +} + + +struct MyLogger; + +impl logging::Host for RulesEngineState { + fn get_logger(&mut self) -> anyhow::Result> { + let resource = self.table_mut().push::(MyLogger)?; + Ok(Resource::new_own( + resource.rep(), + )) + } +} \ No newline at end of file diff --git a/src/product-service/src/main.rs b/src/product-service/src/main.rs index 9b59b4e0..0acd8617 100644 --- a/src/product-service/src/main.rs +++ b/src/product-service/src/main.rs @@ -1,311 +1,14 @@ -use actix_cors::Cors; -use actix_web::middleware::Logger; -use actix_web::{ - error, error::ResponseError, middleware, web, App, Error, HttpResponse, HttpServer, +use product_service::{ + configuration::Settings, + startup::run }; use env_logger::Env; -use futures_util::StreamExt; -use serde::{Deserialize, Serialize}; -use serde_json::json; -use std::collections::HashMap; -use std::fmt; -use std::sync::Mutex; - -const MAX_SIZE: usize = 262_144; // max payload size is 256k - -async fn health() -> Result { - let version = std::env::var("APP_VERSION").unwrap_or_else(|_| "0.1.0".to_string()); - let health = json!({"status": "ok", "version": version}); - Ok(HttpResponse::Ok().json(health)) -} - -async fn get_product( - data: web::Data, - path: web::Path, -) -> Result { - let products = data.products.lock().unwrap(); - - // find product by id in products - let index = products - .iter() - .position(|p| p.id == path.product_id) - .unwrap(); - - Ok(HttpResponse::Ok().json(products[index].clone())) -} - -async fn get_products(data: web::Data) -> Result { - let products = data.products.lock().unwrap(); - Ok(HttpResponse::Ok().json(products.to_vec())) -} - -async fn add_product( - data: web::Data, - mut payload: web::Payload, -) -> Result { - let mut products = data.products.lock().unwrap(); - let new_id = products.len() as i32 + 1; - - // payload is a stream of Bytes objects - let mut body = web::BytesMut::new(); - while let Some(chunk) = payload.next().await { - let chunk = chunk?; - // limit max size of in-memory payload - if (body.len() + chunk.len()) > MAX_SIZE { - return Err(error::ErrorBadRequest("overflow")); - } - body.extend_from_slice(&chunk); - } - - // body is loaded, now we can deserialize serde-json - let mut product = serde_json::from_slice::(&body)?; - - // update product id - product.id = new_id; - - // add product to products - products.push(product.clone()); - - Ok(HttpResponse::Ok().json(product)) -} - -async fn update_product( - data: web::Data, - mut payload: web::Payload, -) -> Result { - let mut products = data.products.lock().unwrap(); - - // payload is a stream of Bytes objects - let mut body = web::BytesMut::new(); - while let Some(chunk) = payload.next().await { - let chunk = chunk?; - // limit max size of in-memory payload - if (body.len() + chunk.len()) > MAX_SIZE { - return Err(error::ErrorBadRequest("overflow")); - } - body.extend_from_slice(&chunk); - } - - // body is loaded, now we can deserialize serde-json - let product = serde_json::from_slice::(&body)?; - - // replace product with same id - let index = products.iter().position(|p| p.id == product.id).unwrap(); - products[index] = product.clone(); - - Ok(HttpResponse::Ok().json(product)) -} - -async fn delete_product( - data: web::Data, - path: web::Path, -) -> Result { - let mut products = data.products.lock().unwrap(); - - // find product by id in products - let index = products - .iter() - .position(|p| p.id == path.product_id) - .unwrap(); - - // remove product from products - products.remove(index); - - Ok(HttpResponse::Ok().body("")) -} - -////////////////////////// -// Proxy for AI service -////////////////////////// - -#[derive(Debug)] -struct ProxyError(reqwest::Error); - -impl fmt::Display for ProxyError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.0) - } -} - -impl ResponseError for ProxyError { - fn error_response(&self) -> HttpResponse { - HttpResponse::InternalServerError().json(self.0.to_string()) - } -} - -impl From for ProxyError { - fn from(err: reqwest::Error) -> ProxyError { - ProxyError(err) - } -} - -fn get_ai_service_url() -> String { - let ai_service_url = std::env::var("AI_SERVICE_URL").unwrap_or_else(|_| "http://127.0.0.1:5001".to_string()); - ai_service_url.trim_end_matches('/').to_string() -} - -async fn ai_health() -> Result { - let client = reqwest::Client::new(); - let resp = client.get(get_ai_service_url() + "/health").send().await.unwrap(); - let status = resp.status(); - if status.is_success() { - let body: HashMap = resp.json().await.map_err(ProxyError::from)?; - let body_json = serde_json::to_string(&body).unwrap(); - Ok(HttpResponse::Ok().body(body_json)) - } else { - Ok(HttpResponse::build(actix_web::http::StatusCode::NOT_FOUND).body("")) - } -} - -async fn ai_generate_description(mut payload: web::Payload) -> Result { - let mut body = web::BytesMut::new(); - while let Some(chunk) = payload.next().await { - let chunk = chunk?; - body.extend_from_slice(&chunk); - } - let client = reqwest::Client::new(); - let resp = client - .post(get_ai_service_url() + "/generate/description") - .body(body.to_vec()) - .send() - .await - .unwrap(); - - let status = resp.status(); - let body: HashMap = resp.json().await.map_err(ProxyError::from)?; - let body_json = serde_json::to_string(&body).unwrap(); - if status.is_success() { - Ok(HttpResponse::Ok().body(body_json)) - } else { - Ok(HttpResponse::build(actix_web::http::StatusCode::INTERNAL_SERVER_ERROR).body(body_json)) - } -} #[actix_web::main] async fn main() -> std::io::Result<()> { - let products = vec![ - Product { - id: 1, - name: "Contoso Catnip's Friend".to_string(), - price: 9.99, - description: "Watch your feline friend embark on a fishing adventure with Contoso Catnip's Friend toy. Packed with irresistible catnip and dangling fish lure.".to_string(), - image: "/placeholder.png".to_string() - }, - Product { - id: 2, - name: "Salty Sailor's Squeaky Squid".to_string(), - price: 6.99, - description: "Let your dog set sail with the Salty Sailor's Squeaky Squid. This interactive toy provides hours of fun, featuring multiple squeakers and crinkle tentacles.".to_string(), - image: "/placeholder.png".to_string() - }, - Product { - id: 3, - name: "Mermaid's Mice Trio".to_string(), - price: 12.99, - description: "Entertain your kitty with the Mermaid's Mice Trio. These adorable plush mice are dressed as mermaids and filled with catnip to captivate their curiosity.".to_string(), - image: "/placeholder.png".to_string() - }, - Product { - id: 4, - name: "Ocean Explorer's Puzzle Ball".to_string(), - price: 11.99, - description: "Challenge your pet's problem-solving skills with the Ocean Explorer's Puzzle Ball. This interactive toy features hidden compartments and treats, providing mental stimulation and entertainment.".to_string(), - image: "/placeholder.png".to_string() - }, - Product { - id: 5, - name: "Pirate Parrot Teaser Wand".to_string(), - price: 8.99, - description: "Engage your cat in a playful pursuit with the Pirate Parrot Teaser Wand. The colorful feathers and jingling bells mimic the mischievous charm of a pirate's parrot.".to_string(), - image: "/placeholder.png".to_string() - }, - Product { - id: 6, - name: "Seafarer's Tug Rope".to_string(), - price: 14.99, - description: "Tug-of-war meets nautical adventure with the Seafarer's Tug Rope. Made from marine-grade rope, it's perfect for interactive play and promoting dental health in dogs.".to_string(), - image: "/placeholder.png".to_string() - }, - Product { - id: 7, - name: "Seashell Snuggle Bed".to_string(), - price: 19.99, - description: "Give your furry friend a cozy spot to curl up with the Seashell Snuggle Bed. Shaped like a seashell, this plush bed provides comfort and relaxation for cats and small dogs.".to_string(), - image: "/placeholder.png".to_string() - }, - Product { - id: 8, - name: "Nautical Knot Ball".to_string(), - price: 7.99, - description: "Unleash your dog's inner sailor with the Nautical Knot Ball. Made from sturdy ropes, it's perfect for fetching, tugging, and satisfying their chewing needs.".to_string(), - image: "/placeholder.png".to_string() - }, - Product { - id: 9, - name: "Contoso Claw's Crabby Cat Toy".to_string(), - price: 3.99, - description: "Watch your cat go crazy for Contoso Claw's Crabby Cat Toy. This crinkly and catnip-filled toy will awaken their hunting instincts and provide endless entertainment.".to_string(), - image: "/placeholder.png".to_string() - }, - Product { - id: 10, - name: "Ahoy Doggy Life Jacket".to_string(), - price: 5.99, - description: "Ensure your furry friend stays safe during water adventures with the Ahoy Doggy Life Jacket. Designed for dogs, this flotation device offers buoyancy and visibility in style.".to_string(), - image: "/placeholder.png".to_string() - } - ]; - - let product_state = web::Data::new(AppState { - products: Mutex::new(products.to_vec()), - }); - - println!("Listening on http://0.0.0.0:3002"); - - env_logger::init_from_env(Env::default().default_filter_or("info")); - - HttpServer::new(move || { - let cors = Cors::permissive(); - - App::new() - .wrap(cors) - .wrap(Logger::default()) - .wrap(Logger::new("%a %{User-Agent}i")) - .wrap(middleware::DefaultHeaders::new().add(("X-Version", "0.2"))) - .app_data(product_state.clone()) - .route("/health", web::get().to(health)) - .route("/health", web::head().to(health)) - .route("/{product_id}", web::get().to(get_product)) - .route("/", web::get().to(get_products)) - .route("/", web::post().to(add_product)) - .route("/", web::put().to(update_product)) - .route("/{product_id}", web::delete().to(delete_product)) - .route("/ai/health", web::get().to(ai_health)) - .route("/ai/health", web::head().to(ai_health)) - .route( - "/ai/generate/description", - web::post().to(ai_generate_description), - ) - }) - .bind(("0.0.0.0", 3002))? - .run() - .await -} - -struct AppState { - products: Mutex>, -} - -#[derive(Serialize, Deserialize, Clone)] -struct Product { - id: i32, - name: String, - price: f32, - description: String, - image: String, -} -#[derive(Deserialize)] -struct ProductInfo { - product_id: i32, + let settings = Settings::new() + .set_wasm_rules_engine(false); + env_logger::init_from_env(Env::default().default_filter_or(&settings.log_level)); + run(settings)?.await } diff --git a/src/product-service/src/model.rs b/src/product-service/src/model.rs new file mode 100644 index 00000000..e090d83c --- /dev/null +++ b/src/product-service/src/model.rs @@ -0,0 +1,41 @@ +use serde::{Deserialize, Serialize}; +use crate::localwasmtime::WasmProduct; + +#[derive(Serialize, Deserialize, Clone)] +pub struct Product { + pub id: i32, + pub name: String, + pub price: f32, + pub description: String, + pub image: String, +} + +#[derive(Deserialize)] +pub struct ProductInfo { + pub product_id: i32, +} + + +impl Into for Product { + fn into(self) -> WasmProduct { + WasmProduct { + id: self.id, + name: self.name, + description: self.description, + price: self.price, + image: self.image, + } + } +} + +impl From for Product { + fn from(product: WasmProduct) -> Self { + Self { + id: product.id, + name: product.name, + description: product.description, + price: product.price, + image: product.image, + } + } +} diff --git a/src/product-service/src/routes/add.rs b/src/product-service/src/routes/add.rs new file mode 100644 index 00000000..4bda5d89 --- /dev/null +++ b/src/product-service/src/routes/add.rs @@ -0,0 +1,43 @@ +use actix_web::{error, web, Error, HttpResponse}; +use crate::model::Product; +use crate::startup::AppState; +use futures_util::StreamExt; +use crate::localwasmtime::validate_product; + +pub async fn add_product( + data: web::Data, + mut payload: web::Payload, +) -> Result { + let mut products = data.products.lock().unwrap(); + let new_id = products.len() as i32 + 1; + + // payload is a stream of Bytes objects + let mut body = web::BytesMut::new(); + while let Some(chunk) = payload.next().await { + let chunk = chunk?; + // limit max size of in-memory payload + if (body.len() + chunk.len()) > data.settings.max_size { + return Err(error::ErrorBadRequest("overflow")); + } + body.extend_from_slice(&chunk); + } + + // body is loaded, now we can deserialize serde-json + let mut product = serde_json::from_slice::(&body)?; + + // update product id + product.id = new_id; + + // Add rules engine evaluation here + match validate_product(&data.settings, &product) { + Ok(validated_product) => { + // add product to products + products.push(validated_product.clone()); + + Ok(HttpResponse::Ok().json(validated_product)) + } + Err(e) => { + Ok(HttpResponse::BadRequest().body(e.to_string())) + } + } +} \ No newline at end of file diff --git a/src/product-service/src/routes/ai.rs b/src/product-service/src/routes/ai.rs new file mode 100644 index 00000000..b48132cb --- /dev/null +++ b/src/product-service/src/routes/ai.rs @@ -0,0 +1,77 @@ +////////////////////////// +// Proxy for AI service +////////////////////////// + +use std::collections::HashMap; +use std::fmt; +use actix_web::{web, Error, HttpResponse, ResponseError}; +use crate::startup::AppState; +use futures_util::StreamExt; + +#[derive(Debug)] +pub struct ProxyError(reqwest::Error); + +impl fmt::Display for ProxyError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.0) + } +} + +impl ResponseError for ProxyError { + fn error_response(&self) -> HttpResponse { + HttpResponse::InternalServerError().json(self.0.to_string()) + } +} + +impl From for ProxyError { + fn from(err: reqwest::Error) -> ProxyError { + ProxyError(err) + } +} + +pub async fn ai_health(data: web::Data) -> Result { + let client = reqwest::Client::new(); + let ai_service_url = data.settings.ai_service_url.to_owned(); + let resp = match client.get(ai_service_url + "/health").send().await { + Ok(resp) => resp, + Err(e) => { + return Ok(HttpResponse::InternalServerError().json(e.to_string())) + } + }; + let status = resp.status(); + if status.is_success() { + let body: HashMap = resp.json().await.map_err(ProxyError::from)?; + let body_json = serde_json::to_string(&body).unwrap(); + Ok(HttpResponse::Ok().body(body_json)) + } else { + Ok(HttpResponse::build(actix_web::http::StatusCode::NOT_FOUND).body("")) + } +} + +pub async fn ai_generate_description(data: web::Data, mut payload: web::Payload) -> Result { + let mut body = web::BytesMut::new(); + while let Some(chunk) = payload.next().await { + let chunk = chunk?; + body.extend_from_slice(&chunk); + } + let client = reqwest::Client::new(); + let ai_service_url = data.settings.ai_service_url.to_owned(); + let resp = match client.post( ai_service_url + "/generate/description") + .body(body.to_vec()) + .send() + .await { + Ok(resp) => resp, + Err(e) => { + return Ok(HttpResponse::InternalServerError().json(e.to_string())) + } + }; + + let status = resp.status(); + let body: HashMap = resp.json().await.map_err(ProxyError::from)?; + let body_json = serde_json::to_string(&body).unwrap(); + if status.is_success() { + Ok(HttpResponse::Ok().body(body_json)) + } else { + Ok(HttpResponse::build(actix_web::http::StatusCode::INTERNAL_SERVER_ERROR).body(body_json)) + } +} \ No newline at end of file diff --git a/src/product-service/src/routes/delete.rs b/src/product-service/src/routes/delete.rs new file mode 100644 index 00000000..de3d7373 --- /dev/null +++ b/src/product-service/src/routes/delete.rs @@ -0,0 +1,21 @@ +use crate::model::ProductInfo; +use crate::startup::AppState; +use actix_web::{web, Error, HttpResponse}; + +pub async fn delete_product( + data: web::Data, + path: web::Path, +) -> Result { + let mut products = data.products.lock().unwrap(); + + // find product by id in products + let index = products + .iter() + .position(|p| p.id == path.product_id) + .unwrap(); + + // remove product from products + products.remove(index); + + Ok(HttpResponse::Ok().body("")) +} \ No newline at end of file diff --git a/src/product-service/src/routes/get.rs b/src/product-service/src/routes/get.rs new file mode 100644 index 00000000..57bd8ab3 --- /dev/null +++ b/src/product-service/src/routes/get.rs @@ -0,0 +1,26 @@ +use crate::model::ProductInfo; +use crate::startup::AppState; +use actix_web::{web, Error, HttpResponse}; + +pub async fn get_product( + data: web::Data, + path: web::Path, +) -> Result { + let products = data.products.lock().unwrap(); + + // find product by id in products + let index = products + .iter() + .position(|p| p.id == path.product_id); + if let Some(i) = index { + return Ok(HttpResponse::Ok().json(products[i].clone())) + } + else { + return Ok(HttpResponse::NotFound().body("Product not found")) + } +} + +pub async fn get_products(data: web::Data) -> Result { + let products = data.products.lock().unwrap(); + Ok(HttpResponse::Ok().json(products.to_vec())) +} \ No newline at end of file diff --git a/src/product-service/src/routes/health.rs b/src/product-service/src/routes/health.rs new file mode 100644 index 00000000..8ed89bb4 --- /dev/null +++ b/src/product-service/src/routes/health.rs @@ -0,0 +1,8 @@ +use actix_web::{Error, HttpResponse}; +use serde_json::json; + +pub async fn health() -> Result { + let version = std::env::var("APP_VERSION").unwrap_or_else(|_| "0.1.0".to_string()); + let health = json!({"status": "ok", "version": version}); + Ok(HttpResponse::Ok().json(health)) +} \ No newline at end of file diff --git a/src/product-service/src/routes/mod.rs b/src/product-service/src/routes/mod.rs new file mode 100644 index 00000000..8ed075c1 --- /dev/null +++ b/src/product-service/src/routes/mod.rs @@ -0,0 +1,13 @@ +mod add; +mod delete; +mod get; +mod update; +mod health; +mod ai; + +pub use add::*; +pub use delete::*; +pub use get::*; +pub use update::*; +pub use health::*; +pub use ai::*; diff --git a/src/product-service/src/routes/update.rs b/src/product-service/src/routes/update.rs new file mode 100644 index 00000000..836036d8 --- /dev/null +++ b/src/product-service/src/routes/update.rs @@ -0,0 +1,39 @@ +use actix_web::{error, web, Error, HttpResponse}; +use crate::model::Product; +use crate::startup::AppState; +use futures_util::StreamExt; +use crate::localwasmtime::validate_product; + +pub async fn update_product( + data: web::Data, + mut payload: web::Payload, +) -> Result { + let mut products = data.products.lock().unwrap(); + + // payload is a stream of Bytes objects + let mut body = web::BytesMut::new(); + while let Some(chunk) = payload.next().await { + let chunk = chunk?; + // limit max size of in-memory payload + if (body.len() + chunk.len()) > data.settings.max_size { + return Err(error::ErrorBadRequest("overflow")); + } + body.extend_from_slice(&chunk); + } + + // body is loaded, now we can deserialize serde-json + let product = serde_json::from_slice::(&body)?; + + match validate_product(&data.settings, &product) { + Ok(validated_product) => { + // replace product with same id + let index = products.iter().position(|p| p.id == product.id).unwrap(); + products[index] = validated_product.clone(); + + Ok(HttpResponse::Ok().json(validated_product)) + } + Err(e) => { + Ok(HttpResponse::BadRequest().body(e.to_string())) + } + } +} \ No newline at end of file diff --git a/src/product-service/src/startup.rs b/src/product-service/src/startup.rs new file mode 100644 index 00000000..40623fbb --- /dev/null +++ b/src/product-service/src/startup.rs @@ -0,0 +1,64 @@ + +use actix_cors::Cors; +use actix_web::dev::Server; +use actix_web::middleware::Logger; +use actix_web::{middleware, web, App, HttpServer}; + + +use std::sync::Mutex; +use crate::configuration::Settings; +use crate::routes::*; +use crate::model::Product; +use crate::data::fetch_products; + + +pub fn run(mut settings: Settings) -> Result { + + let products = fetch_products(&settings); + + let listener = settings.get_tcp_listener()?; + let port = listener.local_addr().unwrap().port(); + println!("Listening on http://0.0.0.0:{}", port); + + + let product_state = web::Data::new(AppState { + products: Mutex::new(products.to_vec()), + settings: settings, + }); + + let server = HttpServer::new(move || { + + let cors = Cors::permissive(); + + App::new() + .wrap(cors) + .wrap(Logger::default()) + .wrap(Logger::new("%a %{User-Agent}i")) + .wrap(middleware::DefaultHeaders::new().add(("X-Version", "0.2"))) + .app_data(product_state.clone()) + .route("/health", web::get().to(health)) + .route("/health", web::head().to(health)) + .route("/{product_id}", web::get().to(get_product)) + .route("/", web::get().to(get_products)) + .route("/", web::post().to(add_product)) + .route("/", web::put().to(update_product)) + .route("/{product_id}", web::delete().to(delete_product)) + .route("/ai/health", web::get().to(ai_health)) + .route("/ai/health", web::head().to(ai_health)) + .route( + "/ai/generate/description", + web::post().to(ai_generate_description), + ) + }) + .listen(listener)? + .run(); + + Ok(server) +} + +pub struct AppState { + pub products: Mutex>, + pub settings: Settings, +} + + diff --git a/src/product-service/test-product-service.http b/src/product-service/test-product-service.http index d842f5f5..92529879 100644 --- a/src/product-service/test-product-service.http +++ b/src/product-service/test-product-service.http @@ -19,6 +19,32 @@ Content-Type: application/json "image": "/placeholder.png" } +### Update product with too short of a description +PUT / +Host: localhost:3002 +Content-Type: application/json + +{ + "id": 11, + "name": "Where My Dogs At Digital Collar Tag", + "price": 105.99, + "description": "Tag your dog", + "image": "/placeholder.png" +} + +### Update product with invalid price +PUT / +Host: localhost:3002 +Content-Type: application/json + +{ + "id": 11, + "name": "Where My Dogs At Digital Collar Tag", + "price": 105.99, + "description": "Ensure your furry friend always finds their way home with this Where My Dogs At Digital Collar Tag. This digital tag uses low energy bluetooth to connect to your phone and features a fun design that will make your dog the talk of the town. It also includes a metal ring that makes it easy to attach to your dog's collar.", + "image": "/placeholder.png" +} + ### Update product PUT / Host: localhost:3002 diff --git a/src/product-service/tests/base_product_service.rs b/src/product-service/tests/base_product_service.rs new file mode 100644 index 00000000..e1289bd0 --- /dev/null +++ b/src/product-service/tests/base_product_service.rs @@ -0,0 +1,171 @@ +mod common; +use common::*; +use product_service::model::Product; +use actix_web::test; + +// test health check +#[test] +async fn test_health_check() { + let url = spawn_app(false); + + let res = get_health_check(&url).await; + + assert_eq!(res.status().as_u16(), 200); + let check = res.text().await.unwrap(); + assert_eq!(check, "{\"status\":\"ok\",\"version\":\"0.1.0\"}"); +} + +// test health check head +#[test] +async fn test_health_check_head() { + let url = spawn_app(false); + + let res = get_health_check_head(&url).await; + + assert_eq!(res.status().as_u16(), 200); +} + +#[test] +async fn test_ai_health_check_head() { + let url = spawn_app(false); + + let res = get_ai_health_check_head(&url).await; + + assert_eq!(res.status().as_u16(), 500); +} + +#[test] +async fn test_get_ai_health_check() { + let url = spawn_app(false); + + let res = get_ai_health_check(&url).await; + + assert_eq!(res.status().as_u16(), 500); +} + +// test get all products +#[test] +async fn test_get_all_products() { + let url = spawn_app(false); + + let res = get_products(&url).await; + + assert_eq!(res.status().as_u16(), 200); + + let products = res.json::>().await.unwrap(); + assert!(products.len() >= 10); +} + +// test get product by id +#[test] +async fn test_get_product_by_id() { + let url = spawn_app(false); + + let res = get_product(&url, 1).await; + + assert_eq!(res.status().as_u16(), 200); + + let product = res.json::().await.unwrap(); + assert_eq!(product.id, 1); +} + + +#[test] +async fn test_add_product() { + let url = spawn_app(false); + + let res = post_product(&url, &new_product()).await; + + assert_eq!(res.status().as_u16(), 200); + + let return_product = res.json::().await.unwrap(); + assert!(return_product.id >= 11); + assert_eq!(return_product.name, "test".to_string()); +} + +#[test] +async fn test_add_product_with_validation_short_description_length() { + let url = spawn_app(true); + + let failed_res = post_product(&url, &new_product()).await; + + assert_eq!(failed_res.status().as_u16(), 400); + assert_eq!(failed_res.text().await.unwrap(), "Error::InvalidProduct(\"The product description is too short!\")"); +} + +#[test] +async fn test_add_product_with_validation_long_description_length() { + let url = spawn_app(true); + + let successful_res = post_product(&url, &new_product_with_longer_description()).await; + + assert_eq!(successful_res.status().as_u16(), 200); + let return_product = successful_res.json::().await.unwrap(); + assert!(return_product.id >= 11); + assert_eq!(return_product.name, "test".to_string()); +} + +#[test] +async fn test_add_product_with_validation_high_price() { + let url = spawn_app(true); + + let failed_res = post_product(&url, &new_product_with_high_price()).await; + + assert_eq!(failed_res.status().as_u16(), 400); + assert_eq!(failed_res.text().await.unwrap(), "Error::PricingStandardsViolation(\"Price is too high!\")"); +} + +// test update product +#[test] +async fn test_update_product() { + let url = spawn_app(false); + + let res = post_product(&url, &new_product()).await; + + assert_eq!(res.status().as_u16(), 200); + + let return_product = res.json::().await.unwrap(); + assert!(return_product.id >= 11); + assert_eq!(return_product.name, "test".to_string()); + + let updated_product = Product { + id: return_product.id, + name: "test2".to_string(), + price: 2.0, + description: "test2".to_string(), + image: "test2".to_string(), + }; + + let res = update_product(&url, &updated_product).await; + + assert_eq!(res.status().as_u16(), 200); + + let return_product = res.json::().await.unwrap(); + assert_eq!(return_product.id, updated_product.id); + assert_eq!(return_product.name, updated_product.name); + assert_eq!(return_product.price, updated_product.price); + assert_eq!(return_product.description, updated_product.description); + assert_eq!(return_product.image, updated_product.image); +} + +// test delete product +#[test] +async fn test_delete_product() { + let url = spawn_app(false); + + let res = post_product(&url, &new_product()).await; + + assert_eq!(res.status().as_u16(), 200); + + let return_product = res.json::().await.unwrap(); + assert!(return_product.id >= 11); + assert_eq!(return_product.name, "test".to_string()); + + let res = delete_product(&url, return_product.id).await; + + assert_eq!(res.status().as_u16(), 200); + + let res = get_product(&url, return_product.id).await; + + assert_eq!(res.status().as_u16(), 404); +} \ No newline at end of file diff --git a/src/product-service/tests/common.rs b/src/product-service/tests/common.rs new file mode 100644 index 00000000..f796c550 --- /dev/null +++ b/src/product-service/tests/common.rs @@ -0,0 +1,125 @@ +use product_service::startup::run; +use product_service::model::Product; +use product_service::configuration::Settings; +use env_logger::Env; + +#[ctor::ctor] +fn init() { + env_logger::init_from_env(Env::default().default_filter_or("warn")); +} + +pub fn spawn_app(enable_wasm: bool) -> String { + let mut settings = Settings::new() + .set_wasm_rules_engine(enable_wasm) + .set_port(0); + + let listener = &settings.get_tcp_listener().expect("Failed to bind address"); + let port = listener.local_addr().unwrap().port(); + let app = run(settings).expect("Failed to bind address"); + let _ = actix_web::rt::spawn(app); + format!("http://127.0.0.1:{}", port) +} + +pub fn new_product() -> Product { + Product { + id: 0, + name: "test".to_string(), + price: 1.0, + description: "test".to_string(), + image: "test".to_string(), + } +} + +pub fn new_product_with_longer_description() -> Product { + Product { + id: 0, + name: "test".to_string(), + price: 1.0, + description: "This is longer than 10 characters".to_string(), + image: "test".to_string(), + } +} + +pub fn new_product_with_high_price() -> Product { + Product { + id: 0, + name: "test".to_string(), + price: 105.0, + description: "This is longer than 10 characters".to_string(), + image: "test".to_string(), + } +} + +pub async fn post_product(address: &str, product: &Product) -> reqwest::Response { + let client = reqwest::Client::new(); + client.post(address) + .json(product) + .send() + .await + .unwrap() +} + +pub async fn get_products(address: &str) -> reqwest::Response { + let client = reqwest::Client::new(); + client.get(address) + .send() + .await + .unwrap() +} + +pub async fn get_product(address: &str, id: i32) -> reqwest::Response { + let client = reqwest::Client::new(); + client.get(format!("{}/{}", address, id)) + .send() + .await + .unwrap() +} + +pub async fn delete_product(address: &str, id: i32) -> reqwest::Response { + let client = reqwest::Client::new(); + client.delete(format!("{}/{}", address, id)) + .send() + .await + .unwrap() +} + +pub async fn update_product(address: &str, product: &Product) -> reqwest::Response { + let client = reqwest::Client::new(); + client.put(address) + .json(product) + .send() + .await + .unwrap() +} + +pub async fn get_health_check(address: &str) -> reqwest::Response { + let client = reqwest::Client::new(); + client.get(format!("{}/health", address)) + .send() + .await + .unwrap() +} + +pub async fn get_health_check_head(address: &str) -> reqwest::Response { + let client = reqwest::Client::new(); + client.head(format!("{}/health", address)) + .send() + .await + .unwrap() +} + +pub async fn get_ai_health_check_head(address: &str) -> reqwest::Response { + let client = reqwest::Client::new(); + client.head(format!("{}/ai/health", address)) + .send() + .await + .unwrap() +} + +pub async fn get_ai_health_check(address: &str) -> reqwest::Response { + let client = reqwest::Client::new(); + client.get(format!("{}/ai/health", address)) + .send() + .await + .unwrap() +} diff --git a/src/product-service/tests/rule_engine.wasm b/src/product-service/tests/rule_engine.wasm new file mode 100644 index 00000000..124e2b56 Binary files /dev/null and b/src/product-service/tests/rule_engine.wasm differ diff --git a/tests/e2e/add_product.spec.ts b/tests/e2e/add_product.spec.ts new file mode 100644 index 00000000..f8c0721b --- /dev/null +++ b/tests/e2e/add_product.spec.ts @@ -0,0 +1,28 @@ +import { test, expect } from '@playwright/test'; + + +test('can add product ', async ({ page }) => { + await page.goto('/'); + + await page.getByRole('link', { name: 'Products' }).click(); + await page.getByRole('button', { name: 'Add Product' }).click(); + + await page.getByPlaceholder('Product Name').fill('Bear Snacks'); + await page.getByPlaceholder('Price').fill('29.99'); + await page.getByPlaceholder('Product Keywords').fill('dog, snack, treat, courage, ghosts'); + + const askOpenAI = page.getByRole('button', { name: 'Ask OpenAI' }); + + if (await askOpenAI.isVisible()) { + const aiApiCall = page.waitForResponse('/ai/generate/description'); + await askOpenAI.click(); + await aiApiCall; + } + else { + await page.getByPlaceholder('Product Description').fill('Something tasty for the pups'); + } + + await page.getByRole('button', { name: 'Save Product' }).click(); + await expect(page.getByRole('heading', { name: 'Bear Snacks - 29.99' })).toBeVisible(); + await expect(page.getByRole('button', { name: 'Edit Product' })).toBeVisible(); + }); diff --git a/tests/e2e/example.spec.ts b/tests/e2e/example.spec.ts new file mode 100644 index 00000000..f6dbb89c --- /dev/null +++ b/tests/e2e/example.spec.ts @@ -0,0 +1,18 @@ +import { test, expect } from '@playwright/test'; + +test('has title', async ({ page }) => { + await page.goto('/'); + + // Expect a title "to contain" a substring. + await expect(page).toHaveTitle(/store-admin/); +}); + +test('has Products link', async ({ page }) => { + await page.goto('/'); + + // Click the get started link. + await page.getByRole('link', { name: 'Products' }).click(); + + // Expects page to have an Add Product button. + await expect(page.getByRole('button', { name: 'Add Product' })).toBeVisible(); +}); diff --git a/tests/e2e/products.spec.ts b/tests/e2e/products.spec.ts new file mode 100644 index 00000000..bf08ea98 --- /dev/null +++ b/tests/e2e/products.spec.ts @@ -0,0 +1,15 @@ +import { test, expect } from '@playwright/test'; + + +test('renders functionally', async ({ page }) => { + await page.goto('/'); + + // Click the get started link. + await page.getByRole('link', { name: 'Products' }).click(); + + // Expects page to have an Add Product button. + await expect(page.getByRole('button', { name: 'Add Product' })).toBeVisible(); + await expect(page.getByText('Product ID')).toBeVisible(); + await expect(page.getByText('Product Name')).toBeVisible(); + await expect(page.getByText('Product Description')).toBeVisible(); + }); diff --git a/tests/package-lock.json b/tests/package-lock.json new file mode 100644 index 00000000..f9729fcb --- /dev/null +++ b/tests/package-lock.json @@ -0,0 +1,115 @@ +{ + "name": "tests", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "tests", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "dotenv": "^10.0.0", + "playwright": "^1.38.1", + "playwright-core": "^1.38.1" + }, + "devDependencies": { + "@playwright/test": "^1.38.1", + "@types/node": "^20.7.2" + } + }, + "node_modules/@playwright/test": { + "version": "1.38.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.38.1.tgz", + "integrity": "sha512-NqRp8XMwj3AK+zKLbZShl0r/9wKgzqI/527bkptKXomtuo+dOjU9NdMASQ8DNC9z9zLOMbG53T4eihYr3XR+BQ==", + "dev": true, + "dependencies": { + "playwright": "1.38.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@types/node": { + "version": "20.7.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.7.2.tgz", + "integrity": "sha512-RcdC3hOBOauLP+r/kRt27NrByYtDjsXyAuSbR87O6xpsvi763WI+5fbSIvYJrXnt9w4RuxhV6eAXfIs7aaf/FQ==", + "dev": true + }, + "node_modules/dotenv": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", + "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", + "engines": { + "node": ">=10" + } + }, + "node_modules/playwright": { + "version": "1.38.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.38.1.tgz", + "integrity": "sha512-oRMSJmZrOu1FP5iu3UrCx8JEFRIMxLDM0c/3o4bpzU5Tz97BypefWf7TuTNPWeCe279TPal5RtPPZ+9lW/Qkow==", + "dependencies": { + "playwright-core": "1.38.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=16" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.38.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.38.1.tgz", + "integrity": "sha512-tQqNFUKa3OfMf4b2jQ7aGLB8o9bS3bOY0yMEtldtC2+spf8QXG9zvXLTXUeRsoNuxEYMgLYR+NXfAa1rjKRcrg==", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=16" + } + } + }, + "dependencies": { + "@playwright/test": { + "version": "1.38.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.38.1.tgz", + "integrity": "sha512-NqRp8XMwj3AK+zKLbZShl0r/9wKgzqI/527bkptKXomtuo+dOjU9NdMASQ8DNC9z9zLOMbG53T4eihYr3XR+BQ==", + "dev": true, + "requires": { + "playwright": "1.38.1" + } + }, + "@types/node": { + "version": "20.7.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.7.2.tgz", + "integrity": "sha512-RcdC3hOBOauLP+r/kRt27NrByYtDjsXyAuSbR87O6xpsvi763WI+5fbSIvYJrXnt9w4RuxhV6eAXfIs7aaf/FQ==", + "dev": true + }, + "dotenv": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", + "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==" + }, + "playwright": { + "version": "1.38.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.38.1.tgz", + "integrity": "sha512-oRMSJmZrOu1FP5iu3UrCx8JEFRIMxLDM0c/3o4bpzU5Tz97BypefWf7TuTNPWeCe279TPal5RtPPZ+9lW/Qkow==", + "requires": { + "fsevents": "2.3.2", + "playwright-core": "1.38.1" + } + }, + "playwright-core": { + "version": "1.38.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.38.1.tgz", + "integrity": "sha512-tQqNFUKa3OfMf4b2jQ7aGLB8o9bS3bOY0yMEtldtC2+spf8QXG9zvXLTXUeRsoNuxEYMgLYR+NXfAa1rjKRcrg==" + } + } +} diff --git a/tests/package.json b/tests/package.json new file mode 100644 index 00000000..02adbb32 --- /dev/null +++ b/tests/package.json @@ -0,0 +1,19 @@ +{ + "name": "tests", + "version": "1.0.0", + "description": "", + "main": "index.js", + "dependencies": { + "playwright": "^1.38.1", + "playwright-core": "^1.38.1", + "dotenv": "^10.0.0" + }, + "devDependencies": { + "@playwright/test": "^1.38.1", + "@types/node": "^20.7.2" + }, + "scripts": {}, + "keywords": [], + "author": "", + "license": "ISC" +} diff --git a/tests/playwright.config.ts b/tests/playwright.config.ts new file mode 100644 index 00000000..db162d15 --- /dev/null +++ b/tests/playwright.config.ts @@ -0,0 +1,77 @@ +import { defineConfig, devices } from '@playwright/test'; + +/** + * Read environment variables from file. + * https://github.com/motdotla/dotenv + */ +require('dotenv').config({ path: '.env.playwright.local' }); + +/** + * See https://playwright.dev/docs/test-configuration. + */ +export default defineConfig({ + testDir: './e2e', + /* Run tests in files in parallel */ + fullyParallel: true, + /* Fail the build on CI if you accidentally left test.only in the source code. */ + forbidOnly: !!process.env.CI, + /* Retry on CI only */ + retries: process.env.CI ? 2 : 0, + /* Opt out of parallel tests on CI. */ + workers: process.env.CI ? 1 : undefined, + /* Reporter to use. See https://playwright.dev/docs/test-reporters */ + reporter: 'html', + /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ + use: { + /* Base URL to use in actions like `await page.goto('/')`. */ + baseURL: process.env.STORE_ADMIN_URL, + + /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ + trace: 'on-first-retry', + }, + + /* Configure projects for major browsers */ + projects: [ + { + name: 'chromium', + use: { ...devices['Desktop Chrome'] }, + }, + + { + name: 'firefox', + use: { ...devices['Desktop Firefox'] }, + }, + + { + name: 'webkit', + use: { ...devices['Desktop Safari'] }, + }, + + /* Test against mobile viewports. */ + // { + // name: 'Mobile Chrome', + // use: { ...devices['Pixel 5'] }, + // }, + // { + // name: 'Mobile Safari', + // use: { ...devices['iPhone 12'] }, + // }, + + /* Test against branded browsers. */ + // { + // name: 'Microsoft Edge', + // use: { ...devices['Desktop Edge'], channel: 'msedge' }, + // }, + // { + // name: 'Google Chrome', + // use: { ...devices['Desktop Chrome'], channel: 'chrome' }, + // }, + ], + + /* Run your local dev server before starting the tests */ + // webServer: { + // command: 'npm run start', + // url: 'http://127.0.0.1:3000', + // reuseExistingServer: !process.env.CI, + // }, +});