diff --git a/.github/workflows/codspeed.yml b/.github/workflows/codspeed.yml index 48b700fc6..da0b3dbfd 100644 --- a/.github/workflows/codspeed.yml +++ b/.github/workflows/codspeed.yml @@ -26,7 +26,7 @@ jobs: with: submodules: true - - uses: dtolnay/rust-toolchain@1.87.0 + - uses: dtolnay/rust-toolchain@1.90.0 with: targets: wasm32-unknown-unknown diff --git a/.github/workflows/pullrequest.yml b/.github/workflows/pullrequest.yml index bf73c7304..1375f637b 100644 --- a/.github/workflows/pullrequest.yml +++ b/.github/workflows/pullrequest.yml @@ -17,7 +17,7 @@ jobs: runs-on: ${{ matrix.platform }} steps: - - uses: dtolnay/rust-toolchain@1.87.0 + - uses: dtolnay/rust-toolchain@1.90.0 - uses: actions/checkout@v4 with: submodules: true @@ -29,10 +29,20 @@ jobs: restore-keys: ${{ runner.os }}-cargo- - run: cargo test -p worker-build - run: cargo build -p worker-build + - name: Build wasm-bindgen CLI (fork) + working-directory: wasm-bindgen + run: cargo build -p wasm-bindgen-cli --bin wasm-bindgen + - name: Copy wasm-bindgen binary alongside worker-build + shell: bash + run: cp wasm-bindgen/target/debug/wasm-bindgen* target/debug/ 2>/dev/null || true - uses: actions/upload-artifact@v4 with: - name: worker-build - path: target/debug/worker-build + name: worker-build-${{ matrix.platform }} + path: | + target/debug/worker-build + target/debug/worker-build.exe + target/debug/wasm-bindgen + target/debug/wasm-bindgen.exe build-templates: name: Templates @@ -40,7 +50,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: dtolnay/rust-toolchain@1.87.0 + - uses: dtolnay/rust-toolchain@1.90.0 - uses: actions/checkout@v4 with: @@ -55,18 +65,20 @@ jobs: - uses: actions/download-artifact@v4 with: - name: worker-build + name: worker-build-ubuntu-latest path: ./target/debug - - name: Make worker-build executable - run: chmod +x ./target/debug/worker-build + - name: Make binaries executable + run: chmod +x ./target/debug/worker-build ./target/debug/wasm-bindgen - - uses: cargo-bins/cargo-binstall@main + - uses: cargo-bins/cargo-binstall@v1.17.7 - name: Install cargo-generate run: cargo binstall cargo-generate - name: Generate and build all templates + env: + WASM_BINDGEN_BIN: ${{ github.workspace }}/target/debug/wasm-bindgen run: | mkdir -p generated for template in templates/*/; do @@ -88,7 +100,7 @@ jobs: needs: worker-build runs-on: ubuntu-latest steps: - - uses: dtolnay/rust-toolchain@1.87.0 + - uses: dtolnay/rust-toolchain@1.90.0 - uses: actions/checkout@v4 with: submodules: true @@ -97,18 +109,20 @@ jobs: uses: actions/cache@v4 with: path: ~/.cargo/registry ~/.cargo/git target - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-cargo- + key: ${{ runner.os }}-cargo-examples-${{ hashFiles('**/Cargo.lock', 'wasm-bindgen/crates/shared/src/lib.rs') }} + restore-keys: ${{ runner.os }}-cargo-examples- - uses: actions/download-artifact@v4 with: - name: worker-build + name: worker-build-ubuntu-latest path: ./target/debug - - name: Make worker-build executable - run: chmod +x ./target/debug/worker-build + - name: Make binaries executable + run: chmod +x ./target/debug/worker-build ./target/debug/wasm-bindgen - name: Build all examples + env: + WASM_BINDGEN_BIN: ${{ github.workspace }}/target/debug/wasm-bindgen run: | sed -i 's/, "examples\/axum"//g' Cargo.toml for example in examples/*/; do @@ -127,7 +141,7 @@ jobs: name: Formatter runs-on: ubuntu-latest steps: - - uses: dtolnay/rust-toolchain@1.87.0 + - uses: dtolnay/rust-toolchain@1.90.0 with: components: rustfmt, clippy @@ -164,7 +178,7 @@ jobs: runs-on: ${{ matrix.platform }} steps: - - uses: dtolnay/rust-toolchain@1.87.0 + - uses: dtolnay/rust-toolchain@1.90.0 - uses: actions/checkout@v4 with: submodules: true @@ -176,11 +190,12 @@ jobs: - uses: actions/download-artifact@v4 with: - name: worker-build + name: worker-build-${{ matrix.platform }} path: ./target/debug - - name: Make worker-build executable - run: chmod +x ./target/debug/worker-build + - name: Make binaries executable + if: matrix.platform != 'windows-latest' + run: chmod +x ./target/debug/worker-build ./target/debug/wasm-bindgen - name: Cache Rust dependencies uses: actions/cache@v4 @@ -241,11 +256,11 @@ jobs: - uses: actions/download-artifact@v4 with: - name: worker-build + name: worker-build-ubuntu-latest path: ./target/debug - - name: Make worker-build executable - run: chmod +x ./target/debug/worker-build + - name: Make binaries executable + run: chmod +x ./target/debug/worker-build ./target/debug/wasm-bindgen - name: Cache Rust dependencies uses: actions/cache@v4 diff --git a/Cargo.lock b/Cargo.lock index bc3a291ff..f5a66151e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "adler2" @@ -600,7 +600,7 @@ dependencies = [ "tracing", "tracing-subscriber", "tracing-web", - "worker 0.7.4", + "worker 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -611,9 +611,9 @@ checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" [[package]] name = "deflate64" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26bf8fc351c5ed29b5c2f0cbbac1b209b74f60ecd62e675a998df72c49af5204" +checksum = "807800ff3288b621186fe0a8f3392c4652068257302709c24efd918c3dffcdc2" [[package]] name = "der" @@ -661,7 +661,7 @@ name = "digest-stream-on-workers" version = "0.1.0" dependencies = [ "hex", - "worker 0.7.4", + "worker 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -727,12 +727,6 @@ dependencies = [ "regex", ] -[[package]] -name = "env_home" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7f84e12ccf0a7ddc17a6c41c93326024c42920d7ee630d04950e6926645c0fe" - [[package]] name = "env_logger" version = "0.11.9" @@ -754,9 +748,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "erased-serde" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e8918065695684b2b0702da20382d5ae6065cf3327bc2d6436bd49a71ce9f3" +checksum = "d2add8a07dd6a8d93ff627029c51de145e12686fbc36ecb298ac22e74cf02dec" dependencies = [ "serde", "serde_core", @@ -797,7 +791,7 @@ version = "0.1.0" dependencies = [ "serde", "serde_json", - "worker 0.7.4", + "worker 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -964,20 +958,20 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "r-efi", + "r-efi 5.3.0", "wasip2", "wasm-bindgen", ] [[package]] name = "getrandom" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" dependencies = [ "cfg-if", "libc", - "r-efi", + "r-efi 6.0.0", "wasip2", "wasip3", ] @@ -1006,7 +1000,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ "foldhash 0.1.5", - "serde", ] [[package]] @@ -1301,9 +1294,9 @@ checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" [[package]] name = "jiff" -version = "0.2.21" +version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3e3d65f018c6ae946ab16e80944b97096ed73c35b221d1c478a6c81d8f57940" +checksum = "1a3546dc96b6d42c5f24902af9e2538e82e39ad350b0c766eb3fbf2d8f3d8359" dependencies = [ "jiff-static", "log", @@ -1314,9 +1307,9 @@ dependencies = [ [[package]] name = "jiff-static" -version = "0.2.21" +version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a17c2b211d863c7fde02cbea8a3c1a439b98e109286554f2860bdded7ff83818" +checksum = "2a8c8b344124222efd714b73bb41f8b5120b27a7cc1c75593a6ff768d9d05aa4" dependencies = [ "proc-macro2", "quote", @@ -1335,10 +1328,10 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.90" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14dc6f6450b3f6d4ed5b16327f38fed626d375a886159ca555bd7822c0c3a5a6" +version = "0.3.91" dependencies = [ + "cfg-if", + "futures-util", "once_cell", "wasm-bindgen", ] @@ -1348,7 +1341,7 @@ name = "kv-on-workers" version = "0.1.0" dependencies = [ "serde_json", - "worker 0.7.4", + "worker 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1371,9 +1364,9 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "libc" -version = "0.2.182" +version = "0.2.183" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" +checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" [[package]] name = "libm" @@ -1383,13 +1376,14 @@ checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "libredox" -version = "0.1.12" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" +checksum = "1744e39d1d6a9948f4f388969627434e31128196de472883b39f148769bfe30a" dependencies = [ "bitflags", "libc", - "redox_syscall 0.7.2", + "plain", + "redox_syscall 0.7.3", ] [[package]] @@ -1753,18 +1747,18 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.10" +version = "1.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" +checksum = "f1749c7ed4bcaf4c3d0a3efc28538844fb29bcdd7d2b67b2be7e20ba861ff517" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.10" +version = "1.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" +checksum = "d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6" dependencies = [ "proc-macro2", "quote", @@ -1773,9 +1767,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] name = "pin-utils" @@ -1789,6 +1783,12 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + [[package]] name = "portable-atomic" version = "1.13.1" @@ -1882,14 +1882,14 @@ name = "queue-on-workers" version = "0.1.0" dependencies = [ "serde", - "worker 0.7.4", + "worker 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "quote" -version = "1.0.44" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" dependencies = [ "proc-macro2", ] @@ -1900,6 +1900,12 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + [[package]] name = "rand" version = "0.9.2" @@ -1960,9 +1966,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d94dd2f7cd932d4dc02cc8b2b50dfd38bd079a4e5d79198b99743d7fcf9a4b4" +checksum = "6ce70a74e890531977d37e532c34d45e9055d2409ed08ddba14529471ed0be16" dependencies = [ "bitflags", ] @@ -2036,7 +2042,7 @@ version = "0.1.0" dependencies = [ "serde", "tokio", - "worker 0.7.4", + "worker 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2147,9 +2153,9 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.28" +version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" +checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" dependencies = [ "windows-sys 0.61.2", ] @@ -2399,12 +2405,12 @@ checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "socket2" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0" +checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -2477,12 +2483,12 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.26.0" +version = "3.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82a72c767771b47409d2345987fda8628641887d5466101319899796367354a0" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ "fastrand", - "getrandom 0.4.1", + "getrandom 0.4.2", "once_cell", "rustix 1.1.4", "windows-sys 0.61.2", @@ -2596,9 +2602,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.49.0" +version = "1.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" +checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d" dependencies = [ "bytes", "libc", @@ -2613,9 +2619,9 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.6.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" +checksum = "5c55a2eff8b69ce66c84f85e1da1c233edc36ceb85a2058d11b0d6a3c7e7569c" dependencies = [ "proc-macro2", "quote", @@ -3077,11 +3083,11 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.21.0" +version = "1.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b672338555252d43fd2240c714dc444b8c6fb0a5c5335e65a07bba7742735ddb" +checksum = "a68d3c8f01c0cfa54a75291d83601161799e4a89a39e0929f4b0354d88757a37" dependencies = [ - "getrandom 0.4.1", + "getrandom 0.4.2", "js-sys", "serde_core", "wasm-bindgen", @@ -3117,9 +3123,9 @@ dependencies = [ [[package]] name = "walrus" -version = "0.25.1" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e227b6648df548f43f267aeee20dfd74d3121ccea10f6a73ea5aa319012df20" +checksum = "d5387fce247006749df1ba65c7c93d1d3f0e36259174f299a8f677e0c38e5091" dependencies = [ "anyhow", "gimli", @@ -3134,9 +3140,9 @@ dependencies = [ [[package]] name = "walrus-macro" -version = "0.25.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cef8d704ff46ad931a2cd1f7a504fe43ffb8e968d931e179ff18d0dff4949bd5" +checksum = "1a9b0525d7ea6e5f906aca581a172e5c91b4c595290dfa8ad4a2bc9ffef33b44" dependencies = [ "heck", "proc-macro2", @@ -3188,9 +3194,7 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.113" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60722a937f594b7fde9adb894d7c092fc1bb6612897c46368d18e7a20208eff2" +version = "0.2.114" dependencies = [ "cfg-if", "once_cell", @@ -3201,9 +3205,7 @@ dependencies = [ [[package]] name = "wasm-bindgen-cli-support" -version = "0.2.113" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a855c0fac6939d61ef9c27e1a436edf4ffdfa0bf63862dee3c1555f6d23b009" +version = "0.2.114" dependencies = [ "anyhow", "base64", @@ -3214,28 +3216,20 @@ dependencies = [ "serde_json", "walrus", "wasm-bindgen-shared", - "wasmparser 0.240.0", + "wasmparser 0.245.1", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.63" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a89f4650b770e4521aa6573724e2aed4704372151bd0de9d16a3bbabb87441a" +version = "0.4.64" dependencies = [ - "cfg-if", - "futures-util", "js-sys", - "once_cell", "wasm-bindgen", - "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.113" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac8c6395094b6b91c4af293f4c79371c163f9a6f56184d2c9a85f5a95f3950" +version = "0.2.114" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3243,9 +3237,7 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.113" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab3fabce6159dc20728033842636887e4877688ae94382766e00b180abac9d60" +version = "0.2.114" dependencies = [ "bumpalo", "proc-macro2", @@ -3256,18 +3248,14 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.113" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de0e091bdb824da87dc01d967388880d017a0a9bc4f3bdc0d86ee9f9336e3bb5" +version = "0.2.114" dependencies = [ "unicode-ident", ] [[package]] name = "wasm-bindgen-test" -version = "0.3.63" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e6fc7a6f61926fa909ee570d4ca194e264545ebbbb4ffd63ac07ba921bff447" +version = "0.3.64" dependencies = [ "async-trait", "cast", @@ -3287,9 +3275,7 @@ dependencies = [ [[package]] name = "wasm-bindgen-test-macro" -version = "0.3.63" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f745a117245c232859f203d6c8d52c72d4cfc42de7e668c147ca6b3e45f1157e" +version = "0.3.64" dependencies = [ "proc-macro2", "quote", @@ -3298,9 +3284,7 @@ dependencies = [ [[package]] name = "wasm-bindgen-test-shared" -version = "0.2.113" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f88e7ae201cc7c291da857532eb1c8712e89494e76ec3967b9805221388e938" +version = "0.2.114" [[package]] name = "wasm-encoder" @@ -3334,19 +3318,6 @@ dependencies = [ "wasmparser 0.244.0", ] -[[package]] -name = "wasm-streams" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" -dependencies = [ - "futures-util", - "js-sys", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - [[package]] name = "wasm-streams" version = "0.5.0" @@ -3371,19 +3342,6 @@ dependencies = [ "semver", ] -[[package]] -name = "wasmparser" -version = "0.240.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b722dcf61e0ea47440b53ff83ccb5df8efec57a69d150e4f24882e4eba7e24a4" -dependencies = [ - "bitflags", - "hashbrown 0.15.5", - "indexmap", - "semver", - "serde", -] - [[package]] name = "wasmparser" version = "0.244.0" @@ -3411,9 +3369,7 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.90" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "705eceb4ce901230f8625bd1d665128056ccbe4b7408faa625eec1ba80f59a97" +version = "0.3.91" dependencies = [ "js-sys", "wasm-bindgen", @@ -3448,13 +3404,11 @@ dependencies = [ [[package]] name = "which" -version = "8.0.0" +version = "8.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3fabb953106c3c8eea8306e4393700d7657561cb43122571b172bbfb7c7ba1d" +checksum = "81995fafaaaf6ae47a7d0cc83c67caf92aeb7e5331650ae6ff856f7c0c60c459" dependencies = [ - "env_home", - "rustix 1.1.4", - "winsafe", + "libc", ] [[package]] @@ -3587,15 +3541,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows-sys" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" -dependencies = [ - "windows-targets 0.53.5", -] - [[package]] name = "windows-sys" version = "0.61.2" @@ -3629,30 +3574,13 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", + "windows_i686_gnullvm", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] -[[package]] -name = "windows-targets" -version = "0.53.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" -dependencies = [ - "windows-link", - "windows_aarch64_gnullvm 0.53.1", - "windows_aarch64_msvc 0.53.1", - "windows_i686_gnu 0.53.1", - "windows_i686_gnullvm 0.53.1", - "windows_i686_msvc 0.53.1", - "windows_x86_64_gnu 0.53.1", - "windows_x86_64_gnullvm 0.53.1", - "windows_x86_64_msvc 0.53.1", -] - [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -3665,12 +3593,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" - [[package]] name = "windows_aarch64_msvc" version = "0.48.5" @@ -3683,12 +3605,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" - [[package]] name = "windows_i686_gnu" version = "0.48.5" @@ -3701,24 +3617,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" -[[package]] -name = "windows_i686_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" - [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" - [[package]] name = "windows_i686_msvc" version = "0.48.5" @@ -3731,12 +3635,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_i686_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" - [[package]] name = "windows_x86_64_gnu" version = "0.48.5" @@ -3749,12 +3647,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" - [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" @@ -3767,12 +3659,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" - [[package]] name = "windows_x86_64_msvc" version = "0.48.5" @@ -3785,27 +3671,15 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" - [[package]] name = "winnow" -version = "0.7.14" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" dependencies = [ "memchr", ] -[[package]] -name = "winsafe" -version = "0.0.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" - [[package]] name = "wit-bindgen" version = "0.51.0" @@ -3914,13 +3788,13 @@ dependencies = [ [[package]] name = "worker" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "244647fd7673893058f91f22a0eabd0f45bb50298e995688cb0c4b9837081b19" +version = "0.7.5" dependencies = [ "async-trait", + "axum", "bytes", "chrono", + "chrono-tz", "futures-channel", "futures-util", "http", @@ -3933,24 +3807,26 @@ dependencies = [ "serde_json", "serde_urlencoded", "tokio", + "tokio-postgres", "url", "wasm-bindgen", "wasm-bindgen-futures", - "wasm-streams 0.4.2", + "wasm-bindgen-test", + "wasm-streams", "web-sys", - "worker-macros 0.7.4", - "worker-sys 0.7.4", + "worker-macros 0.7.5", + "worker-sys 0.7.5", ] [[package]] name = "worker" version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7267f3baa986254a8dace6f6a7c6ab88aef59f00c03aaad6749e048b5faaf6f6" dependencies = [ "async-trait", - "axum", "bytes", "chrono", - "chrono-tz", "futures-channel", "futures-util", "http", @@ -3963,15 +3839,13 @@ dependencies = [ "serde_json", "serde_urlencoded", "tokio", - "tokio-postgres", "url", "wasm-bindgen", "wasm-bindgen-futures", - "wasm-bindgen-test", - "wasm-streams 0.5.0", + "wasm-streams", "web-sys", - "worker-macros 0.7.5", - "worker-sys 0.7.5", + "worker-macros 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)", + "worker-sys 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -4023,9 +3897,7 @@ dependencies = [ [[package]] name = "worker-macros" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac7e73ffb164183b57bb67d3efb881681fcd93ef5515ba32a4d022c4a6acc2ce" +version = "0.7.5" dependencies = [ "async-trait", "proc-macro2", @@ -4034,12 +3906,14 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "wasm-bindgen-macro-support", - "worker-sys 0.7.4", + "worker-sys 0.7.5", ] [[package]] name = "worker-macros" version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7410081121531ec2fa111ab17b911efc601d7b6d590c0a92b847874ebeff0030" dependencies = [ "async-trait", "proc-macro2", @@ -4048,7 +3922,7 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "wasm-bindgen-macro-support", - "worker-sys 0.7.5", + "worker-sys 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -4085,9 +3959,7 @@ dependencies = [ [[package]] name = "worker-sys" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2b96254fcaa9229fd82d886f04be99c4ee8e59c8d80438724aa70039dca838" +version = "0.7.5" dependencies = [ "cfg-if", "js-sys", @@ -4098,6 +3970,8 @@ dependencies = [ [[package]] name = "worker-sys" version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4777582bf8a04174a034cb336f3702eb0e5cb444a67fdaa4fd44454ff7e2dd95" dependencies = [ "cfg-if", "js-sys", @@ -4166,18 +4040,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.39" +version = "0.8.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db6d35d663eadb6c932438e763b262fe1a70987f9ae936e60158176d710cae4a" +checksum = "f2578b716f8a7a858b7f02d5bd870c14bf4ddbbcf3a4c05414ba6503640505e3" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.39" +version = "0.8.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517" +checksum = "7e6cc098ea4d3bd6246687de65af3f920c430e236bee1e3bf2e441463f08a02f" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index c669339b5..bb185bddd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,21 +27,22 @@ chrono = { version = "0.4.41", default-features = false, features = [ futures-channel = "0.3.31" futures-util = { version = "0.3.31", default-features = false } http = "1.3" -js-sys = { version = "0.3.90" } +js-sys = { version = "0.3.91" } serde = { version = "1.0.164", features = ["derive"] } serde_json = "1.0.140" serde-wasm-bindgen = "0.6.5" syn = "2.0.17" proc-macro2 = "1.0.60" quote = "1.0.28" -wasm-bindgen = { version = "0.2.113" } -wasm-bindgen-cli-support = { version = "0.2.113" } -wasm-bindgen-futures = { version = "0.4.63" } -wasm-bindgen-macro-support = { version = "0.2.113" } -wasm-bindgen-shared = { version = "0.2.113" } -wasm-bindgen-test = { version = "0.3.63" } +wasm-bindgen = { version = "0.2.114" } +wasm-bindgen-cli-support = { version = "0.2.114" } +wasm-bindgen-futures = { version = "0.4.64" } +wasm-bindgen-macro = { version = "0.2.114" } +wasm-bindgen-macro-support = { version = "0.2.114" } +wasm-bindgen-shared = { version = "0.2.114" } +wasm-bindgen-test = { version = "0.3.64" } wasm-streams = { version = "0.5.0" } -web-sys = { version = "0.3.90", features = [ +web-sys = { version = "0.3.91", features = [ "AbortController", "AbortSignal", "BinaryType", @@ -103,11 +104,14 @@ opt-level = "z" # These are local patches we use to test against local wasm bindgen # We always align on the exact stable wasm bindgen version for releases [patch.crates-io] -js-sys = { version = "0.3.90", path = './wasm-bindgen/crates/js-sys' } -wasm-bindgen = { version = "0.2.113", path = './wasm-bindgen' } -wasm-bindgen-cli-support = { version = "0.2.113", path = "./wasm-bindgen/crates/cli-support" } -wasm-bindgen-futures = { version = "0.4.63", path = './wasm-bindgen/crates/futures' } -wasm-bindgen-macro-support = { version = "0.2.113", path = "./wasm-bindgen/crates/macro-support" } -wasm-bindgen-shared = { version = "0.2.113", path = "./wasm-bindgen/crates/shared" } -wasm-bindgen-test = { version = "0.3.63", path = "./wasm-bindgen/crates/test" } -web-sys = { version = "0.3.90", path = './wasm-bindgen/crates/web-sys' } +js-sys = { version = "0.3.91", path = './wasm-bindgen/crates/js-sys' } +wasm-bindgen = { version = "0.2.114", path = './wasm-bindgen' } +wasm-bindgen-cli-support = { version = "0.2.114", path = "./wasm-bindgen/crates/cli-support" } +wasm-bindgen-futures = { version = "0.4.64", path = './wasm-bindgen/crates/futures' } +wasm-bindgen-macro = { version = "0.2.114", path = "./wasm-bindgen/crates/macro" } +wasm-bindgen-macro-support = { version = "0.2.114", path = "./wasm-bindgen/crates/macro-support" } +wasm-bindgen-shared = { version = "0.2.114", path = "./wasm-bindgen/crates/shared" } +wasm-bindgen-test = { version = "0.3.64", path = "./wasm-bindgen/crates/test" } +wasm-bindgen-test-macro = { version = "0.3.64", path = "./wasm-bindgen/crates/test-macro" } +wasm-bindgen-test-shared = { version = "0.2.114", path = "./wasm-bindgen/crates/test-shared" } +web-sys = { version = "0.3.91", path = './wasm-bindgen/crates/web-sys' } diff --git a/examples/axum/Cargo.lock b/examples/axum/Cargo.lock index e2b104274..9fd071b85 100644 --- a/examples/axum/Cargo.lock +++ b/examples/axum/Cargo.lock @@ -342,9 +342,9 @@ checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" [[package]] name = "js-sys" -version = "0.3.85" +version = "0.3.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" +checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c" dependencies = [ "once_cell", "wasm-bindgen", @@ -666,9 +666,9 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "wasm-bindgen" -version = "0.2.108" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" +checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e" dependencies = [ "cfg-if", "once_cell", @@ -679,9 +679,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.58" +version = "0.4.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70a6e77fd0ae8029c9ea0063f87c46fde723e7d887703d74ad2616d792e51e6f" +checksum = "e9c5522b3a28661442748e09d40924dfb9ca614b21c00d3fd135720e48b67db8" dependencies = [ "cfg-if", "futures-util", @@ -693,9 +693,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.108" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" +checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -703,9 +703,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.108" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" +checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3" dependencies = [ "bumpalo", "proc-macro2", @@ -716,9 +716,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.108" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" +checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16" dependencies = [ "unicode-ident", ] @@ -738,9 +738,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.85" +version = "0.3.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "312e32e551d92129218ea9a2452120f4aabc03529ef03e4d0d82fb2780608598" +checksum = "854ba17bb104abfb26ba36da9729addc7ce7f06f5c0f90f3c391f8461cca21f9" dependencies = [ "js-sys", "wasm-bindgen", diff --git a/examples/axum/Cargo.toml b/examples/axum/Cargo.toml index 36e34902e..3f1565730 100644 --- a/examples/axum/Cargo.toml +++ b/examples/axum/Cargo.toml @@ -16,5 +16,5 @@ axum = { version = "0.8", default-features = false, features = ['json'] } axum-macros = "0.5.0" tower-service = "0.3.3" wasm-bindgen-futures = "0.4" -wasm-bindgen = "0.2.108" +wasm-bindgen = "0.2.114" serde = { version = "1.0", features = ["derive"] } diff --git a/rust-toolchain.toml b/rust-toolchain.toml index ab40f4f44..2ce412d5a 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "1.88.0" +channel = "1.90.0" profile = "default" diff --git a/test/src/alarm.rs b/test/src/alarm.rs index 76e188bfb..74ce0ce4e 100644 --- a/test/src/alarm.rs +++ b/test/src/alarm.rs @@ -1,7 +1,5 @@ use std::time::Duration; -use worker::{ - console_log, durable_object, wasm_bindgen, DurableObject, Env, Request, Response, Result, State, -}; +use worker::{console_log, durable_object, DurableObject, Env, Request, Response, Result, State}; use super::SomeSharedData; diff --git a/test/src/counter.rs b/test/src/counter.rs index c301efabb..21930895a 100644 --- a/test/src/counter.rs +++ b/test/src/counter.rs @@ -1,8 +1,8 @@ use std::cell::RefCell; use tokio_stream::{StreamExt, StreamMap}; use worker::{ - durable_object, wasm_bindgen, wasm_bindgen_futures, DurableObject, Env, Error, Method, Request, - Response, ResponseBuilder, Result, State, WebSocket, WebSocketIncomingMessage, WebSocketPair, + durable_object, wasm_bindgen_futures, DurableObject, Env, Error, Method, Request, Response, + ResponseBuilder, Result, State, WebSocket, WebSocketIncomingMessage, WebSocketPair, WebsocketEvent, }; @@ -34,6 +34,10 @@ impl DurableObject for Counter { *self.count.borrow_mut() = self.state.storage().get("count").await?.unwrap_or(0); } + if req.path().eq("/panic") { + panic!("Intentional panic inside Durable Object fetch handler"); + } + if req.path().eq("/ws") { let pair = WebSocketPair::new()?; let server = pair.server; @@ -110,6 +114,13 @@ pub async fn handle_id(req: Request, env: Env, _data: SomeSharedData) -> Result< stub.fetch_with_str("https://fake-host/").await } +#[worker::send] +pub async fn handle_do_panic(_req: Request, env: Env, _data: SomeSharedData) -> Result { + let namespace = env.durable_object("COUNTER").expect("COUNTER binding"); + let stub = namespace.id_from_name("A")?.get_stub()?; + stub.fetch_with_str("https://fake-host/panic").await +} + #[worker::send] pub async fn handle_websocket(req: Request, env: Env, _data: SomeSharedData) -> Result { let durable_object_name = if req.path().contains("shared") { diff --git a/test/src/put_raw.rs b/test/src/put_raw.rs index 04d469ef9..c7eeaf35d 100644 --- a/test/src/put_raw.rs +++ b/test/src/put_raw.rs @@ -2,7 +2,7 @@ use std::convert::TryFrom; use worker::{ durable_object, js_sys::{self, Uint8Array}, - wasm_bindgen::{self, JsValue}, + wasm_bindgen::JsValue, DurableObject, Env, Request, Response, Result, State, }; diff --git a/test/src/router.rs b/test/src/router.rs index 4ca07033e..a1d307178 100644 --- a/test/src/router.rs +++ b/test/src/router.rs @@ -137,6 +137,7 @@ macro_rules! add_routes ( add_route!($obj, get, format_route!("/proxy_request/{}", "*url") ,fetch::handle_proxy_request); add_route!($obj, get, "/durable/alarm", alarm::handle_alarm); add_route!($obj, get, format_route!("/durable/{}", "id"), counter::handle_id); + add_route!($obj, get, "/durable/do-panic", counter::handle_do_panic); add_route!($obj, get, "/durable/put-raw", put_raw::handle_put_raw); add_route!($obj, get, "/durable/websocket", counter::handle_websocket); add_route!($obj, get, "/secret", request::handle_secret); diff --git a/test/src/sql_counter.rs b/test/src/sql_counter.rs index 46672e018..299413f37 100644 --- a/test/src/sql_counter.rs +++ b/test/src/sql_counter.rs @@ -1,6 +1,4 @@ -use worker::{ - durable_object, wasm_bindgen, DurableObject, Env, Request, Response, Result, SqlStorage, State, -}; +use worker::{durable_object, DurableObject, Env, Request, Response, Result, SqlStorage, State}; /// A simple SQLite-backed counter stored in Durable Object storage. /// diff --git a/test/src/sql_iterator.rs b/test/src/sql_iterator.rs index 019c0b63d..d17160ded 100644 --- a/test/src/sql_iterator.rs +++ b/test/src/sql_iterator.rs @@ -1,7 +1,7 @@ use serde::Deserialize; use worker::{ - durable_object, wasm_bindgen, DurableObject, Env, Request, Response, Result, SqlStorage, - SqlStorageValue, State, + durable_object, DurableObject, Env, Request, Response, Result, SqlStorage, SqlStorageValue, + State, }; /// A Durable Object that demonstrates SQL cursor iterator methods. diff --git a/test/tests/mf-socket.ts b/test/tests/mf-socket.ts index 7c00fbb00..28de3d731 100644 --- a/test/tests/mf-socket.ts +++ b/test/tests/mf-socket.ts @@ -11,7 +11,7 @@ export const server = createServer(function (socket) { export const mf = new Miniflare({ scriptPath: "./build/index.js", - compatibilityDate: "2024-12-05", + compatibilityDate: "2025-07-24", modules: true, modulesRules: [ { type: "CompiledWasm", include: ["**/*.wasm"], fallthrough: true }, diff --git a/test/tests/panic.spec.ts b/test/tests/panic.spec.ts index c6a553547..1880142a5 100644 --- a/test/tests/panic.spec.ts +++ b/test/tests/panic.spec.ts @@ -90,6 +90,98 @@ describe("Panic Hook with WASM Reinitialization", () => { expect(responses[2].status).toBe(200); } + // Test 4: Panic inside a Durable Object's fetch handler + // The DO instance should survive the panic and retain its in-memory state. + // Note: all /durable/* routes resolve to the same DO instance (name "A"), + // so we use relative counter assertions rather than absolute values. + { + // Read current counter state + const before = await mf.dispatchFetch(`${mfUrl}durable/pre-do-panic`); + expect(before.status).toBe(200); + const matchBefore = (await before.text()).match(/unstored_count: (\d+)/); + const countBefore = matchBefore ? parseInt(matchBefore[1]) : 0; + + // Trigger a panic inside the DO's fetch handler + const panicResp = await mf.dispatchFetch(`${mfUrl}durable/do-panic`); + expect(panicResp.status).toBe(500); + + // The DO instance should still be alive with its in-memory state intact. + // unstored_count should increment by 1 from countBefore, not reset to 1. + const after = await mf.dispatchFetch(`${mfUrl}durable/post-do-panic`); + expect(after.status).toBe(200); + const matchAfter = (await after.text()).match(/unstored_count: (\d+)/); + const countAfter = matchAfter ? parseInt(matchAfter[1]) : 0; + expect(countAfter).toBe(countBefore + 1); + } + + // Test 5: Fatal abort (wasm32::unreachable) triggers auto-reinit. + // wasm-bindgen's __wbg_termination_guard calls __wbg_reset_state on the + // next request. The reinit hook eagerly reconstructs all live DO instances + // on the fresh wasm module. + // (Note: DO-internal panic test above uses the same COUNTER DO as "A", + // so the unstored_count here reflects accumulated state from prior tests.) + { + // Establish counter state (unstored_count > 0 from prior tests) + const before = await mf.dispatchFetch(`${mfUrl}durable/pre-abort`); + const beforeMatch = (await before.text()).match(/unstored_count: (\d+)/); + const beforeCount = beforeMatch ? parseInt(beforeMatch[1]) : 0; + expect(beforeCount).toBeGreaterThan(0); + + // Fatal abort — wasm32::unreachable() + const abortResp = await mf.dispatchFetch(`${mfUrl}test-abort`); + expect(abortResp.status).toBe(500); + + // Next request triggers auto-reinit. Counter should reset to 1 + // (fresh wasm instance, DO reconstructed, unstored_count starts at 0+1=1) + const after = await mf.dispatchFetch(`${mfUrl}durable/post-abort`); + expect(after.status).toBe(200); + expect(await after.text()).toContain("unstored_count: 1"); + } + + // Test 6: Panic hook still works after fatal reinit + // The reinit hook re-registers setPanicHook, so subsequent panics should + // still be caught and returned as PanicError (not bare RuntimeError). + { + const panicResp = await mf.dispatchFetch(`${mfUrl}test-panic`); + expect(panicResp.status).toBe(500); + const panicText = await panicResp.text(); + expect(panicText).toContain("PanicError:"); + expect(panicText).toContain("Intentional panic"); + } + + // Test 7: OOM triggers auto-reinit + { + // Establish counter is working + const before = await mf.dispatchFetch(`${mfUrl}durable/pre-oom`); + expect(before.status).toBe(200); + const beforeMatch = (await before.text()).match(/unstored_count: (\d+)/); + const beforeCount = beforeMatch ? parseInt(beforeMatch[1]) : 0; + expect(beforeCount).toBeGreaterThan(0); + + // OOM — allocates 1GB chunks until failure + const oomResp = await mf.dispatchFetch(`${mfUrl}test-oom`); + expect(oomResp.status).toBe(500); + + // Counter should reset after auto-reinit + const after = await mf.dispatchFetch(`${mfUrl}durable/post-oom`); + expect(after.status).toBe(200); + expect(await after.text()).toContain("unstored_count: 1"); + } + + // Test 8: Multiple fatal error recovery cycles + // Proves reinit is repeatable and the reinit hook fires every time. + { + for (let cycle = 1; cycle <= 3; cycle++) { + const abortResp = await mf.dispatchFetch(`${mfUrl}test-abort`); + expect(abortResp.status).toBe(500); + + const recovery = await mf.dispatchFetch(`${mfUrl}durable/cycle-${cycle}`); + expect(recovery.status).toBe(200); + // After each reinit, unstored_count resets to 1 + expect(await recovery.text()).toContain("unstored_count: 1"); + } + } + } else { // ===== PANIC=ABORT MODE TESTS (default) ===== // In this mode, panics cause "Workers runtime canceled" and WASM reinitializes. diff --git a/wasm-bindgen b/wasm-bindgen index 7509015d4..b1eb2063d 160000 --- a/wasm-bindgen +++ b/wasm-bindgen @@ -1 +1 @@ -Subproject commit 7509015d4c530c7558177a1ba9cf692657a1780b +Subproject commit b1eb2063dd9e6547c7876367afcd131754ee92b3 diff --git a/worker-build/src/js/shim-unwind.js b/worker-build/src/js/shim-unwind.js new file mode 100644 index 000000000..09bbe0f44 --- /dev/null +++ b/worker-build/src/js/shim-unwind.js @@ -0,0 +1,32 @@ +import { WorkerEntrypoint } from "cloudflare:workers"; +import * as exports from "./index.js"; + +Error.stackTraceLimit = 100; + +// Polyfill console.createTask for runtimes that don't support it (e.g. workerd). +// wasm-bindgen-futures calls this under debug_assertions for async task tracking. +if (typeof console.createTask !== "function") { + console.createTask = (_name) => ({ + run: (fn) => fn(), + }); +} + +function panicHook(message) { + console.error("Rust panic:", message); +} + +function registerPanicHook() { + if (exports.setPanicHook) { + exports.setPanicHook(panicHook); + } +} + +registerPanicHook(); + +class Entrypoint extends WorkerEntrypoint {} + +$HANDLERS + +$DO_CLASSES + +export default Entrypoint; diff --git a/worker-build/src/js/shim.js b/worker-build/src/js/shim.js index a3e27b44a..098966338 100644 --- a/worker-build/src/js/shim.js +++ b/worker-build/src/js/shim.js @@ -3,13 +3,21 @@ import * as exports from "./index.js"; Error.stackTraceLimit = 100; +// Polyfill console.createTask for runtimes that don't support it (e.g. workerd). +// wasm-bindgen-futures calls this under debug_assertions for async task tracking. +if (typeof console.createTask !== "function") { + console.createTask = (_name) => ({ + run: (fn) => fn(), + }); +} + let criticalError = false; function registerPanicHook() { if (exports.setPanicHook) exports.setPanicHook(function (message) { const panicError = new Error("Rust panic: " + message); console.error('Critical', panicError); - $PANIC_CRITICAL_ERROR + criticalError = true; }); } @@ -19,7 +27,10 @@ let instanceId = 0; function checkReinitialize() { if (criticalError) { console.log("Reinitializing Wasm application"); - exports.__wbg_reset_state(); + // The try/catch guards against panic=abort builds where __reinit_handler + // is not present as a Wasm global — the fresh instance is still created + // successfully before the handler invocation that may throw. + try { exports.__wbg_reset_state(); } catch(_) {} criticalError = false; registerPanicHook(); instanceId++; @@ -41,73 +52,6 @@ class Entrypoint extends WorkerEntrypoint {} $HANDLERS -const instanceProxyHooks = { - set: (target, prop, value, receiver) => Reflect.set(target.instance, prop, value, receiver), - has: (target, prop) => Reflect.has(target.instance, prop), - deleteProperty: (target, prop) => Reflect.deleteProperty(target.instance, prop), - apply: (target, thisArg, args) => Reflect.apply(target.instance, thisArg, args), - construct: (target, args, newTarget) => Reflect.construct(target.instance, args, newTarget), - getPrototypeOf: (target) => Reflect.getPrototypeOf(target.instance), - setPrototypeOf: (target, proto) => Reflect.setPrototypeOf(target.instance, proto), - isExtensible: (target) => Reflect.isExtensible(target.instance), - preventExtensions: (target) => Reflect.preventExtensions(target.instance), - getOwnPropertyDescriptor: (target, prop) => Reflect.getOwnPropertyDescriptor(target.instance, prop), - defineProperty: (target, prop, descriptor) => Reflect.defineProperty(target.instance, prop, descriptor), - ownKeys: (target) => Reflect.ownKeys(target.instance), -}; - -const classProxyHooks = { - construct(ctor, args, newTarget) { - try { - checkReinitialize(); - const instance = { - instance: Reflect.construct(ctor, args, newTarget), - instanceId, - ctor, - args, - newTarget - }; - return new Proxy(instance, { - ...instanceProxyHooks, - get(target, prop, receiver) { - if (target.instanceId !== instanceId) { - target.instance = Reflect.construct(target.ctor, target.args, target.newTarget); - target.instanceId = instanceId; - } - const original = Reflect.get(target.instance, prop, receiver); - if (typeof original !== 'function') return original; - if (original.constructor === Function) { - return new Proxy(original, { - apply(target, thisArg, argArray) { - checkReinitialize(); - try { - return target.apply(thisArg, argArray); - } catch (e) { - handleMaybeCritical(e); - throw e; - } - } - }); - } else { - return new Proxy(original, { - async apply(target, thisArg, argArray) { - checkReinitialize(); - try { - return await target.apply(thisArg, argArray); - } catch (e) { - handleMaybeCritical(e); - throw e; - } - } - }); - } - } - }); - } catch (e) { - criticalError = true; - throw e; - } - } -}; +$DO_CLASSES -export default new Proxy(Entrypoint, classProxyHooks); +export default Entrypoint; diff --git a/worker-build/src/main.rs b/worker-build/src/main.rs index c5ee1bb6c..51edcdba0 100644 --- a/worker-build/src/main.rs +++ b/worker-build/src/main.rs @@ -1,5 +1,5 @@ use std::{ - env::{self, VarError}, + env, fs::{self, File}, io::{Read, Write}, path::{Path, PathBuf}, @@ -16,6 +16,7 @@ use clap::Parser; const OUT_DIR: &str = "build"; const SHIM_FILE: &str = include_str!("./js/shim.js"); +const SHIM_UNWIND_FILE: &str = include_str!("./js/shim-unwind.js"); pub(crate) mod binary; mod build; @@ -115,21 +116,28 @@ pub fn main() -> Result<()> { } if module_target { - let shim = SHIM_FILE - .replace("$HANDLERS", &generate_handlers(&staging_dir)?) - .replace( - "$PANIC_CRITICAL_ERROR", - if builder.panic_unwind { - "" - } else { - "criticalError = true;" - }, - ); + let index_path = output_path(&staging_dir, "index.js"); + let index_content = fs::read_to_string(&index_path) + .with_context(|| format!("Failed to read {}", index_path.display()))?; + + let exported_fns = collect_exported_fns(&index_content); + let do_classes = detect_do_classes(&exported_fns); + + let handlers = generate_handlers(&exported_fns, builder.panic_unwind); + let do_class_js = generate_do_classes(&do_classes, &exported_fns, builder.panic_unwind); + + let shim = if builder.panic_unwind { + SHIM_UNWIND_FILE + } else { + SHIM_FILE + } + .replace("$HANDLERS", &handlers) + .replace("$DO_CLASSES", &do_class_js); let shim_path = output_path(&staging_dir, "shim.js"); fs::write(&shim_path, shim) .with_context(|| format!("Failed to write {}", shim_path.display()))?; - add_export_wrappers(&staging_dir)?; + add_class_reexports(&staging_dir, &do_classes)?; update_package_json(&staging_dir)?; @@ -152,88 +160,278 @@ pub fn main() -> Result<()> { Ok(()) } -fn generate_handlers(out_dir: &Path) -> Result { - let index_path = output_path(out_dir, "index.js"); - let content = fs::read_to_string(&index_path) - .with_context(|| format!("Failed to read {}", index_path.display()))?; +/// Names of wasm-bindgen internal/system exports that must NOT be wrapped as +/// Worker handler methods on the Entrypoint prototype. +static SYSTEM_FNS: &[&str] = &["__wbg_reset_state", "setPanicHook"]; - // Extract ESM function exports from the wasm-bindgen generated output. - // This code is specialized to what wasm-bindgen outputs for ESM and is therefore - // brittle to upstream changes. It is comprehensive to current output patterns though. - // TODO: Convert this to Wasm binary exports analysis for entry point detection instead. - let mut func_names = Vec::new(); +/// The well-known method suffixes emitted by the `#[durable_object]` macro. +/// Each DO class exports `ClassName__DURABLE_OBJECT_INIT` plus a subset of these. +static DO_METHOD_SUFFIXES: &[&str] = &[ + "fetch", + "alarm", + "webSocketMessage", + "webSocketClose", + "webSocketError", +]; + +/// Collects all exported function names from the wasm-bindgen output. +fn collect_exported_fns(content: &str) -> Vec { + let mut names = Vec::new(); for line in content.lines() { - if let Some(rest) = line.strip_prefix("export function") { - if let Some(bracket_pos) = rest.find("(") { - let func_name = rest[..bracket_pos].trim(); - // strip the exported function (we re-wrap all handlers) - if !SYSTEM_FNS.contains(&func_name) { - func_names.push(func_name); - } + let trimmed = line.trim_start(); + if let Some(rest) = trimmed.strip_prefix("export function ") { + if let Some(paren) = rest.find('(') { + names.push(rest[..paren].trim().to_string()); } - } else if let Some(rest) = line.strip_prefix("export {") { + } else if let Some(rest) = trimmed.strip_prefix("export {") { if let Some(as_pos) = rest.find(" as ") { let rest = &rest[as_pos + 4..]; - if let Some(brace_pos) = rest.find("}") { - let func_name = rest[..brace_pos].trim(); - if !SYSTEM_FNS.contains(&func_name) { - func_names.push(func_name); - } + if let Some(brace) = rest.find('}') { + names.push(rest[..brace].trim().to_string()); } } } } + names +} + +/// Detect Durable Object class names by finding `ClassName__DURABLE_OBJECT_INIT` exports. +fn detect_do_classes(exported_fns: &[String]) -> Vec { + exported_fns + .iter() + .filter_map(|name| name.strip_suffix("__DURABLE_OBJECT_INIT").map(String::from)) + .collect() +} +/// Generate `Entrypoint.prototype.*` handler methods for Worker-level exports +/// (fetch, scheduled, queue, etc.), excluding system fns and DO method exports. +/// +/// In abort mode (`panic_unwind == false`), each handler is wrapped with +/// `checkReinitialize()` and a try/catch that flags `RuntimeError` as critical. +fn generate_handlers(exported_fns: &[String], panic_unwind: bool) -> String { let mut handlers = String::new(); - for func_name in func_names { + for func_name in exported_fns { + // Skip system functions + if SYSTEM_FNS.contains(&func_name.as_str()) { + continue; + } + // Skip DO method exports (contain "__") + if func_name.contains("__") { + continue; + } + if func_name == "fetch" && env::var("RUN_TO_COMPLETION").is_ok() { - handlers += "Entrypoint.prototype.fetch = async function fetch(request) { + if panic_unwind { + handlers += "Entrypoint.prototype.fetch = async function fetch(request) { let response = exports.fetch(request, this.env, this.ctx); this.ctx.waitUntil(response); return response; } "; + } else { + handlers += "Entrypoint.prototype.fetch = async function fetch(request) { + checkReinitialize(); + try { + let response = exports.fetch(request, this.env, this.ctx); + this.ctx.waitUntil(response); + return response; + } catch (e) { handleMaybeCritical(e); throw e; } +} +"; + } } else if func_name == "fetch" || func_name == "queue" || func_name == "scheduled" { - // TODO: Switch these over to https://github.com/wasm-bindgen/wasm-bindgen/pull/4757 - // once that lands. - handlers += &format!( - "Entrypoint.prototype.{func_name} = function {func_name} (arg) {{ + if panic_unwind { + handlers += &format!( + "Entrypoint.prototype.{func_name} = function {func_name} (arg) {{ return exports.{func_name}.call(this, arg, this.env, this.ctx); }} " + ); + } else { + handlers += &format!( + "Entrypoint.prototype.{func_name} = function {func_name} (arg) {{ + checkReinitialize(); + try {{ + return exports.{func_name}.call(this, arg, this.env, this.ctx); + }} catch (e) {{ handleMaybeCritical(e); throw e; }} +}} +" + ); + } + } else if panic_unwind { + handlers += &format!("Entrypoint.prototype.{func_name} = exports.{func_name};\n"); + } else { + handlers += &format!( + "Entrypoint.prototype.{func_name} = function {func_name} (...args) {{ + checkReinitialize(); + try {{ + return exports.{func_name}(...args); + }} catch (e) {{ handleMaybeCritical(e); throw e; }} +}} +" + ); + } + } + handlers +} + +/// Generate thin JS class wrappers for Durable Objects and a reinit callback. +/// +/// Each DO instance is stored in a Rust-side `HashMap` keyed by a +/// JS-assigned `u32`. A `FinalizationRegistry` calls the `__DURABLE_OBJECT_FREE` +/// export when the JS wrapper is garbage-collected, eagerly dropping the Rust +/// struct and freeing its memory. +/// +/// For the **unwind** shim, classes simply delegate to `exports.ClassName__method`. +/// The post-reinit hook callback re-initialises each DO with stashed state/env. +/// +/// For the **abort** shim, each method also includes `checkReinitialize()` and a +/// lazy staleness check via `instanceId`. +fn generate_do_classes( + do_classes: &[String], + exported_fns: &[String], + panic_unwind: bool, +) -> String { + if do_classes.is_empty() { + return String::new(); + } + + let mut output = String::new(); + + // Global key counter shared by all DO classes. + // Each DO instance gets a unique key used to look up the Rust struct. + output += "let __do_next_key = 0;\n"; + + // Map from key → { cls, state, env } for reinit after wasm reset. + output += "const __do_live = new Map();\n"; + + // FinalizationRegistry: when a JS DO wrapper is GC'd, free the Rust-side + // HashMap entry so the struct is dropped and its memory reclaimed. + output += "const __do_cleanup = new FinalizationRegistry(({ key, cls }) => {\n\ + \x20 exports[cls + '__DURABLE_OBJECT_FREE'](key);\n\ + \x20 __do_live.delete(key);\n\ + });\n\n"; + + for class_name in do_classes { + let methods: Vec<&str> = DO_METHOD_SUFFIXES + .iter() + .filter(|m| exported_fns.contains(&format!("{class_name}__{m}"))) + .copied() + .collect(); + + output += &format!("class {class_name} {{\n"); + + // Constructor: assign a key, stash state/env, call Rust init, register + // for GC-based cleanup. + if panic_unwind { + output += &format!( + " constructor(state, env) {{\n\ + \x20 this.__key = __do_next_key++;\n\ + \x20 __do_live.set(this.__key, {{ cls: \"{class_name}\", state, env }});\n\ + \x20 exports.{class_name}__DURABLE_OBJECT_INIT(this.__key, state, env);\n\ + \x20 __do_cleanup.register(this, {{ key: this.__key, cls: \"{class_name}\" }});\n\ + \x20 }}\n" ); } else { - handlers += &format!("Entrypoint.prototype.{func_name} = exports.{func_name};\n"); + output += &format!( + " constructor(state, env) {{\n\ + \x20 checkReinitialize();\n\ + \x20 this.__key = __do_next_key++;\n\ + \x20 this.__insId = instanceId;\n\ + \x20 __do_live.set(this.__key, {{ cls: \"{class_name}\", state, env }});\n\ + \x20 exports.{class_name}__DURABLE_OBJECT_INIT(this.__key, state, env);\n\ + \x20 __do_cleanup.register(this, {{ key: this.__key, cls: \"{class_name}\" }});\n\ + \x20 }}\n" + ); + } + + // Methods + for method in &methods { + let args = match *method { + "fetch" => "req", + "alarm" => "", + "webSocketMessage" => "ws, message", + "webSocketClose" => "ws, code, reason, was_clean", + "webSocketError" => "ws, error", + _ => "", + }; + let args_with_key = if args.is_empty() { + "this.__key".to_string() + } else { + format!("this.__key, {args}") + }; + + if panic_unwind { + output += &format!( + " {method}({args}) {{ return exports.{class_name}__{method}({args_with_key}); }}\n" + ); + } else { + output += &format!( + " {method}({args}) {{\n\ + \x20 checkReinitialize();\n\ + \x20 if (this.__insId !== instanceId) {{\n\ + \x20 const e = __do_live.get(this.__key);\n\ + \x20 if (e) exports[e.cls + '__DURABLE_OBJECT_INIT'](this.__key, e.state, e.env);\n\ + \x20 this.__insId = instanceId;\n\ + \x20 }}\n\ + \x20 try {{\n\ + \x20 return exports.{class_name}__{method}({args_with_key});\n\ + \x20 }} catch (e) {{ handleMaybeCritical(e); throw e; }}\n\ + \x20 }}\n" + ); + } } + + output += "}\n"; + output += &format!("export {{ {class_name} }};\n\n"); } - Ok(handlers) -} + // Reinit callback: after wasm reset, re-init every live DO instance + // with its stashed state/env so subsequent method calls succeed. + if panic_unwind { + output += "globalThis.__worker_reinit_dos = function () {\n\ + \x20 for (const [key, e] of __do_live) {\n\ + \x20 exports[e.cls + '__DURABLE_OBJECT_INIT'](key, e.state, e.env);\n\ + \x20 }\n\ + };\n"; + } -static SYSTEM_FNS: &[&str] = &["__wbg_reset_state", "setPanicHook"]; + output +} -fn add_export_wrappers(out_dir: &Path) -> Result<()> { +/// Re-export non-DO classes (wasm-bindgen utility types) directly, without Proxy. +fn add_class_reexports(out_dir: &Path, do_classes: &[String]) -> Result<()> { let index_path = output_path(out_dir, "index.js"); let content = fs::read_to_string(&index_path) .with_context(|| format!("Failed to read {}", index_path.display()))?; let mut class_names = Vec::new(); for line in content.lines() { - if let Some(rest) = line.strip_prefix("export class ") { - if let Some(brace_pos) = rest.find("{") { + let trimmed = line.trim_start(); + if let Some(rest) = trimmed.strip_prefix("export class ") { + if let Some(brace_pos) = rest.find('{') { let class_name = rest[..brace_pos].trim(); - class_names.push(class_name.to_string()); + // Only re-export non-DO classes (DOs are now flat fn exports) + if !do_classes.iter().any(|dc| dc == class_name) { + class_names.push(class_name.to_string()); + } } } } + if class_names.is_empty() { + return Ok(()); + } + let shim_path = output_path(out_dir, "shim.js"); let mut output = fs::read_to_string(&shim_path) .with_context(|| format!("Failed to read {}", shim_path.display()))?; - for class_name in class_names { - output.push_str(&format!( - "export const {class_name} = new Proxy(exports.{class_name}, classProxyHooks);\n" - )); + for class_name in &class_names { + use std::fmt::Write; + writeln!( + &mut output, + "export const {class_name} = exports.{class_name};" + )?; } fs::write(&shim_path, output) .with_context(|| format!("Failed to write {}", shim_path.display()))?; @@ -245,7 +443,7 @@ const INSTALL_HELP: &str = "In case you are missing the binary, you can install fn wasm_coredump(out_dir: &Path) -> Result<()> { let coredump_flags = env::var("COREDUMP_FLAGS"); let coredump_flags: Vec<&str> = if let Ok(flags) = &coredump_flags { - flags.split(' ').collect() + flags.split_whitespace().collect() } else { vec![] }; @@ -371,7 +569,7 @@ where // Bundles the snippets and worker-related code into a single file. fn bundle(out_dir: &Path, esbuild_path: &Path) -> Result<()> { - let no_minify = !matches!(env::var("NO_MINIFY"), Err(VarError::NotPresent)); + let minify = env::var("NO_MINIFY").is_err(); let path = out_dir .canonicalize() .with_context(|| format!("Failed to resolve output directory {}", out_dir.display()))?; @@ -390,7 +588,7 @@ fn bundle(out_dir: &Path, esbuild_path: &Path) -> Result<()> { "--allow-overwrite", ]); - if !no_minify { + if minify { command.arg("--minify"); } diff --git a/worker-build/src/versions.rs b/worker-build/src/versions.rs index 032f641ea..8a0b6d01a 100644 --- a/worker-build/src/versions.rs +++ b/worker-build/src/versions.rs @@ -7,12 +7,12 @@ macro_rules! version { } // Current build toolchain, always used exactly for builds, unless overridden by {}_BIN env vars -pub(crate) static LATEST_WASM_BINDGEN_VERSION: LazyLock = version!("0.2.113"); +pub(crate) static LATEST_WASM_BINDGEN_VERSION: LazyLock = version!("0.2.114"); pub(crate) static CUR_WASM_OPT_VERSION: &str = "126"; pub(crate) static CUR_ESBUILD_VERSION: LazyLock = version!("0.27.3"); // Minimum required libraries, validated before build -pub(crate) static MIN_WASM_BINDGEN_LIB_VERSION: LazyLock = version!("0.2.106"); +pub(crate) static MIN_WASM_BINDGEN_LIB_VERSION: LazyLock = version!("0.2.114"); pub(crate) static MIN_RUSTC_VERSION: LazyLock = version!("1.71.0"); // workers-rs MSRV pub(crate) static MIN_WORKER_LIB_VERSION: LazyLock = version!(&format!( diff --git a/worker-macros/src/durable_object.rs b/worker-macros/src/durable_object.rs index 41b6a3f52..31cca6fce 100644 --- a/worker-macros/src/durable_object.rs +++ b/worker-macros/src/durable_object.rs @@ -1,5 +1,5 @@ use proc_macro2::{Ident, TokenStream}; -use quote::quote; +use quote::{format_ident, quote}; use syn::{Error, ItemImpl, ItemStruct}; enum DurableObjectType { @@ -19,69 +19,158 @@ impl syn::parse::Parse for DurableObjectType { } } -mod bindgen_methods { - use proc_macro2::TokenStream; +/// Generate flat wasm_bindgen function exports for a Durable Object. +/// +/// Each DO instance is stored in a `thread_local! HashMap` keyed by an +/// instance ID assigned on the JS side. Every exported function takes the +/// instance key as its first `u32` argument so the correct instance is looked +/// up. A `__free` export is provided so the JS shim can eagerly drop instances +/// when they are no longer needed. +mod bindgen_fns { + use proc_macro2::{Ident, TokenStream}; use quote::quote; - pub fn core() -> TokenStream { + /// Wraps `body` in the boilerplate that borrows the instance from the map. + /// Inside `body`, `static_ref: &'static T` is available. + fn with_instance(class_name: &Ident, body: TokenStream) -> TokenStream { quote! { - #[wasm_bindgen(constructor, wasm_bindgen=::worker::wasm_bindgen)] - pub fn new( + __INSTANCES.with(|map| { + let borrow = map.borrow(); + let instance = borrow.get(&key) + .expect("Durable Object not initialized — call init first"); + // SAFETY: The instance reference is extended to `'static` lifetime for use + // inside the `async move` future handed to `future_to_promise`. This is + // sound under the following invariants: + // 1. The JS shim only calls `__free` inside the DO constructor, before + // any method is invoked on the new instance. The Workers runtime + // serialises requests to a DO, so no async future can be alive for a + // key that is about to be freed. + // 2. WASM is single-threaded; no concurrent mutation of the map is + // possible. + // 3. The Workers runtime serialises requests to a single DO instance so + // only one `async` future runs at a time per instance. + let static_ref: &'static #class_name = unsafe { &*(instance as *const _) }; + #body + }) + } + } + + pub fn init(class_name: &Ident, js_name: &str) -> TokenStream { + quote! { + #[wasm_bindgen(js_name = #js_name, wasm_bindgen=::worker::wasm_bindgen)] + pub fn __init( + key: u32, state: ::worker::worker_sys::DurableObjectState, env: ::worker::Env - ) -> Self { - ::new( + ) { + let instance = <#class_name as ::worker::DurableObject>::new( ::worker::durable::State::from(state), - env - ) + env, + ); + __INSTANCES.with(|map| map.borrow_mut().insert(key, instance)); } + } + } - #[wasm_bindgen(js_name = fetch, wasm_bindgen=::worker::wasm_bindgen)] - pub fn fetch( - &self, - req: ::worker::worker_sys::web_sys::Request - ) -> ::worker::js_sys::Promise { - // SAFETY: - // Durable Object will never be destroyed while there is still - // a running promise inside of it, therefore we can let a reference - // to the durable object escape into a static-lifetime future. - let static_self: &'static Self = unsafe { &*(self as *const _) }; - - ::worker::wasm_bindgen_futures::future_to_promise(::std::panic::AssertUnwindSafe(async move { - ::fetch(static_self, req.into()).await - .map(::worker::worker_sys::web_sys::Response::from) - .map(::worker::wasm_bindgen::JsValue::from) - .map_err(::worker::wasm_bindgen::JsValue::from) - })) + pub fn free(js_name: &str) -> TokenStream { + quote! { + #[wasm_bindgen(js_name = #js_name, wasm_bindgen=::worker::wasm_bindgen)] + pub fn __free(key: u32) { + __INSTANCES.with(|map| map.borrow_mut().remove(&key)); } } } - pub fn alarm() -> TokenStream { + pub fn fetch(class_name: &Ident, js_name: &str) -> TokenStream { + let body = with_instance( + class_name, + quote! { + ::worker::wasm_bindgen_futures::future_to_promise( + ::std::panic::AssertUnwindSafe(async move { + <#class_name as ::worker::DurableObject>::fetch(static_ref, req.into()).await + .map(::worker::worker_sys::web_sys::Response::from) + .map(::worker::wasm_bindgen::JsValue::from) + .map_err(::worker::wasm_bindgen::JsValue::from) + }) + ) + }, + ); quote! { - #[wasm_bindgen(js_name = alarm, wasm_bindgen=::worker::wasm_bindgen)] - pub fn alarm(&self) -> ::worker::js_sys::Promise { - // SAFETY: - // Durable Object will never be destroyed while there is still - // a running promise inside of it, therefore we can let a reference - // to the durable object escape into a static-lifetime future. - let static_self: &'static Self = unsafe { &*(self as *const _) }; - - ::worker::wasm_bindgen_futures::future_to_promise(::std::panic::AssertUnwindSafe(async move { - ::alarm(static_self).await - .map(::worker::worker_sys::web_sys::Response::from) - .map(::worker::wasm_bindgen::JsValue::from) - .map_err(::worker::wasm_bindgen::JsValue::from) - })) + #[wasm_bindgen(js_name = #js_name, wasm_bindgen=::worker::wasm_bindgen)] + pub fn __fetch(key: u32, req: ::worker::worker_sys::web_sys::Request) -> ::worker::js_sys::Promise { + #body } } } - pub fn websocket() -> TokenStream { + pub fn alarm(class_name: &Ident, js_name: &str) -> TokenStream { + let body = with_instance( + class_name, + quote! { + ::worker::wasm_bindgen_futures::future_to_promise( + ::std::panic::AssertUnwindSafe(async move { + <#class_name as ::worker::DurableObject>::alarm(static_ref).await + .map(::worker::worker_sys::web_sys::Response::from) + .map(::worker::wasm_bindgen::JsValue::from) + .map_err(::worker::wasm_bindgen::JsValue::from) + }) + ) + }, + ); quote! { - #[wasm_bindgen(js_name = webSocketMessage, wasm_bindgen=::worker::wasm_bindgen)] - pub fn websocket_message( - &self, + #[wasm_bindgen(js_name = #js_name, wasm_bindgen=::worker::wasm_bindgen)] + pub fn __alarm(key: u32) -> ::worker::js_sys::Promise { + #body + } + } + } + + pub fn websocket( + class_name: &Ident, + msg_name: &str, + close_name: &str, + error_name: &str, + ) -> TokenStream { + let msg_body = with_instance( + class_name, + quote! { + ::worker::wasm_bindgen_futures::future_to_promise( + ::std::panic::AssertUnwindSafe(async move { + <#class_name as ::worker::DurableObject>::websocket_message(static_ref, ws.into(), message).await + .map(|_| ::worker::wasm_bindgen::JsValue::NULL) + .map_err(::worker::wasm_bindgen::JsValue::from) + }) + ) + }, + ); + let close_body = with_instance( + class_name, + quote! { + ::worker::wasm_bindgen_futures::future_to_promise( + ::std::panic::AssertUnwindSafe(async move { + <#class_name as ::worker::DurableObject>::websocket_close(static_ref, ws.into(), code, reason, was_clean).await + .map(|_| ::worker::wasm_bindgen::JsValue::NULL) + .map_err(::worker::wasm_bindgen::JsValue::from) + }) + ) + }, + ); + let error_body = with_instance( + class_name, + quote! { + ::worker::wasm_bindgen_futures::future_to_promise( + ::std::panic::AssertUnwindSafe(async move { + <#class_name as ::worker::DurableObject>::websocket_error(static_ref, ws.into(), error.into()).await + .map(|_| ::worker::wasm_bindgen::JsValue::NULL) + .map_err(::worker::wasm_bindgen::JsValue::from) + }) + ) + }, + ); + quote! { + #[wasm_bindgen(js_name = #msg_name, wasm_bindgen=::worker::wasm_bindgen)] + pub fn __websocket_message( + key: u32, ws: ::worker::worker_sys::web_sys::WebSocket, message: ::worker::wasm_bindgen::JsValue ) -> ::worker::js_sys::Promise { @@ -91,58 +180,27 @@ mod bindgen_methods { ::worker::js_sys::Uint8Array::new(&message).to_vec() ) }; - - // SAFETY: - // Durable Object will never be destroyed while there is still - // a running promise inside of it, therefore we can let a reference - // to the durable object escape into a static-lifetime future. - let static_self: &'static Self = unsafe { &*(self as *const _) }; - - ::worker::wasm_bindgen_futures::future_to_promise(::std::panic::AssertUnwindSafe(async move { - ::websocket_message(static_self, ws.into(), message).await - .map(|_| ::worker::wasm_bindgen::JsValue::NULL) - .map_err(::worker::wasm_bindgen::JsValue::from) - })) + #msg_body } - #[wasm_bindgen(js_name = webSocketClose, wasm_bindgen=::worker::wasm_bindgen)] - pub fn websocket_close( - &self, + #[wasm_bindgen(js_name = #close_name, wasm_bindgen=::worker::wasm_bindgen)] + pub fn __websocket_close( + key: u32, ws: ::worker::worker_sys::web_sys::WebSocket, code: usize, reason: String, was_clean: bool ) -> ::worker::js_sys::Promise { - // SAFETY: - // Durable Object will never be destroyed while there is still - // a running promise inside of it, therefore we can let a reference - // to the durable object escape into a static-lifetime future. - let static_self: &'static Self = unsafe { &*(self as *const _) }; - - ::worker::wasm_bindgen_futures::future_to_promise(::std::panic::AssertUnwindSafe(async move { - ::websocket_close(static_self, ws.into(), code, reason, was_clean).await - .map(|_| ::worker::wasm_bindgen::JsValue::NULL) - .map_err(::worker::wasm_bindgen::JsValue::from) - })) + #close_body } - #[wasm_bindgen(js_name = webSocketError, wasm_bindgen=::worker::wasm_bindgen)] - pub fn websocket_error( - &self, + #[wasm_bindgen(js_name = #error_name, wasm_bindgen=::worker::wasm_bindgen)] + pub fn __websocket_error( + key: u32, ws: ::worker::worker_sys::web_sys::WebSocket, error: ::worker::wasm_bindgen::JsValue ) -> ::worker::js_sys::Promise { - // SAFETY: - // Durable Object will never be destroyed while there is still - // a running promise inside of it, therefore we can let a reference - // to the durable object escape into a static-lifetime future. - let static_self: &'static Self = unsafe { &*(self as *const _) }; - - ::worker::wasm_bindgen_futures::future_to_promise(::std::panic::AssertUnwindSafe(async move { - ::websocket_error(static_self, ws.into(), error.into()).await - .map(|_| ::worker::wasm_bindgen::JsValue::NULL) - .map_err(::worker::wasm_bindgen::JsValue::from) - })) + #error_body } } } @@ -153,7 +211,7 @@ pub fn expand_macro(attr: TokenStream, tokens: TokenStream) -> syn::Result(tokens.clone()).is_ok() { return Err(syn::Error::new( proc_macro2::Span::call_site(), - "The #[durable_object] macro is no longer required for `impl` blocks, and can be removed" + "The #[durable_object] macro is now only needed on the struct definition. Remove it from the impl block." )); } @@ -163,24 +221,52 @@ pub fn expand_macro(attr: TokenStream, tokens: TokenStream) -> syn::Result(attr)) .transpose()?; - let bindgen_methods = match durable_object_type { - // if not specified, bindgen all. - // this is expected behavior, and is also required for #[durable_object] to compile and work - None => vec![ - bindgen_methods::core(), - bindgen_methods::alarm(), - bindgen_methods::websocket(), - ], - - // if specified, bindgen only related methods. - Some(DurableObjectType::Fetch) => vec![bindgen_methods::core()], - Some(DurableObjectType::Alarm) => vec![bindgen_methods::core(), bindgen_methods::alarm()], + let target_name = &target.ident; + let class_str = target_name.to_string(); + + // Build JS export names: ClassName__method + // The init name uses a distinctive suffix so worker-build can reliably + // detect DO classes without false-positiving on user-defined exports. + let init_js = format!("{class_str}__DURABLE_OBJECT_INIT"); + let free_js = format!("{class_str}__DURABLE_OBJECT_FREE"); + let fetch_js = format!("{class_str}__fetch"); + let alarm_js = format!("{class_str}__alarm"); + let ws_msg_js = format!("{class_str}__webSocketMessage"); + let ws_close_js = format!("{class_str}__webSocketClose"); + let ws_err_js = format!("{class_str}__webSocketError"); + + let mut fns = vec![ + bindgen_fns::init(target_name, &init_js), + bindgen_fns::free(&free_js), + bindgen_fns::fetch(target_name, &fetch_js), + ]; + + match durable_object_type { + None => { + fns.push(bindgen_fns::alarm(target_name, &alarm_js)); + fns.push(bindgen_fns::websocket( + target_name, + &ws_msg_js, + &ws_close_js, + &ws_err_js, + )); + } + Some(DurableObjectType::Fetch) => {} + Some(DurableObjectType::Alarm) => { + fns.push(bindgen_fns::alarm(target_name, &alarm_js)); + } Some(DurableObjectType::WebSocket) => { - vec![bindgen_methods::core(), bindgen_methods::websocket()] + fns.push(bindgen_fns::websocket( + target_name, + &ws_msg_js, + &ws_close_js, + &ws_err_js, + )); } }; - let target_name = &target.ident; + let instances_static = format_ident!("__DO_INSTANCES_{}", class_str); + Ok(quote! { #target @@ -191,14 +277,15 @@ pub fn expand_macro(attr: TokenStream, tokens: TokenStream) -> syn::Result + > = ::std::cell::RefCell::new(::std::collections::HashMap::new()); } + + use #instances_static as __INSTANCES; + + #(#fns)* }; }) } diff --git a/worker/Cargo.toml b/worker/Cargo.toml index de87a9e40..881f2d6d3 100644 --- a/worker/Cargo.toml +++ b/worker/Cargo.toml @@ -8,7 +8,7 @@ keywords = ["serverless", "ffi", "workers", "wasm", "cloudflare"] license = "Apache-2.0" description = "A Rust SDK for writing Cloudflare Workers." readme = "../README.md" -rust-version = "1.75" +rust-version = "1.90" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/worker/src/analytics_engine.rs b/worker/src/analytics_engine.rs index a82c88761..d593eeda4 100644 --- a/worker/src/analytics_engine.rs +++ b/worker/src/analytics_engine.rs @@ -193,12 +193,12 @@ impl AnalyticsEngineDataPointBuilder { /// /// # Examples /// - /// ``` + /// ```no_run /// use worker::AnalyticsEngineDataPointBuilder; /// let point = AnalyticsEngineDataPointBuilder::new() /// .indexes(["index1"]) - /// .add_double(1) // value will be replaced by the following line - /// .doubles([1, 2, 3]) // sets double1, double2 and double3 + /// .add_double(1.0) // value will be replaced by the following line + /// .doubles([1.0, 2.0, 3.0]) // sets double1, double2 and double3 /// .build(); /// println!("{:?}", point); /// ``` @@ -284,7 +284,7 @@ impl AnalyticsEngineDataPointBuilder { /// /// # Examples /// - /// ``` + /// ```ignore /// use worker::{Env, AnalyticsEngineDataPointBuilder, Response}; /// use std::io::Error; /// diff --git a/worker/src/context.rs b/worker/src/context.rs index 30671c666..0f96dad65 100644 --- a/worker/src/context.rs +++ b/worker/src/context.rs @@ -27,7 +27,7 @@ impl Context { /// until the given future has been completed. The future is executed before the handler /// terminates but does not block the response. For example, this is ideal for caching /// responses or handling logging. - /// ```no_run + /// ```ignore /// context.wait_until(async move { /// let _ = cache.put(request, response).await; /// }); @@ -66,7 +66,7 @@ impl Context { /// ``` /// /// Then deserialize them to your custom type: - /// ```no_run + /// ```ignore /// use serde::Deserialize; /// /// #[derive(Deserialize)] diff --git a/worker/src/crypto.rs b/worker/src/crypto.rs index aa6a96de5..40cb8e0f0 100644 --- a/worker/src/crypto.rs +++ b/worker/src/crypto.rs @@ -7,7 +7,7 @@ use crate::send::SendFuture; /// A Rust-friendly wrapper around the non-standard [crypto.DigestStream](https://developers.cloudflare.com/workers/runtime-apis/web-crypto/#constructors) API /// /// Example usage: -/// ```rust +/// ```ignore /// let digest_stream = DigestStream::new(DigestStreamAlgorithm::Sha256); /// /// // create a ReadableStream from a string diff --git a/worker/src/date.rs b/worker/src/date.rs index b246a7934..66365b1de 100644 --- a/worker/src/date.rs +++ b/worker/src/date.rs @@ -7,6 +7,7 @@ use wasm_bindgen::JsValue; /// The equivalent to a JavaScript `Date` Object. /// ```no_run +/// # use worker::*; /// let now = Date::now(); /// let millis = now.as_millis(); /// // or use a specific point in time: @@ -26,6 +27,7 @@ impl PartialEq for Date { /// Initialize a `Date` by constructing this enum. /// ```no_run +/// # use worker::*; /// let t1: Date = DateInit::Millis(1630611511000).into(); /// let t2: Date = DateInit::String("Thu, 02 Sep 2021 19:38:31 GMT".to_string()).into(); /// ``` diff --git a/worker/src/durable.rs b/worker/src/durable.rs index 446866b49..19c461559 100644 --- a/worker/src/durable.rs +++ b/worker/src/durable.rs @@ -395,14 +395,14 @@ impl Storage { /// Takes an object and stores each of its keys and values to storage. /// - /// ```no_run + /// ```ignore /// # use worker::Storage; - /// use worker::JsValue; + /// use wasm_bindgen::JsValue; /// /// # let storage: Storage = todo!(); /// /// let obj = js_sys::Object::new(); - /// js_sys::Reflect::set(&obj, &JsValue::from_str("foo"), JsValue::from_u64(1)); + /// js_sys::Reflect::set(&obj, &JsValue::from_str("foo"), &JsValue::from_f64(1.0)); /// /// storage.put_multiple_raw(obj); /// ``` @@ -851,7 +851,7 @@ integrate them with the Workers Runtime, you must also add the **`#[durable_obje to the struct. ## Example -```no_run +```ignore use worker::*; #[durable_object] diff --git a/worker/src/dynamic_dispatch.rs b/worker/src/dynamic_dispatch.rs index 7ad76f89b..3907f1b0d 100644 --- a/worker/src/dynamic_dispatch.rs +++ b/worker/src/dynamic_dispatch.rs @@ -9,7 +9,7 @@ use crate::{env::EnvBinding, Fetcher, Result}; /// /// # Example: /// -/// ```no_run +/// ```ignore /// let dispatcher = env.dynamic_dispatcher("DISPATCHER")?; /// let fetcher = dispatcher.get("namespaced-worker-name")?; /// let resp = fetcher.fetch_request(req).await?; diff --git a/worker/src/fetcher.rs b/worker/src/fetcher.rs index f72231715..11b497ece 100644 --- a/worker/src/fetcher.rs +++ b/worker/src/fetcher.rs @@ -62,7 +62,7 @@ impl Fetcher { } /// Convert Fetcher into user-defined RPC interface. - /// ``` + /// ```ignore /// #[wasm_bindgen] /// extern "C" { /// #[wasm_bindgen(extends=js_sys::Object)] diff --git a/worker/src/lib.rs b/worker/src/lib.rs index 174427495..2f3d50432 100644 --- a/worker/src/lib.rs +++ b/worker/src/lib.rs @@ -11,7 +11,7 @@ //! //! Enables `queue` event type in [`[event]`](worker_macros::event) macro. //! -//! ``` +//! ```ignore //! // Consume messages from a queue //! #[event(queue)] //! pub async fn main(message_batch: MessageBatch, env: Env, _ctx: Context) -> Result<()> { @@ -34,7 +34,7 @@ //! //! The end result is being able to use frameworks like `axum` directly (see [example](./examples/axum)): //! -//! ```rust +//! ```ignore //! pub async fn root() -> &'static str { //! "Hello Axum!" //! } @@ -65,7 +65,7 @@ //! //! 1. [`send::SendFuture`] - wraps any `Future` and marks it as `Send`: //! -//! ```rust +//! ```ignore //! // `fut` is `Send` //! let fut = send::SendFuture::new(async move { //! // `JsFuture` is not `Send` @@ -76,7 +76,7 @@ //! 2. [`send::SendWrapper`] - Marks an arbitrary object as `Send` and implements `Deref` and `DerefMut`, as well as `Clone`, `Debug`, and `Display` if the //! inner type does. This is useful for attaching types as state to an `axum` `Router`: //! -//! ```rust +//! ```ignore //! // `KvStore` is not `Send` //! let store = env.kv("FOO")?; //! // `state` is `Send` @@ -89,7 +89,7 @@ //! `axum`'s `[debug_handler]` macro can help, and looking for warnings that a function or object cannot safely be sent //! between threads. //! -//! ```rust +//! ```ignore //! // This macro makes the whole function (i.e. the `Future` it returns) `Send`. //! #[worker::send] //! async fn handler(Extension(env): Extension) -> Response { @@ -100,7 +100,7 @@ //! } //! //! let router = axum::Router::new() -//! .route("/", get(handler)) +//! .route("/", get(handler)); //! ``` //! //! # RPC Support diff --git a/worker/src/panic_abort.rs b/worker/src/panic_abort.rs index 17527df5b..e1734d10c 100644 --- a/worker/src/panic_abort.rs +++ b/worker/src/panic_abort.rs @@ -4,17 +4,20 @@ use std::panic; use wasm_bindgen::prelude::*; #[cfg(target_arch = "wasm32")] -use std::cell::Cell; +use std::cell::RefCell; #[cfg(target_arch = "wasm32")] thread_local! { - static PANIC_CALLBACK: Cell> = Cell::new(None); + // RefCell (not Cell) so we can borrow the callback without consuming it. + // Using Cell::take() would remove the callback after the first panic, causing + // subsequent panics in unwind-mode to silently bypass the JS hook. + static PANIC_CALLBACK: RefCell> = RefCell::new(None); } #[cfg(target_arch = "wasm32")] #[wasm_bindgen(js_name = "setPanicHook")] pub fn set_panic_hook(callback: js_sys::Function) { - PANIC_CALLBACK.with(|f| f.set(Some(callback))); + PANIC_CALLBACK.with(|f| *f.borrow_mut() = Some(callback)); set_once(); } @@ -23,18 +26,56 @@ pub fn set_panic_hook(_callback: ()) { // No-op on non-wasm targets } +#[cfg(target_arch = "wasm32")] +#[wasm_bindgen] +extern "C" { + /// JS callback registered by the unwind shim on `globalThis` to + /// re-initialise Durable Object instances with their stashed state/env + /// after a wasm reinit. Guarded with `catch` so the call is a no-op + /// when the global is absent (e.g. abort-mode shim, or non-worker usage). + #[wasm_bindgen(catch, js_namespace = globalThis, js_name = "__worker_reinit_dos")] + fn worker_reinit_dos() -> Result<(), JsValue>; +} + +/// Abort handler: signals that the instance should be reinitialized after a +/// hard abort (unreachable, OOM, stack overflow). Called by wasm-bindgen's JS +/// glue via the indirect function table. Only effective on `panic=unwind` +/// builds; a no-op on `panic=abort`. +#[cfg(target_arch = "wasm32")] +fn on_abort() { + wasm_bindgen::handler::reinit(); +} + +/// Reinit handler: called on the NEW wasm instance after `__wbg_reset_state` +/// creates it. Re-installs the panic hook (the `std::sync::Once` is fresh on +/// a new instance) and invokes the JS-side callback that re-initialises +/// Durable Object instances with their stashed state/env. +/// Only effective on `panic=unwind` builds; a no-op on `panic=abort`. +#[cfg(target_arch = "wasm32")] +fn on_reinit() { + set_once(); + let _ = worker_reinit_dos(); +} + #[allow(deprecated)] #[cfg(target_arch = "wasm32")] fn hook_impl(info: &panic::PanicInfo) { let message = info.to_string(); PANIC_CALLBACK.with(|f| { - if let Some(callback) = f.take() { + // Borrow without consuming so the callback remains registered for + // subsequent panics (important in panic=unwind mode where the worker + // continues after a caught panic). + if let Some(callback) = f.borrow().as_ref() { use js_sys::JsString; - if let Err(e) = callback.call1(&JsValue::UNDEFINED, &JsString::from(message)) { + if let Err(e) = callback.call1(&JsValue::UNDEFINED, &JsString::from(message.as_str())) { web_sys::console::error_2(&"Failed to call panic callback:".into(), &e); } + } else { + // No JS callback registered (e.g. after reinit before the shim + // re-registers one). Fall back to logging directly. + web_sys::console::error_1(&format!("Rust panic: {message}").into()); } }); } @@ -47,13 +88,24 @@ fn hook_impl(_info: &panic::PanicInfo) { } /// Set the WASM reinitialization panic hook the first time this is called. -/// Subsequent invocations do nothing. +/// Subsequent invocations do nothing. On `panic=unwind` builds, also +/// registers the abort and reinit handlers via `wasm_bindgen::handler`. #[allow(dead_code)] #[inline] fn set_once() { use std::sync::Once; static SET_HOOK: Once = Once::new(); SET_HOOK.call_once(|| { + // Register abort handler for hard-abort recovery (unreachable, OOM, etc.). + // On panic=unwind builds this fires from __wbg_handle_catch and signals + // reinit so the next export call creates a fresh instance. + // On panic=abort builds these are no-ops. + #[cfg(target_arch = "wasm32")] + { + wasm_bindgen::handler::set_on_abort(on_abort); + wasm_bindgen::handler::set_on_reinit(on_reinit); + } + let default_hook = panic::take_hook(); panic::set_hook(Box::new(move |panic_info| { // First call the existing hook (console_error_panic_hook if set) diff --git a/worker/src/r2/builder.rs b/worker/src/r2/builder.rs index e339695ff..c002e1b38 100644 --- a/worker/src/r2/builder.rs +++ b/worker/src/r2/builder.rs @@ -311,7 +311,7 @@ impl CreateMultipartUploadOptionsBuilder<'_> { } /// Metadata that's automatically rendered into R2 HTTP API endpoints. -/// ``` +/// ```text /// * contentType -> content-type /// * contentLanguage -> content-language /// etc... @@ -399,10 +399,10 @@ impl ListOptionsBuilder<'_> { /// you are sending into one bucket. Make sure to look at `truncated` for the result /// rather than having logic like /// - /// ```no_run + /// ```ignore /// while listed.len() < limit { /// listed = bucket.list() - /// .limit(limit), + /// .limit(limit) /// .include(vec![Include::CustomMetadata]) /// .execute() /// .await?; diff --git a/worker/src/response.rs b/worker/src/response.rs index 4ffac586b..83e43ca64 100644 --- a/worker/src/response.rs +++ b/worker/src/response.rs @@ -383,7 +383,8 @@ impl ResponseBuilder { /// Sets this response's cors headers from the `Cors` struct. /// Example usage: - /// ``` + /// ```ignore + /// use worker::*; /// let cors = Cors::default(); /// ResponseBuilder::new() /// .with_cors(&cors) diff --git a/worker/src/send.rs b/worker/src/send.rs index b565c9b9a..421ca5fe0 100644 --- a/worker/src/send.rs +++ b/worker/src/send.rs @@ -15,7 +15,7 @@ use std::task::Poll; #[pin_project] /// Wrap any future to make it `Send`. /// -/// ```rust +/// ```ignore /// let fut = SendFuture::new(JsFuture::from(promise)); /// fut.await /// ``` @@ -44,7 +44,7 @@ impl Future for SendFuture { /// Trait for SendFuture. Implemented for any type that implements Future. /// -/// ```rust +/// ```ignore /// let fut = JsFuture::from(promise).into_send(); /// fut.await /// ``` @@ -67,7 +67,7 @@ where /// Wrap any type to make it `Send`. /// -/// ```rust +/// ```ignore /// // js_sys::Promise is !Send /// let send_promise = SendWrapper::new(promise); /// ```