diff --git a/.gitignore b/.gitignore index 172c621c5..f8077b5a7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -/target +target/ .DS_Store .cursor diff --git a/Cargo.lock b/Cargo.lock index 70fabd5f7..18eb3f797 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,15 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "addr2line" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59317f77929f0e679d39364702289274de2f0f0b22cbf50b2b8cff2169a0b27a" +dependencies = [ + "gimli", +] + [[package]] name = "adler2" version = "2.0.1" @@ -85,18 +94,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] -name = "anstream" -version = "0.6.21" +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 = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" dependencies = [ - "anstyle", - "anstyle-parse 0.2.7", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", + "libc", ] [[package]] @@ -106,7 +115,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" dependencies = [ "anstyle", - "anstyle-parse 1.0.0", + "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", @@ -120,15 +129,6 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" -[[package]] -name = "anstyle-parse" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" -dependencies = [ - "utf8parse", -] - [[package]] name = "anstyle-parse" version = "1.0.0" @@ -144,7 +144,7 @@ version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -155,7 +155,7 @@ checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -176,7 +176,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7eb93bbb63b9c227414f6eb3a0adfddca591a8ce1e9b60661bb08969b87e340b" dependencies = [ - "object", + "object 0.37.3", ] [[package]] @@ -187,9 +187,9 @@ checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" [[package]] name = "arc-swap" -version = "1.9.0" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a07d1f37ff60921c83bdfc7407723bdefe89b44b98a9b772f225c8f9d67141a6" +checksum = "6a3a1fd6f75306b68087b831f025c712524bcb19aad54e557b1129cfa0a2b207" dependencies = [ "rustversion", ] @@ -226,9 +226,9 @@ dependencies = [ [[package]] name = "assert_cmd" -version = "2.2.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a686bbee5efb88a82df0621b236e74d925f470e5445d3220a5648b892ec99c9" +checksum = "39bae1d3fa576f7c6519514180a72559268dd7d1fe104070956cb687bc6673bd" dependencies = [ "anstyle", "bstr", @@ -326,7 +326,7 @@ dependencies = [ "futures-lite", "parking", "polling", - "rustix", + "rustix 1.1.4", "slab", "windows-sys 0.61.2", ] @@ -357,7 +357,7 @@ dependencies = [ "cfg-if", "event-listener 5.4.1", "futures-lite", - "rustix", + "rustix 1.1.4", ] [[package]] @@ -384,9 +384,9 @@ dependencies = [ [[package]] name = "async-signal" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43c070bbf59cd3570b6b2dd54cd772527c7c3620fce8be898406dd3ed6adc64c" +checksum = "52b5aaafa020cf5053a01f2a60e8ff5dccf550f0f77ec54a4e47285ac2bab485" dependencies = [ "async-io", "async-lock", @@ -394,7 +394,7 @@ dependencies = [ "cfg-if", "futures-core", "futures-io", - "rustix", + "rustix 1.1.4", "signal-hook-registry", "slab", "windows-sys 0.61.2", @@ -451,9 +451,9 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "aws-lc-rs" -version = "1.16.2" +version = "1.16.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a054912289d18629dc78375ba2c3726a3afe3ff71b4edba9dedfca0e3446d1fc" +checksum = "0ec6fb3fe69024a75fa7e1bfb48aa6cf59706a101658ea01bfd33b2b248a038f" dependencies = [ "aws-lc-sys", "zeroize", @@ -461,9 +461,9 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.39.0" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa7e52a4c5c547c741610a2c6f123f3881e409b714cd27e6798ef020c514f0a" +checksum = "f50037ee5e1e41e7b8f9d161680a725bd1626cb6f8c7e901f91f942850852fe7" dependencies = [ "cc", "cmake", @@ -541,7 +541,7 @@ dependencies = [ "getrandom 0.2.17", "instant", "pin-project-lite", - "rand 0.8.5", + "rand 0.8.6", "tokio", ] @@ -668,9 +668,18 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.11.0" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" + +[[package]] +name = "bitmaps" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" +checksum = "031043d04099746d8db04daf1fa424b2bc8bd69d92b25962dcde24da39ab64a2" +dependencies = [ + "typenum", +] [[package]] name = "bitvec" @@ -862,6 +871,9 @@ name = "bumpalo" version = "3.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" +dependencies = [ + "allocator-api2", +] [[package]] name = "byte-unit" @@ -981,9 +993,9 @@ dependencies = [ [[package]] name = "candid" -version = "0.10.26" +version = "0.10.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "846adba6d1b4a00eeb8d4a0e4b88dfab570c25ad150cd52e51dfdc4f9d0a66cd" +checksum = "1ba5b4833b63bf7b785fecdd2cc918ed90d988fd974825d5c48e7b407c39ef38" dependencies = [ "anyhow", "binread", @@ -1004,9 +1016,9 @@ dependencies = [ [[package]] name = "candid_derive" -version = "0.10.26" +version = "0.10.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c367110b158be2edc335a4ad70f3467fa588d5c5675e149ef38638a8e281fc4" +checksum = "7b60664b6324832dfb4863f3b19eb4d58819cd38fba6d3941b101213cea0d9ec" dependencies = [ "lazy_static", "proc-macro2", @@ -1016,9 +1028,9 @@ dependencies = [ [[package]] name = "candid_parser" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "331d5ed7e9a460cd0db8f1c7641a30fb86d50c1e209a5f8053bc0fbb7c1a5da2" +checksum = "50e7b872ea5d7b8b445b7b15134ccb7d71e53882c4b5db62e706f9f8a8637c50" dependencies = [ "anyhow", "candid", @@ -1039,11 +1051,89 @@ dependencies = [ "toml 0.8.23", ] +[[package]] +name = "cap-fs-ext" +version = "3.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5528f85b1e134ae811704e41ef80930f56e795923f866813255bc342cc20654" +dependencies = [ + "cap-primitives", + "cap-std", + "io-lifetimes", + "windows-sys 0.52.0", +] + +[[package]] +name = "cap-net-ext" +version = "3.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20a158160765c6a7d0d8c072a53d772e4cb243f38b04bfcf6b4939cfbe7482e7" +dependencies = [ + "cap-primitives", + "cap-std", + "rustix 1.1.4", + "smallvec", +] + +[[package]] +name = "cap-primitives" +version = "3.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6cf3aea8a5081171859ef57bc1606b1df6999df4f1110f8eef68b30098d1d3a" +dependencies = [ + "ambient-authority", + "fs-set-times", + "io-extras", + "io-lifetimes", + "ipnet", + "maybe-owned", + "rustix 1.1.4", + "rustix-linux-procfs", + "windows-sys 0.52.0", + "winx", +] + +[[package]] +name = "cap-rand" +version = "3.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8144c22e24bbcf26ade86cb6501a0916c46b7e4787abdb0045a467eb1645a1d" +dependencies = [ + "ambient-authority", + "rand 0.8.6", +] + +[[package]] +name = "cap-std" +version = "3.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6dc3090992a735d23219de5c204927163d922f42f575a0189b005c62d37549a" +dependencies = [ + "cap-primitives", + "io-extras", + "io-lifetimes", + "rustix 1.1.4", +] + +[[package]] +name = "cap-time-ext" +version = "3.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "def102506ce40c11710a9b16e614af0cde8e76ae51b1f48c04b8d79f4b671a80" +dependencies = [ + "ambient-authority", + "cap-primitives", + "iana-time-zone", + "once_cell", + "rustix 1.1.4", + "winx", +] + [[package]] name = "cargo-generate" -version = "0.23.7" +version = "0.23.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6ecf1e81816c3dbe016101d21a198ec0f4a55bb04173ff9d3071ebb626f2cc1" +checksum = "0c3b0a106ac22b8fcd7dee8fb5b21c9276564866d954244324a7bdd346ebdb68" dependencies = [ "anstyle", "anyhow", @@ -1068,7 +1158,7 @@ dependencies = [ "log", "names", "openssl", - "paste", + "pastey", "regex", "remove_dir_all", "rhai", @@ -1109,9 +1199,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.57" +version = "1.2.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a0dd1ca384932ff3641c8718a02769f1698e7563dc6974ffd03346116310423" +checksum = "43c5703da9466b66a946814e1adf53ea2c90f10063b86290cc9eb67ce3478a20" dependencies = [ "find-msvc-tools", "jobserver", @@ -1145,7 +1235,7 @@ checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" dependencies = [ "cfg-if", "cpufeatures 0.3.0", - "rand_core 0.10.0", + "rand_core 0.10.1", ] [[package]] @@ -1183,7 +1273,7 @@ version = "4.5.61" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2071365c5c56eae7d77414029dde2f4f4ba151cf68d5a3261c9a40de428ace93" dependencies = [ - "anstream 1.0.0", + "anstream", "anstyle", "clap_lex", "strsim", @@ -1210,9 +1300,9 @@ checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" [[package]] name = "cmake" -version = "0.1.57" +version = "0.1.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d" +checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678" dependencies = [ "cc", ] @@ -1223,6 +1313,15 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f88a43d011fc4a6876cb7344703e297c71dda42494fee094d5f7c76bf13f746" +[[package]] +name = "cobs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" +dependencies = [ + "thiserror 2.0.18", +] + [[package]] name = "codespan-reporting" version = "0.11.1" @@ -1350,6 +1449,15 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "cpp_demangle" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2bb79cb74d735044c972aae58ed0aaa9a837e85b01106a54c39e42e97f62253" +dependencies = [ + "cfg-if", +] + [[package]] name = "cpufeatures" version = "0.2.17" @@ -1368,6 +1476,148 @@ dependencies = [ "libc", ] +[[package]] +name = "cranelift-assembler-x64" +version = "0.130.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "046d4b584c3bb9b5eb500c8f29549bec36be11000f1ba2a927cef3d1a9875691" +dependencies = [ + "cranelift-assembler-x64-meta", +] + +[[package]] +name = "cranelift-assembler-x64-meta" +version = "0.130.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9b194a7870becb1490366fc0ae392ccd188065ff35f8391e77ac659db6fb977" +dependencies = [ + "cranelift-srcgen", +] + +[[package]] +name = "cranelift-bforest" +version = "0.130.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb6a4ab44c6b371e661846b97dab687387a60ac4e2f864e2d4257284aad9e889" +dependencies = [ + "cranelift-entity", + "wasmtime-internal-core", +] + +[[package]] +name = "cranelift-bitset" +version = "0.130.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8b7a44150c2f471a94023482bda1902710746e4bed9f9973d60c5a94319b06d" +dependencies = [ + "serde", + "serde_derive", + "wasmtime-internal-core", +] + +[[package]] +name = "cranelift-codegen" +version = "0.130.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01b06598133b1dd76758b8b95f8d6747c124124aade50cea96a3d88b962da9fa" +dependencies = [ + "bumpalo", + "cranelift-assembler-x64", + "cranelift-bforest", + "cranelift-bitset", + "cranelift-codegen-meta", + "cranelift-codegen-shared", + "cranelift-control", + "cranelift-entity", + "cranelift-isle", + "gimli", + "hashbrown 0.16.1", + "libm", + "log", + "pulley-interpreter", + "regalloc2", + "rustc-hash 2.1.2", + "serde", + "smallvec", + "target-lexicon", + "wasmtime-internal-core", +] + +[[package]] +name = "cranelift-codegen-meta" +version = "0.130.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6190e2e7bcf0a678da2f715363d34ed530fedf7a2f0ab75edaefef72a70465ff" +dependencies = [ + "cranelift-assembler-x64-meta", + "cranelift-codegen-shared", + "cranelift-srcgen", + "heck", + "pulley-interpreter", +] + +[[package]] +name = "cranelift-codegen-shared" +version = "0.130.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f583cf203d1aa8b79560e3b01f929bdacf9070b015eec4ea9c46e22a3f83e4a0" + +[[package]] +name = "cranelift-control" +version = "0.130.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "803159df35cc398ae54473c150b16d6c77e92ab2948be638488de126a3328fbc" +dependencies = [ + "arbitrary", +] + +[[package]] +name = "cranelift-entity" +version = "0.130.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3109e417257082d88087f5bcce677525bdaa8322b88dd7f175ed1a1fd41d546c" +dependencies = [ + "cranelift-bitset", + "serde", + "serde_derive", + "wasmtime-internal-core", +] + +[[package]] +name = "cranelift-frontend" +version = "0.130.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14db6b0e0e4994c581092df78d837be2072578f7cb2528f96a6cf895e56dee63" +dependencies = [ + "cranelift-codegen", + "log", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cranelift-isle" +version = "0.130.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec66ea5025c7317383699778282ac98741d68444f956e3b1d7b62f12b7216e67" + +[[package]] +name = "cranelift-native" +version = "0.130.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "373ade56438e6232619d85678477d0a88a31b3581936e0503e61e96b546b0800" +dependencies = [ + "cranelift-codegen", + "libc", + "target-lexicon", +] + +[[package]] +name = "cranelift-srcgen" +version = "0.130.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53619d3cd5c78fd998c6d9420547af26b72e6456f94c2a8a2334cb76b42baa" + [[package]] name = "crc32fast" version = "1.5.0" @@ -1454,7 +1704,7 @@ version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff765b99fc49f3116c9a908484486a2b92fd73c48da45c3a69716471c6cc56c6" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "cryptoki-sys", "libloading 0.8.9", "log", @@ -1611,6 +1861,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "debugid" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d" +dependencies = [ + "uuid", +] + [[package]] name = "der" version = "0.7.10" @@ -1746,6 +2005,16 @@ dependencies = [ "dirs-sys", ] +[[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 = "6.0.0" @@ -1774,7 +2043,7 @@ dependencies = [ "libc", "option-ext", "redox_users 0.5.2", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -1794,7 +2063,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "block2", "libc", "objc2", @@ -1914,6 +2183,18 @@ dependencies = [ "serde", ] +[[package]] +name = "embedded-io" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" + +[[package]] +name = "embedded-io" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" + [[package]] name = "ena" version = "0.14.4" @@ -1967,9 +2248,9 @@ dependencies = [ [[package]] name = "env_filter" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a1c3cc8e57274ec99de65301228b537f1e4eedc1b8e0f9411c6caac8ae7308f" +checksum = "32e90c2accc4b07a8456ea0debdc2e7587bdd890680d71173a15d4ae604f6eef" dependencies = [ "log", "regex", @@ -1977,11 +2258,11 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.11.9" +version = "0.11.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2daee4ea451f429a58296525ddf28b45a3b64f1acf6587e2067437bb11e218d" +checksum = "0621c04f2196ac3f488dd583365b9c09be011a4ab8b9f37248ffcc8f6198b56a" dependencies = [ - "anstream 0.6.21", + "anstream", "anstyle", "env_filter", "jiff", @@ -2021,7 +2302,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -2074,9 +2355,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.3.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" [[package]] name = "fd-lock" @@ -2085,8 +2366,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ce92ff622d6dadf7349484f42c93271a0d49b7cc4d466a936405bacbe10aa78" dependencies = [ "cfg-if", - "rustix", - "windows-sys 0.59.0", + "rustix 1.1.4", + "windows-sys 0.52.0", ] [[package]] @@ -2213,13 +2494,24 @@ dependencies = [ [[package]] name = "fs-err" -version = "3.1.3" +version = "3.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ad492b2cf1d89d568a43508ab24f98501fe03f2f31c01e1d0fe7366a71745d2" +checksum = "baf68cef89750956493a66a10f512b9e58d9db21f2a573c079c0bdf1207a54a7" dependencies = [ "autocfg", ] +[[package]] +name = "fs-set-times" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94e7099f6313ecacbe1256e8ff9d617b75d1bcb16a6fddef94866d225a01a14a" +dependencies = [ + "io-lifetimes", + "rustix 1.1.4", + "windows-sys 0.52.0", +] + [[package]] name = "fs_at" version = "0.2.1" @@ -2377,6 +2669,20 @@ dependencies = [ "slab", ] +[[package]] +name = "fxprof-processed-profile" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25234f20a3ec0a962a61770cfe39ecf03cb529a6e474ad8cff025ed497eda557" +dependencies = [ + "bitflags 2.11.1", + "debugid", + "rustc-hash 2.1.2", + "serde", + "serde_derive", + "serde_json", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -2424,18 +2730,30 @@ dependencies = [ "cfg-if", "libc", "r-efi 6.0.0", - "rand_core 0.10.0", + "rand_core 0.10.1", "wasip2", "wasip3", ] +[[package]] +name = "gimli" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf7f043f89559805f8c7cacc432749b2fa0d0a0a9ee46ce47164ed5ba7f126c" +dependencies = [ + "fnv", + "hashbrown 0.16.1", + "indexmap", + "stable_deref_trait", +] + [[package]] name = "git2" version = "0.20.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b88256088d75a56f8ecfa070513a775dd9107f6530ef14919dac831af9cfe2b" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "libc", "libgit2-sys", "log", @@ -2446,9 +2764,9 @@ dependencies = [ [[package]] name = "gix-actor" -version = "0.35.6" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "987a51a7e66db6ef4dc030418eb2a42af6b913a79edd8670766122d8af3ba59e" +checksum = "636ca0d7bf8f7ad8ba84a5dda8312c8944b275be09d88b072e08f57d3e47c1e8" dependencies = [ "bstr", "gix-date", @@ -2460,9 +2778,9 @@ dependencies = [ [[package]] name = "gix-config" -version = "0.46.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfb898c5b695fd4acfc3c0ab638525a65545d47706064dcf7b5ead6cdb136c0" +checksum = "9419284839421488b5ab9b9b88386bdc1e159a986c08e17ffa3e9a5cd2b139f5" dependencies = [ "bstr", "gix-config-value", @@ -2472,7 +2790,6 @@ dependencies = [ "gix-ref", "gix-sec", "memchr", - "once_cell", "smallvec", "thiserror 2.0.18", "unicode-bom", @@ -2485,7 +2802,7 @@ version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c489abb061c74b0c3ad790e24a606ef968cebab48ec673d6a891ece7d5aef64" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "bstr", "gix-path", "libc", @@ -2494,9 +2811,9 @@ dependencies = [ [[package]] name = "gix-date" -version = "0.10.7" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "661245d045aa7c16ba4244daaabd823c562c3e45f1f25b816be2c57ee09f2171" +checksum = "c0a1259955c76335c9d1a8c511811b10dbc800ffeeca3daea1e0aadd0c98f6b7" dependencies = [ "bstr", "itoa", @@ -2507,9 +2824,9 @@ dependencies = [ [[package]] name = "gix-features" -version = "0.43.1" +version = "0.44.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd1543cd9b8abcbcebaa1a666a5c168ee2cda4dea50d3961ee0e6d1c42f81e5b" +checksum = "dfa64593d1586135102307fb57fb3a9d3868b6b1f45a4da1352cce5070f8916a" dependencies = [ "gix-path", "gix-trace", @@ -2521,9 +2838,9 @@ dependencies = [ [[package]] name = "gix-fs" -version = "0.16.1" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a4d90307d064fa7230e0f87b03231be28f8ba63b913fc15346f489519d0c304" +checksum = "3f1ecd896258cdc5ccd94d18386d17906b8de265ad2ecf68e3bea6b007f6a28f" dependencies = [ "bstr", "fastrand", @@ -2535,11 +2852,11 @@ dependencies = [ [[package]] name = "gix-glob" -version = "0.21.0" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b947db8366823e7a750c254f6bb29e27e17f27e457bf336ba79b32423db62cd5" +checksum = "74254992150b0a88fdb3ad47635ab649512dff2cbbefca7916bb459894fc9d56" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "bstr", "gix-features", "gix-path", @@ -2547,9 +2864,9 @@ dependencies = [ [[package]] name = "gix-hash" -version = "0.19.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "251fad79796a731a2a7664d9ea95ee29a9e99474de2769e152238d4fdb69d50e" +checksum = "826036a9bee95945b0be1e2394c64cd4289916c34a639818f8fd5153906985c1" dependencies = [ "faster-hex", "gix-features", @@ -2559,20 +2876,20 @@ dependencies = [ [[package]] name = "gix-hashtable" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c35300b54896153e55d53f4180460931ccd69b7e8d2f6b9d6401122cdedc4f07" +checksum = "a27d4a3ea9640da504a2657fef3419c517fd71f1767ad8935298bcc805edd195" dependencies = [ "gix-hash", - "hashbrown 0.15.5", + "hashbrown 0.16.1", "parking_lot 0.12.5", ] [[package]] name = "gix-lock" -version = "18.0.0" +version = "19.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9fa71da90365668a621e184eb5b979904471af1b3b09b943a84bc50e8ad42ed" +checksum = "729d7857429a66023bc0c29d60fa21d0d6ae8862f33c1937ba89e0f74dd5c67f" dependencies = [ "gix-tempfile", "gix-utils", @@ -2581,9 +2898,9 @@ dependencies = [ [[package]] name = "gix-object" -version = "0.50.2" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d69ce108ab67b65fbd4fb7e1331502429d78baeb2eee10008bdef55765397c07" +checksum = "84743d1091c501a56f00d7f4c595cb30f20fcef6503b32ac0a1ff3817efd7b5d" dependencies = [ "bstr", "gix-actor", @@ -2614,9 +2931,9 @@ dependencies = [ [[package]] name = "gix-ref" -version = "0.53.1" +version = "0.55.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b966f578079a42f4a51413b17bce476544cca1cf605753466669082f94721758" +checksum = "e51330a32f173c8e831731dfef8e93a748c23c057f4b028841f222564cad84cb" dependencies = [ "gix-actor", "gix-features", @@ -2639,7 +2956,7 @@ version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea9962ed6d9114f7f100efe038752f41283c225bb507a2888903ac593dffa6be" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "gix-path", "libc", "windows-sys 0.61.2", @@ -2647,13 +2964,12 @@ dependencies = [ [[package]] name = "gix-tempfile" -version = "18.0.0" +version = "19.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "666c0041bcdedf5fa05e9bef663c897debab24b7dc1741605742412d1d47da57" +checksum = "e265fc6b54e57693232a79d84038381ebfda7b1a3b1b8a9320d4d5fe6e820086" dependencies = [ "gix-fs", "libc", - "once_cell", "parking_lot 0.12.5", "tempfile", ] @@ -2797,6 +3113,12 @@ dependencies = [ "serde_core", ] +[[package]] +name = "hashbrown" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" + [[package]] name = "heapless" version = "0.8.0" @@ -2963,9 +3285,9 @@ dependencies = [ [[package]] name = "hyper" -version = "1.8.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" +checksum = "6299f016b246a94207e63da54dbe807655bf9e00044f73ded42c3ac5305fbcca" dependencies = [ "atomic-waker", "bytes", @@ -2978,7 +3300,6 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "pin-utils", "smallvec", "tokio", "want", @@ -3001,15 +3322,14 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.7" +version = "0.27.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f" dependencies = [ "http", "hyper", "hyper-util", "rustls", - "rustls-pki-types", "tokio", "tokio-rustls", "tower-service", @@ -3056,20 +3376,44 @@ dependencies = [ ] [[package]] -name = "ic-agent" -version = "0.47.0" +name = "iana-time-zone" +version = "0.1.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "087c953695a2581a1e58a23a88e16a19e5eb2638ecefeea0bde22f23d8896786" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" dependencies = [ - "arc-swap", - "async-channel 2.5.0", - "async-lock", - "async-trait", - "async-watch", - "backoff", - "bytes", - "cached", - "candid", + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core 0.61.2", +] + +[[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 = "ic-agent" +version = "0.47.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "694f78a861d8a0643ecee96926573fc44ab43de9fc74e4443c2174a527d243ad" +dependencies = [ + "arc-swap", + "async-channel 2.5.0", + "async-lock", + "async-trait", + "async-watch", + "backoff", + "bytes", + "cached", + "candid", "ecdsa", "ed25519-consensus", "elliptic-curve", @@ -3182,9 +3526,9 @@ dependencies = [ [[package]] name = "ic-certification" -version = "3.1.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c11273a40f8d67926ee423b0bd21381ae8419db809b42f33c5cb3319549b40f" +checksum = "754e3037360152de7e5f2bd0ccf51db8864b6a03c5a2b4ffc6a65286c0e2ffa7" dependencies = [ "hex", "serde", @@ -3204,7 +3548,7 @@ dependencies = [ "hkdf", "ic_principal", "pem", - "rand 0.8.5", + "rand 0.8.6", "thiserror 2.0.18", "zeroize", ] @@ -3222,9 +3566,9 @@ dependencies = [ [[package]] name = "ic-identity-hsm" -version = "0.47.0" +version = "0.47.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "979ad4a529f16a1d2fea2904c0a8dd9500668b02f9fcb8ebcb7694621bd9f369" +checksum = "8fbebd7ee04ef421df6d170cdfea8fe77259a9fec00f7dbc1dc7f4535c605941" dependencies = [ "hex", "ic-agent", @@ -3282,9 +3626,9 @@ dependencies = [ [[package]] name = "ic-transport-types" -version = "0.47.0" +version = "0.47.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a91a2dc71282291a7c26ec7c23e57335fc4a562a6b0b571ede0044790a68a3f" +checksum = "aa56b9d37b063451c2aadd864030d587d7c050001a26f55b2416cb33a74646f3" dependencies = [ "candid", "hex", @@ -3300,9 +3644,9 @@ dependencies = [ [[package]] name = "ic-utils" -version = "0.47.0" +version = "0.47.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4dac90c041fee47ed98d9f2d1bb3455fb79c43bc4730af3c91f29aec3822e52" +checksum = "4431c306a7e0c7fd126fed3a200b925b5037692ae3e5a847741549d1c6d86418" dependencies = [ "async-trait", "candid", @@ -3330,15 +3674,15 @@ dependencies = [ "ic_bls12_381", "lazy_static", "pairing", - "rand 0.8.5", + "rand 0.8.6", "sha2 0.10.9", ] [[package]] name = "ic0" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1499d08fd5be8f790d477e1865d63bab6a8d748300e141270c4296e6d5fdd6bc" +checksum = "c77c8932bff1f09502d0d8c079d5a206a06afe523e35e816162cf4d30b5bf80d" [[package]] name = "ic_bls12_381" @@ -3404,6 +3748,7 @@ dependencies = [ "ic-management-canister-types 0.7.1", "ic-utils", "icp-canister-interfaces", + "icp-sync-plugin", "icrc-ledger-types", "indoc", "itertools 0.14.0", @@ -3529,6 +3874,21 @@ dependencies = [ "wslpath2", ] +[[package]] +name = "icp-sync-plugin" +version = "0.2.3" +dependencies = [ + "camino", + "candid", + "hex", + "ic-agent", + "icp-canister-interfaces", + "snafu", + "tokio", + "wasmtime", + "wasmtime-wasi", +] + [[package]] name = "icrc-cbor" version = "0.1.0" @@ -3566,12 +3926,13 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" dependencies = [ "displaydoc", "potential_utf", + "utf8_iter", "yoke", "zerofrom", "zerovec", @@ -3579,9 +3940,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" dependencies = [ "displaydoc", "litemap", @@ -3592,9 +3953,9 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" dependencies = [ "icu_collections", "icu_normalizer_data", @@ -3606,15 +3967,15 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" [[package]] name = "icu_properties" -version = "2.1.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" dependencies = [ "icu_collections", "icu_locale_core", @@ -3626,15 +3987,15 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "2.1.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" [[package]] name = "icu_provider" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" dependencies = [ "displaydoc", "icu_locale_core", @@ -3694,6 +4055,20 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "im-rc" +version = "15.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1955a75fa080c677d3972822ec4bad316169ab1cfc6c257a942c2265dbe5fe" +dependencies = [ + "bitmaps", + "rand_core 0.6.4", + "rand_xoshiro", + "sized-chunks", + "typenum", + "version_check", +] + [[package]] name = "image" version = "0.25.10" @@ -3708,12 +4083,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.13.0" +version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" dependencies = [ "equivalent", - "hashbrown 0.16.1", + "hashbrown 0.17.0", "serde", "serde_core", ] @@ -3746,7 +4121,7 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd5b3eaf1a28b758ac0faa5a4254e8ab2705605496f1b1f3fbbc3988ad73d199" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "inotify-sys", "libc", ] @@ -3779,6 +4154,22 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "io-extras" +version = "0.18.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2285ddfe3054097ef4b2fe909ef8c3bcd1ea52a8f0d274416caebeef39f04a65" +dependencies = [ + "io-lifetimes", + "windows-sys 0.52.0", +] + +[[package]] +name = "io-lifetimes" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06432fb54d3be7964ecd3649233cddf80db2832f47fec34c01f65b3d9d774983" + [[package]] name = "ipnet" version = "2.12.0" @@ -3787,9 +4178,9 @@ checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" [[package]] name = "iri-string" -version = "0.7.10" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a" +checksum = "25e659a4bb38e810ebc252e53b5814ff908a8c58c2a9ce2fae1bbec24cbf4e20" dependencies = [ "memchr", "serde", @@ -3834,6 +4225,26 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" +[[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 = "52f5385394064fa2c886205dba02598013ce83d3e92d33dbdc0c52fe0e7bf4fc" +dependencies = [ + "cc", +] + [[package]] name = "jiff" version = "0.2.23" @@ -3846,7 +4257,7 @@ dependencies = [ "portable-atomic", "portable-atomic-util", "serde_core", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -3931,10 +4342,12 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.91" +version = "0.3.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c" +checksum = "2964e92d1d9dc3364cae4d718d93f227e3abb088e747d92e0395bfdedf1c12ca" dependencies = [ + "cfg-if", + "futures-util", "once_cell", "wasm-bindgen", ] @@ -3952,9 +4365,9 @@ dependencies = [ [[package]] name = "jsonschema" -version = "0.45.0" +version = "0.45.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f29616f6e19415398eb186964fb7cbbeef572c79bede3622a8277667924bbe3" +checksum = "257eb0e588b76827bbddc9e73945a9743693dd2adeaee9da26420f93cfedb798" dependencies = [ "ahash 0.8.12", "bytecount", @@ -4087,9 +4500,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "leb128" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" +checksum = "6cc46bac87ef8093eed6f272babb833b6443374399985ac8ed28471ee0918545" [[package]] name = "leb128fmt" @@ -4099,9 +4512,9 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "libc" -version = "0.2.183" +version = "0.2.185" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" +checksum = "52ff2c0fe9bc6cb6b14a0592c2ff4fa9ceb83eea9db979b0487cd054946a2b8f" [[package]] name = "libdbus-sys" @@ -4154,14 +4567,14 @@ checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "libredox" -version = "0.1.14" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1744e39d1d6a9948f4f388969627434e31128196de472883b39f148769bfe30a" +checksum = "e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "libc", "plain", - "redox_syscall 0.7.3", + "redox_syscall 0.7.4", ] [[package]] @@ -4180,9 +4593,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.25" +version = "1.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52f4c29e2a68ac30c9087e1b772dc9f44a2b66ed44edf2266cf2be9b03dafc1" +checksum = "fc3a226e576f50782b3305c5ccf458698f92798987f551c6a02efe8276721e22" dependencies = [ "cc", "libc", @@ -4190,6 +4603,12 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "linux-raw-sys" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + [[package]] name = "linux-raw-sys" version = "0.12.1" @@ -4252,9 +4671,9 @@ dependencies = [ [[package]] name = "litemap" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" [[package]] name = "lock_api" @@ -4310,12 +4729,36 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" +[[package]] +name = "mach2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d640282b302c0bb0a2a8e0233ead9035e3bed871f0b7e81fe4a1ec829765db44" +dependencies = [ + "libc", +] + +[[package]] +name = "maybe-owned" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4facc753ae494aeb6e3c22f839b158aebd4f9270f55cd3c79906c45476c47ab4" + [[package]] name = "memchr" version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" +[[package]] +name = "memfd" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad38eb12aea514a0466ea40a80fd8cc83637065948eb4a426e4aa46261175227" +dependencies = [ + "rustix 1.1.4", +] + [[package]] name = "memmap2" version = "0.9.10" @@ -4416,9 +4859,9 @@ dependencies = [ [[package]] name = "mio" -version = "1.1.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" +checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" dependencies = [ "libc", "log", @@ -4442,7 +4885,7 @@ version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7bddcd3bf5144b6392de80e04c347cd7fab2508f6df16a85fc496ecd5cec39bc" dependencies = [ - "rand 0.8.5", + "rand 0.8.6", ] [[package]] @@ -4457,7 +4900,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "cfg-if", "cfg_aliases", "libc", @@ -4470,7 +4913,7 @@ version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "cfg-if", "cfg_aliases", "libc", @@ -4482,7 +4925,7 @@ version = "0.31.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d6d0705320c1e6ba1d912b5e37cf18071b6c2e9b7fa8215a1e8a7651966f5d3" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "cfg-if", "cfg_aliases", "libc", @@ -4509,7 +4952,7 @@ version = "8.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d3d07927151ff8575b7087f245456e549fea62edf0ec4e565a5ee50c8402bc3" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "fsevent-sys", "inotify", "kqueue", @@ -4527,7 +4970,7 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42b8cfee0e339a0337359f3c88165702ac6e600dc01c0cc9579a92d62b08477a" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", ] [[package]] @@ -4545,7 +4988,7 @@ version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -4601,9 +5044,9 @@ dependencies = [ [[package]] name = "num-conv" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" +checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967" [[package]] name = "num-integer" @@ -4676,7 +5119,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", ] [[package]] @@ -4704,6 +5147,18 @@ dependencies = [ "memchr", ] +[[package]] +name = "object" +version = "0.38.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271638cd5fa9cca89c4c304675ca658efc4e64a66c716b7cfe1afb4b9611dbbc" +dependencies = [ + "crc32fast", + "hashbrown 0.16.1", + "indexmap", + "memchr", +] + [[package]] name = "once_cell" version = "1.21.4" @@ -4727,11 +5182,11 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "openssl" -version = "0.10.76" +version = "0.10.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "951c002c75e16ea2c65b8c7e4d3d51d5530d8dfa7d060b4776828c88cfb18ecf" +checksum = "f38c4372413cdaaf3cc79dd92d29d7d9f5ab09b51b10dded508fb90bb70b9222" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "cfg-if", "foreign-types", "libc", @@ -4765,18 +5220,18 @@ checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" [[package]] name = "openssl-src" -version = "300.5.5+3.5.5" +version = "300.6.0+3.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f1787d533e03597a7934fd0a765f0d28e94ecc5fb7789f8053b1e699a56f709" +checksum = "a8e8cbfd3a4a8c8f089147fd7aaa33cf8c7450c4d09f8f80698a0cf093abeff4" dependencies = [ "cc", ] [[package]] name = "openssl-sys" -version = "0.9.112" +version = "0.9.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57d55af3b3e226502be1526dfdba67ab0e9c96fc293004e79576b2b9edb0dbdb" +checksum = "13ce1245cd07fcc4cfdb438f7507b0c7e4f3849a69fd84d52374c66d83741bb6" dependencies = [ "cc", "libc", @@ -4908,6 +5363,12 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "pastey" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b867cad97c0791bbd3aaa6472142568c6c9e8f71937e98379f584cfb0cf35bec" + [[package]] name = "pbkdf2" version = "0.12.2" @@ -5080,12 +5541,6 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - [[package]] name = "piper" version = "0.2.5" @@ -5136,9 +5591,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" [[package]] name = "plain" @@ -5156,7 +5611,7 @@ dependencies = [ "concurrent-queue", "hermit-abi", "pin-project-lite", - "rustix", + "rustix 1.1.4", "windows-sys 0.61.2", ] @@ -5168,18 +5623,30 @@ checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" [[package]] name = "portable-atomic-util" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "091397be61a01d4be58e7841595bd4bfedb15f1cd54977d79b8271e94ed799a3" +checksum = "c2a106d1259c23fac8e543272398ae0e3c0b8d33c88ed73d0cc71b0f1d902618" dependencies = [ "portable-atomic", ] +[[package]] +name = "postcard" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24" +dependencies = [ + "cobs", + "embedded-io 0.4.0", + "embedded-io 0.6.1", + "serde", +] + [[package]] name = "potential_utf" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" dependencies = [ "zerovec", ] @@ -5271,7 +5738,7 @@ version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" dependencies = [ - "toml_edit 0.25.5+spec-1.1.0", + "toml_edit 0.25.11+spec-1.1.0", ] [[package]] @@ -5322,11 +5789,34 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "pulley-interpreter" +version = "43.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "010dec3755eb61b2f1051ecb3611b718460b7a74c131e474de2af20a845938af" +dependencies = [ + "cranelift-bitset", + "log", + "pulley-macros", + "wasmtime-internal-core", +] + +[[package]] +name = "pulley-macros" +version = "43.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad360c32e85ca4b083ac0e2b6856e8f11c3d5060dafa7d5dc57b370857fa3018" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "pxfm" -version = "0.1.28" +version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5a041e753da8b807c9255f28de81879c78c876392ff2469cde94799b2896b9d" +checksum = "e0c5ccf5294c6ccd63a74f1565028353830a9c2f5eb0c682c355c471726a6e3f" [[package]] name = "quinn" @@ -5339,7 +5829,7 @@ dependencies = [ "pin-project-lite", "quinn-proto", "quinn-udp", - "rustc-hash 2.1.1", + "rustc-hash 2.1.2", "rustls", "socket2", "thiserror 2.0.18", @@ -5358,9 +5848,9 @@ dependencies = [ "bytes", "getrandom 0.3.4", "lru-slab", - "rand 0.9.2", + "rand 0.9.4", "ring", - "rustc-hash 2.1.1", + "rustc-hash 2.1.2", "rustls", "rustls-pki-types", "slab", @@ -5413,9 +5903,9 @@ checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" [[package]] name = "rand" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" dependencies = [ "libc", "rand_chacha 0.3.1", @@ -5424,9 +5914,9 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.2" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" dependencies = [ "rand_chacha 0.9.0", "rand_core 0.9.5", @@ -5440,7 +5930,7 @@ checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207" dependencies = [ "chacha20", "getrandom 0.4.2", - "rand_core 0.10.0", + "rand_core 0.10.1", ] [[package]] @@ -5483,9 +5973,18 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.10.0" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + +[[package]] +name = "rand_xoshiro" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba" +checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" +dependencies = [ + "rand_core 0.6.4", +] [[package]] name = "rangemap" @@ -5493,6 +5992,26 @@ version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "973443cf09a9c8656b574a866ab68dfa19f0867d0340648c7d2f6a71b8a8ea68" +[[package]] +name = "rayon" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + [[package]] name = "redox_syscall" version = "0.2.16" @@ -5508,16 +6027,16 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", ] [[package]] name = "redox_syscall" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce70a74e890531977d37e532c34d45e9055d2409ed08ddba14529471ed0be16" +checksum = "f450ad9c3b1da563fb6948a8e0fb0fb9269711c9c73d9ea1de5058c79c8d643a" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", ] [[package]] @@ -5564,9 +6083,9 @@ dependencies = [ [[package]] name = "referencing" -version = "0.45.0" +version = "0.45.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a618c14f8ba29d8193bb55e2bf13e4fb2b1115313ecb7ae94b43100c7ac7d5" +checksum = "e2f38748ceca8d0b0013e60f534d94a6e23dfd89fd2a88318fc5a2d04fda1010" dependencies = [ "ahash 0.8.12", "fluent-uri", @@ -5577,6 +6096,20 @@ dependencies = [ "serde_json", ] +[[package]] +name = "regalloc2" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de2c52737737f8609e94f975dee22854a2d5c125772d4b1cf292120f4d45c186" +dependencies = [ + "allocator-api2", + "bumpalo", + "hashbrown 0.17.0", + "log", + "rustc-hash 2.1.2", + "smallvec", +] + [[package]] name = "regex" version = "1.12.3" @@ -5690,7 +6223,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4e35aaaa439a5bda2f8d15251bc375e4edfac75f9865734644782c9701b5709" dependencies = [ "ahash 0.8.12", - "bitflags 2.11.0", + "bitflags 2.11.1", "instant", "num-traits", "once_cell", @@ -5765,20 +6298,27 @@ dependencies = [ [[package]] name = "rust_decimal" -version = "1.40.0" +version = "1.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61f703d19852dbf87cbc513643fa81428361eb6940f1ac14fd58155d295a3eb0" +checksum = "2ce901f9a19d251159075a4c37af514c3b8ef99c22e02dd8c19161cf397ee94a" dependencies = [ "arrayvec 0.7.6", "borsh", "bytes", "num-traits", - "rand 0.8.5", + "rand 0.8.6", "rkyv", "serde", "serde_json", + "wasm-bindgen", ] +[[package]] +name = "rustc-demangle" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d" + [[package]] name = "rustc-hash" version = "1.1.0" @@ -5787,9 +6327,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustc-hash" -version = "2.1.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" [[package]] name = "rustc_version" @@ -5800,24 +6340,47 @@ dependencies = [ "semver", ] +[[package]] +name = "rustix" +version = "0.38.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags 2.11.1", + "errno", + "libc", + "linux-raw-sys 0.4.15", + "windows-sys 0.52.0", +] + [[package]] name = "rustix" version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "errno", "libc", - "linux-raw-sys", - "windows-sys 0.61.2", + "linux-raw-sys 0.12.1", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustix-linux-procfs" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fc84bf7e9aa16c4f2c758f27412dc9841341e16aa682d9c7ac308fe3ee12056" +dependencies = [ + "once_cell", + "rustix 1.1.4", ] [[package]] name = "rustls" -version = "0.23.37" +version = "0.23.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" +checksum = "69f9466fb2c14ea04357e91413efb882e2a6d4a406e625449bc0a5d360d53a21" dependencies = [ "aws-lc-rs", "once_cell", @@ -5867,7 +6430,7 @@ dependencies = [ "security-framework 3.7.0", "security-framework-sys", "webpki-root-certs", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -6065,7 +6628,7 @@ dependencies = [ "hkdf", "num", "once_cell", - "rand 0.8.5", + "rand 0.8.6", "serde", "sha2 0.10.9", "zbus", @@ -6077,7 +6640,7 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "core-foundation 0.9.4", "core-foundation-sys", "libc", @@ -6090,7 +6653,7 @@ version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "core-foundation 0.10.1", "core-foundation-sys", "libc", @@ -6120,9 +6683,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.27" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" dependencies = [ "serde", "serde_core", @@ -6256,9 +6819,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "1.0.4" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8bbf91e5a4d6315eee45e704372590b30e260ee83af6639d64557f51b067776" +checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" dependencies = [ "serde_core", ] @@ -6424,9 +6987,9 @@ dependencies = [ [[package]] name = "simd-adler32" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" +checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" [[package]] name = "simdutf8" @@ -6452,6 +7015,16 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" +[[package]] +name = "sized-chunks" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16d69225bde7a69b235da73377861095455d298f2b970996eec25ddbb42b3d1e" +dependencies = [ + "bitmaps", + "typenum", +] + [[package]] name = "slab" version = "0.4.12" @@ -6484,6 +7057,9 @@ name = "smallvec" version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +dependencies = [ + "serde", +] [[package]] name = "smartstring" @@ -6524,7 +7100,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -6553,6 +7129,7 @@ dependencies = [ "cfg-if", "libc", "psm", + "windows-sys 0.52.0", "windows-sys 0.59.0", ] @@ -6709,7 +7286,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "core-foundation 0.9.4", "system-configuration-sys", ] @@ -6724,6 +7301,22 @@ dependencies = [ "libc", ] +[[package]] +name = "system-interface" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc4592f674ce18521c2a81483873a49596655b179f71c5e05d10c1fe66c78745" +dependencies = [ + "bitflags 2.11.1", + "cap-fs-ext", + "cap-std", + "fd-lock", + "io-lifetimes", + "rustix 0.38.44", + "windows-sys 0.52.0", + "winx", +] + [[package]] name = "tap" version = "1.0.1" @@ -6742,7 +7335,13 @@ dependencies = [ ] [[package]] -name = "tempfile" +name = "target-lexicon" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca" + +[[package]] +name = "tempfile" version = "3.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" @@ -6750,8 +7349,8 @@ dependencies = [ "fastrand", "getrandom 0.4.2", "once_cell", - "rustix", - "windows-sys 0.61.2", + "rustix 1.1.4", + "windows-sys 0.52.0", ] [[package]] @@ -6786,11 +7385,11 @@ dependencies = [ [[package]] name = "terminal_size" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b8cb979cb11c32ce1603f8137b22262a9d131aaa5c37b5678025f22b8becd0" +checksum = "230a1b821ccbd75b185820a1f1ff7b14d21da1e442e22c0863ea5f08771a8874" dependencies = [ - "rustix", + "rustix 1.1.4", "windows-sys 0.60.2", ] @@ -6905,7 +7504,7 @@ checksum = "a30fd743a02bf35236f6faf99adb03089bb77e91c998dac2c2ad76bb424f668c" dependencies = [ "once_cell", "pbkdf2", - "rand 0.8.5", + "rand 0.8.6", "rustc-hash 1.1.0", "sha2 0.10.9", "thiserror 1.0.69", @@ -6925,9 +7524,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" dependencies = [ "displaydoc", "zerovec", @@ -6950,9 +7549,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.50.0" +version = "1.52.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d" +checksum = "b67dee974fe86fd92cc45b7a95fdd2f99a36a6d7b0d431a231178d3d670bbcc6" dependencies = [ "bytes", "libc", @@ -6967,9 +7566,9 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.6.1" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c55a2eff8b69ce66c84f85e1da1c233edc36ceb85a2058d11b0d6a3c7e7569c" +checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" dependencies = [ "proc-macro2", "quote", @@ -7019,7 +7618,7 @@ checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863" dependencies = [ "indexmap", "serde_core", - "serde_spanned 1.0.4", + "serde_spanned 1.1.1", "toml_datetime 0.7.5+spec-1.1.0", "toml_parser", "toml_writer", @@ -7046,9 +7645,9 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "1.0.1+spec-1.1.0" +version = "1.1.1+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b320e741db58cac564e26c607d3cc1fdc4a88fd36c879568c07856ed83ff3e9" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" dependencies = [ "serde_core", ] @@ -7068,30 +7667,30 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.25.5+spec-1.1.0" +version = "0.25.11+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ca1a40644a28bce036923f6a431df0b34236949d111cc07cb6dca830c9ef2e1" +checksum = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b" dependencies = [ "indexmap", - "toml_datetime 1.0.1+spec-1.1.0", + "toml_datetime 1.1.1+spec-1.1.0", "toml_parser", - "winnow 1.0.0", + "winnow 1.0.1", ] [[package]] name = "toml_parser" -version = "1.0.10+spec-1.1.0" +version = "1.1.2+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7df25b4befd31c4816df190124375d5a20c6b6921e2cad937316de3fccd63420" +checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" dependencies = [ - "winnow 1.0.0", + "winnow 1.0.1", ] [[package]] name = "toml_writer" -version = "1.0.7+spec-1.1.0" +version = "1.1.1+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f17aaa1c6e3dc22b1da4b6bba97d066e354c7945cac2f7852d4e4e7ca7a6b56d" +checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db" [[package]] name = "tower" @@ -7114,7 +7713,7 @@ version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "bytes", "futures-util", "http", @@ -7215,9 +7814,9 @@ checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" [[package]] name = "typenum" -version = "1.19.0" +version = "1.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" +checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" [[package]] name = "ucd-trie" @@ -7233,7 +7832,7 @@ checksum = "f2f6fb2847f6742cd76af783a2a2c49e9375d0a111c7bef6f71cd9e738c72d6e" dependencies = [ "memoffset", "tempfile", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -7271,9 +7870,9 @@ dependencies = [ [[package]] name = "unicode-segmentation" -version = "1.12.0" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" +checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c" [[package]] name = "unicode-width" @@ -7344,9 +7943,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.22.0" +version = "1.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a68d3c8f01c0cfa54a75291d83601161799e4a89a39e0929f4b0354d88757a37" +checksum = "ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76" dependencies = [ "getrandom 0.4.2", "js-sys", @@ -7424,11 +8023,11 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasip2" -version = "1.0.2+wasi-0.2.9" +version = "1.0.3+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" dependencies = [ - "wit-bindgen", + "wit-bindgen 0.57.1", ] [[package]] @@ -7437,14 +8036,14 @@ version = "0.4.0+wasi-0.3.0-rc-2026-01-06" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" dependencies = [ - "wit-bindgen", + "wit-bindgen 0.51.0", ] [[package]] name = "wasm-bindgen" -version = "0.2.114" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e" +checksum = "0bf938a0bacb0469e83c1e148908bd7d5a6010354cf4fb73279b7447422e3a89" dependencies = [ "cfg-if", "once_cell", @@ -7455,23 +8054,19 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.64" +version = "0.4.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9c5522b3a28661442748e09d40924dfb9ca614b21c00d3fd135720e48b67db8" +checksum = "f371d383f2fb139252e0bfac3b81b265689bf45b6874af544ffa4c975ac1ebf8" dependencies = [ - "cfg-if", - "futures-util", "js-sys", - "once_cell", "wasm-bindgen", - "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.114" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6" +checksum = "eeff24f84126c0ec2db7a449f0c2ec963c6a49efe0698c4242929da037ca28ed" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -7479,9 +8074,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.114" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3" +checksum = "9d08065faf983b2b80a79fd87d8254c409281cf7de75fc4b773019824196c904" dependencies = [ "bumpalo", "proc-macro2", @@ -7492,13 +8087,34 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.114" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16" +checksum = "5fd04d9e306f1907bd13c6361b5c6bfc7b3b3c095ed3f8a9246390f8dbdee129" dependencies = [ "unicode-ident", ] +[[package]] +name = "wasm-compose" +version = "0.245.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd23d12cc95c451c1306db5bc63075fbebb612bb70c53b4237b1ce5bc178343" +dependencies = [ + "anyhow", + "heck", + "im-rc", + "indexmap", + "log", + "petgraph", + "serde", + "serde_derive", + "serde_yaml", + "smallvec", + "wasm-encoder 0.245.1", + "wasmparser 0.245.1", + "wat", +] + [[package]] name = "wasm-encoder" version = "0.244.0" @@ -7509,6 +8125,26 @@ dependencies = [ "wasmparser 0.244.0", ] +[[package]] +name = "wasm-encoder" +version = "0.245.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9dca005e69bf015e45577e415b9af8c67e8ee3c0e38b5b0add5aa92581ed5c" +dependencies = [ + "leb128fmt", + "wasmparser 0.245.1", +] + +[[package]] +name = "wasm-encoder" +version = "0.247.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30b6733b8b91d010a6ac5b0fb237dc46a19650bc4c67db66857e2e787d437204" +dependencies = [ + "leb128fmt", + "wasmparser 0.247.0", +] + [[package]] name = "wasm-metadata" version = "0.244.0" @@ -7517,7 +8153,7 @@ checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" dependencies = [ "anyhow", "indexmap", - "wasm-encoder", + "wasm-encoder 0.244.0", "wasmparser 0.244.0", ] @@ -7540,7 +8176,7 @@ version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "hashbrown 0.15.5", "indexmap", "semver", @@ -7552,18 +8188,371 @@ version = "0.245.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4f08c9adee0428b7bddf3890fc27e015ac4b761cc608c822667102b8bfd6995e" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", + "hashbrown 0.16.1", + "indexmap", + "semver", + "serde", +] + +[[package]] +name = "wasmparser" +version = "0.247.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e6fb4c2bee46c5ea4d40f8cdb5c131725cd976718ec56f1c8e82fbde5fa2a80" +dependencies = [ + "bitflags 2.11.1", + "indexmap", + "semver", +] + +[[package]] +name = "wasmprinter" +version = "0.245.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f41517a3716fbb8ccf46daa9c1325f760fcbff5168e75c7392288e410b91ac8" +dependencies = [ + "anyhow", + "termcolor", + "wasmparser 0.245.1", +] + +[[package]] +name = "wasmtime" +version = "43.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce205cd643d661b5ba5ba4717e13730262e8cdbc8f2eacbc7b906d45c1a74026" +dependencies = [ + "addr2line", + "async-trait", + "bitflags 2.11.1", + "bumpalo", + "cc", + "cfg-if", + "encoding_rs", + "futures", + "fxprof-processed-profile", + "gimli", + "ittapi", + "libc", + "log", + "mach2", + "memfd", + "object 0.38.1", + "once_cell", + "postcard", + "pulley-interpreter", + "rayon", + "rustix 1.1.4", + "semver", + "serde", + "serde_derive", + "serde_json", + "smallvec", + "target-lexicon", + "tempfile", + "wasm-compose", + "wasm-encoder 0.245.1", + "wasmparser 0.245.1", + "wasmtime-environ", + "wasmtime-internal-cache", + "wasmtime-internal-component-macro", + "wasmtime-internal-component-util", + "wasmtime-internal-core", + "wasmtime-internal-cranelift", + "wasmtime-internal-fiber", + "wasmtime-internal-jit-debug", + "wasmtime-internal-jit-icache-coherence", + "wasmtime-internal-unwinder", + "wasmtime-internal-versioned-export-macros", + "wasmtime-internal-winch", + "wat", + "windows-sys 0.61.2", +] + +[[package]] +name = "wasmtime-environ" +version = "43.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b8b78abf3677d4a0a5db82e5015b4d085ff3a1b8b472cbb8c70d4b769f019ce" +dependencies = [ + "anyhow", + "cpp_demangle", + "cranelift-bforest", + "cranelift-bitset", + "cranelift-entity", + "gimli", "hashbrown 0.16.1", "indexmap", + "log", + "object 0.38.1", + "postcard", + "rustc-demangle", "semver", "serde", + "serde_derive", + "sha2 0.10.9", + "smallvec", + "target-lexicon", + "wasm-encoder 0.245.1", + "wasmparser 0.245.1", + "wasmprinter", + "wasmtime-internal-component-util", + "wasmtime-internal-core", +] + +[[package]] +name = "wasmtime-internal-cache" +version = "43.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e4fd4103ba413c0da2e636f73490c6c8e446d708cbde7573703941bc3d6a448" +dependencies = [ + "base64", + "directories-next", + "log", + "postcard", + "rustix 1.1.4", + "serde", + "serde_derive", + "sha2 0.10.9", + "toml 0.9.12+spec-1.1.0", + "wasmtime-environ", + "windows-sys 0.61.2", + "zstd", +] + +[[package]] +name = "wasmtime-internal-component-macro" +version = "43.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d3d6914f34be2f9d78d8ee9f422e834dfc204e71ccce697205fae95fed87892" +dependencies = [ + "anyhow", + "proc-macro2", + "quote", + "syn 2.0.117", + "wasmtime-internal-component-util", + "wasmtime-internal-wit-bindgen", + "wit-parser 0.245.1", +] + +[[package]] +name = "wasmtime-internal-component-util" +version = "43.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3751b0616b914fdd87fe1bf804694a078f321b000338e6476bc48a4d6e454f21" + +[[package]] +name = "wasmtime-internal-core" +version = "43.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22632b187e1b0716f1b9ac57ad29013bed33175fcb19e10bb6896126f82fac67" +dependencies = [ + "anyhow", + "hashbrown 0.16.1", + "libm", + "serde", +] + +[[package]] +name = "wasmtime-internal-cranelift" +version = "43.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b3ca07b3e0bb3429674b173b5800577719d600774dd81bff58f775c0aaa64ee" +dependencies = [ + "cfg-if", + "cranelift-codegen", + "cranelift-control", + "cranelift-entity", + "cranelift-frontend", + "cranelift-native", + "gimli", + "itertools 0.14.0", + "log", + "object 0.38.1", + "pulley-interpreter", + "smallvec", + "target-lexicon", + "thiserror 2.0.18", + "wasmparser 0.245.1", + "wasmtime-environ", + "wasmtime-internal-core", + "wasmtime-internal-unwinder", + "wasmtime-internal-versioned-export-macros", +] + +[[package]] +name = "wasmtime-internal-fiber" +version = "43.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20c8b2c9704eb1f33ead025ec16038277ccb63d0a14c31e99d5b765d7c36da55" +dependencies = [ + "cc", + "cfg-if", + "libc", + "rustix 1.1.4", + "wasmtime-environ", + "wasmtime-internal-versioned-export-macros", + "windows-sys 0.61.2", +] + +[[package]] +name = "wasmtime-internal-jit-debug" +version = "43.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d950310d07391d34369f62c48336ebb14eacbd4d6f772bb5f349c24e838e0664" +dependencies = [ + "cc", + "object 0.38.1", + "rustix 1.1.4", + "wasmtime-internal-versioned-export-macros", +] + +[[package]] +name = "wasmtime-internal-jit-icache-coherence" +version = "43.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3606662c156962d096be3127b8b8ae8ee2f8be3f896dad29259ff01ddb64abfd" +dependencies = [ + "cfg-if", + "libc", + "wasmtime-internal-core", + "windows-sys 0.61.2", +] + +[[package]] +name = "wasmtime-internal-unwinder" +version = "43.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75eef0747e52dc545b075f64fd0e0cc237ae738e641266b1970e07e2d744bc32" +dependencies = [ + "cfg-if", + "cranelift-codegen", + "log", + "object 0.38.1", + "wasmtime-environ", +] + +[[package]] +name = "wasmtime-internal-versioned-export-macros" +version = "43.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b0a5dab02a8fb527f547855ecc0e05f9fdc3d5bd57b8b080349408f9a6cece" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "wasmtime-internal-winch" +version = "43.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8007342bd12ff400293a817973f7ecd6f1d9a8549a53369a9c1af357166f1f1e" +dependencies = [ + "cranelift-codegen", + "gimli", + "log", + "object 0.38.1", + "target-lexicon", + "wasmparser 0.245.1", + "wasmtime-environ", + "wasmtime-internal-cranelift", + "winch-codegen", +] + +[[package]] +name = "wasmtime-internal-wit-bindgen" +version = "43.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7900c3e3c1d6e475bc225d73b02d6d5484815f260022e6964dca9558e50dd01a" +dependencies = [ + "anyhow", + "bitflags 2.11.1", + "heck", + "indexmap", + "wit-parser 0.245.1", +] + +[[package]] +name = "wasmtime-wasi" +version = "43.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3e3ddcfad69e9eb025bd19bff70dad45bafe1d6eacd134c0ffdfc4c161d045" +dependencies = [ + "async-trait", + "bitflags 2.11.1", + "bytes", + "cap-fs-ext", + "cap-net-ext", + "cap-rand", + "cap-std", + "cap-time-ext", + "fs-set-times", + "futures", + "io-extras", + "io-lifetimes", + "rustix 1.1.4", + "system-interface", + "thiserror 2.0.18", + "tokio", + "tracing", + "url", + "wasmtime", + "wasmtime-wasi-io", + "wiggle", + "windows-sys 0.61.2", +] + +[[package]] +name = "wasmtime-wasi-io" +version = "43.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ca5dd3b9f04a851c422d05f333366722742da46bff9369ae0191f32cf83565a" +dependencies = [ + "async-trait", + "bytes", + "futures", + "tracing", + "wasmtime", +] + +[[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 = "247.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "579d2d47eb33b0cdf9b14723cb115f1e1b7d6e77aac6f0816e5b7c7aeaa418ff" +dependencies = [ + "bumpalo", + "leb128fmt", + "memchr", + "unicode-width 0.2.2", + "wasm-encoder 0.247.0", +] + +[[package]] +name = "wat" +version = "1.247.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3f4091c56437e86f2b57fa2fac72c4f528957a605b3f44f7c0b3b19a17ac5ee" +dependencies = [ + "wast 247.0.0", ] [[package]] name = "web-sys" -version = "0.3.91" +version = "0.3.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854ba17bb104abfb26ba36da9729addc7ce7f06f5c0f90f3c391f8461cca21f9" +checksum = "4f2dfbb17949fa2088e5d39408c48368947b86f7834484e87b73de55bc14d97d" dependencies = [ "js-sys", "wasm-bindgen", @@ -7581,9 +8570,9 @@ dependencies = [ [[package]] name = "webpki-root-certs" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "804f18a4ac2676ffb4e8b5b5fa9ae38af06df08162314f96a68d2a363e21a8ca" +checksum = "f31141ce3fc3e300ae89b78c0dd67f9708061d1d2eda54b8209346fd6be9a92c" dependencies = [ "rustls-pki-types", ] @@ -7594,6 +8583,46 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72069c3113ab32ab29e5584db3c6ec55d416895e60715417b5b883a357c3e471" +[[package]] +name = "wiggle" +version = "43.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc1b1135efc8e5a008971897bea8d41ca56d8d501d4efb807842ae0a1c78f639" +dependencies = [ + "bitflags 2.11.1", + "thiserror 2.0.18", + "tracing", + "wasmtime", + "wasmtime-environ", + "wiggle-macro", +] + +[[package]] +name = "wiggle-generate" +version = "43.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7bc2b0d50ec8773b44fbfe1da6cb5cc44a92deaf8483233dcf0831e6db33172" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.117", + "wasmtime-environ", + "witx", +] + +[[package]] +name = "wiggle-macro" +version = "43.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d6c7d44ea552e1fbfdcd7a2cd83f5c2d1e803d5b1a11e3462c06888b77f455f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", + "wiggle-generate", +] + [[package]] name = "winapi" version = "0.3.9" @@ -7616,7 +8645,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -7625,6 +8654,25 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "winch-codegen" +version = "43.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb9f45f7172a2628c8317766e427babc0a400f9d10b1c0f0b0617c5ed5b79de6" +dependencies = [ + "cranelift-assembler-x64", + "cranelift-codegen", + "gimli", + "regalloc2", + "smallvec", + "target-lexicon", + "thiserror 2.0.18", + "wasmparser 0.245.1", + "wasmtime-environ", + "wasmtime-internal-core", + "wasmtime-internal-cranelift", +] + [[package]] name = "windows" version = "0.61.3" @@ -8077,9 +9125,9 @@ dependencies = [ [[package]] name = "winnow" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a90e88e4667264a994d34e6d1ab2d26d398dcdca8b7f52bec8668957517fc7d8" +checksum = "09dac053f1cd375980747450bfc7250c264eaae0583872e845c0c7cd578872b5" dependencies = [ "memchr", ] @@ -8091,7 +9139,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d6f32a0ff4a9f6f01231eb2059cc85479330739333e0e58cadf03b6af2cca10" dependencies = [ "cfg-if", - "windows-sys 0.61.2", + "windows-sys 0.60.2", +] + +[[package]] +name = "winx" +version = "0.36.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f3fd376f71958b862e7afb20cfe5a22830e1963462f3a17f49d82a6c1d1f42d" +dependencies = [ + "bitflags 2.11.1", + "windows-sys 0.52.0", ] [[package]] @@ -8103,6 +9161,12 @@ dependencies = [ "wit-bindgen-rust-macro", ] +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + [[package]] name = "wit-bindgen-core" version = "0.51.0" @@ -8111,7 +9175,7 @@ checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" dependencies = [ "anyhow", "heck", - "wit-parser", + "wit-parser 0.244.0", ] [[package]] @@ -8152,16 +9216,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" dependencies = [ "anyhow", - "bitflags 2.11.0", + "bitflags 2.11.1", "indexmap", "log", "serde", "serde_derive", "serde_json", - "wasm-encoder", + "wasm-encoder 0.244.0", "wasm-metadata", "wasmparser 0.244.0", - "wit-parser", + "wit-parser 0.244.0", ] [[package]] @@ -8182,11 +9246,42 @@ dependencies = [ "wasmparser 0.244.0", ] +[[package]] +name = "wit-parser" +version = "0.245.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330698718e82983499419494dd1e3d7811a457a9bf9f69734e8c5f07a2547929" +dependencies = [ + "anyhow", + "hashbrown 0.16.1", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser 0.245.1", +] + +[[package]] +name = "witx" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e366f27a5cabcddb2706a78296a40b8fcc451e1a6aba2fc1d94b4a01bdaaef4b" +dependencies = [ + "anyhow", + "log", + "thiserror 1.0.69", + "wast 35.0.2", +] + [[package]] name = "writeable" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" [[package]] name = "wslpath2" @@ -8210,7 +9305,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" dependencies = [ "libc", - "rustix", + "rustix 1.1.4", ] [[package]] @@ -8225,9 +9320,9 @@ dependencies = [ [[package]] name = "yoke" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" dependencies = [ "stable_deref_trait", "yoke-derive", @@ -8236,9 +9331,9 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" dependencies = [ "proc-macro2", "quote", @@ -8264,7 +9359,7 @@ dependencies = [ "hex", "nix 0.29.0", "ordered-stream", - "rand 0.8.5", + "rand 0.8.6", "serde", "serde_repr", "sha1", @@ -8304,18 +9399,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.47" +version = "0.8.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efbb2a062be311f2ba113ce66f697a4dc589f85e78a4aea276200804cea0ed87" +checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.47" +version = "0.8.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e8bc7269b54418e7aeeef514aa68f8690b8c0489a06b0136e5f57c4c5ccab89" +checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" dependencies = [ "proc-macro2", "quote", @@ -8324,18 +9419,18 @@ dependencies = [ [[package]] name = "zerofrom" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" dependencies = [ "proc-macro2", "quote", @@ -8365,9 +9460,9 @@ dependencies = [ [[package]] name = "zerotrie" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" dependencies = [ "displaydoc", "yoke", @@ -8376,9 +9471,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.5" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" dependencies = [ "yoke", "zerofrom", @@ -8387,9 +9482,9 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" dependencies = [ "proc-macro2", "quote", @@ -8408,6 +9503,34 @@ version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" +[[package]] +name = "zstd" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.16+zstd.1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748" +dependencies = [ + "cc", + "pkg-config", +] + [[package]] name = "zvariant" version = "4.2.0" diff --git a/Cargo.toml b/Cargo.toml index ed4a5b643..969e91d61 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ members = ["crates/*"] default-members = ["crates/icp-cli"] -exclude = ["examples/icp-rust", "examples/icp-rust-recipe"] +exclude = ["examples/icp-rust", "examples/icp-rust-recipe", "examples/icp-sync-plugin"] resolver = "3" [workspace.package] @@ -57,6 +57,7 @@ ic-management-canister-types = { version = "0.7.1" } ic-utils = { version = "0.47.0" } icp = { path = "crates/icp" } icp-canister-interfaces = { path = "crates/icp-canister-interfaces" } +icp-sync-plugin = { path = "crates/icp-sync-plugin" } ic-identity-hsm = "0.47.0" icrc-ledger-types = "0.1.10" indicatif = "0.18.0" @@ -107,6 +108,8 @@ tracing-subscriber = "0.3.20" url = { version = "2.5.4", features = ["serde"] } uuid = { version = "1.16.0", features = ["serde", "v4"] } wasmparser = "0.245.1" +wasmtime = { version = "43", features = ["component-model"] } +wasmtime-wasi = { version = "43" } winreg = "0.56.0" wslpath2 = "0.1" zeroize = "1.8.1" diff --git a/crates/icp-cli/src/commands/deploy.rs b/crates/icp-cli/src/commands/deploy.rs index deb36de88..8c3fc56d8 100644 --- a/crates/icp-cli/src/commands/deploy.rs +++ b/crates/icp-cli/src/commands/deploy.rs @@ -362,7 +362,15 @@ pub(crate) async fn exec(ctx: &Context, args: &DeployArgs) -> Result<(), anyhow: // method to permit the user identity to upload assets directly before syncing. info!("Syncing canisters:"); - sync_many(ctx.syncer.clone(), agent.clone(), sync_canisters, ctx.debug).await?; + sync_many( + ctx.syncer.clone(), + agent.clone(), + sync_canisters, + environment_selection.name().to_owned(), + args.proxy, + ctx.debug, + ) + .await?; } // Print URLs for deployed canisters diff --git a/crates/icp-cli/src/commands/sync.rs b/crates/icp-cli/src/commands/sync.rs index 7e4663285..81be12170 100644 --- a/crates/icp-cli/src/commands/sync.rs +++ b/crates/icp-cli/src/commands/sync.rs @@ -1,3 +1,4 @@ +use candid::Principal; use clap::Args; use futures::future::try_join_all; use icp::context::{CanisterSelection, Context, EnvironmentSelection}; @@ -15,6 +16,10 @@ pub(crate) struct SyncArgs { /// Canister names (if empty, sync all canisters in environment) pub(crate) canisters: Vec, + /// Principal of a proxy canister to route management canister calls through. + #[arg(long)] + pub(crate) proxy: Option, + #[command(flatten)] pub(crate) environment: EnvironmentOpt, @@ -77,7 +82,15 @@ pub(crate) async fn exec(ctx: &Context, args: &SyncArgs) -> Result<(), anyhow::E info!("Syncing canisters:"); - sync_many(ctx.syncer.clone(), agent, sync_canisters, ctx.debug).await?; + sync_many( + ctx.syncer.clone(), + agent, + sync_canisters, + environment_selection.name().to_owned(), + args.proxy, + ctx.debug, + ) + .await?; Ok(()) } diff --git a/crates/icp-cli/src/operations/sync.rs b/crates/icp-cli/src/operations/sync.rs index feb407055..b5b36e552 100644 --- a/crates/icp-cli/src/operations/sync.rs +++ b/crates/icp-cli/src/operations/sync.rs @@ -1,5 +1,6 @@ +use candid::Principal; use futures::{StreamExt, stream::FuturesOrdered}; -use ic_agent::{Agent, export::Principal}; +use ic_agent::Agent; use icp::{ Canister, canister::sync::{Params, Synchronize, SynchronizeError}, @@ -32,6 +33,8 @@ async fn sync_canister( canister_path: PathBuf, canister_id: Principal, canister_info: &Canister, + environment: &str, + proxy: Option, pb: &mut MultiStepProgressBar, ) -> Result<(), SynchronizeError> { let step_count = canister_info.sync.steps.len(); @@ -50,6 +53,8 @@ async fn sync_canister( &Params { path: canister_path.clone(), cid: canister_id, + environment: environment.to_owned(), + proxy, }, agent, Some(tx), @@ -70,6 +75,8 @@ pub(crate) async fn sync_many( syncer: Arc, agent: Agent, canisters: Vec<(Principal, PathBuf, Canister)>, + environment: String, + proxy: Option, debug: bool, ) -> Result<(), SyncOperationError> { let mut futs = FuturesOrdered::new(); @@ -81,12 +88,21 @@ pub(crate) async fn sync_many( let fut = { let agent = agent.clone(); let syncer = syncer.clone(); + let environment = environment.clone(); async move { // Define the sync logic - let sync_result = - sync_canister(&syncer, &agent, canister_path, cid, &canister_info, &mut pb) - .await; + let sync_result = sync_canister( + &syncer, + &agent, + canister_path, + cid, + &canister_info, + &environment, + proxy, + &mut pb, + ) + .await; // Execute with progress tracking for final state let result = ProgressManager::execute_with_progress( @@ -126,6 +142,14 @@ pub(crate) async fn sync_many( failure.canister_name, failure.canister_id, ); error!("'{}'", failure.error); + { + use std::error::Error; + let mut cause = failure.error.source(); + while let Some(err) = cause { + error!(" caused by: {err}"); + cause = err.source(); + } + } for line in &failure.progress_output { error!("{line}"); } diff --git a/crates/icp-sync-plugin/Cargo.toml b/crates/icp-sync-plugin/Cargo.toml new file mode 100644 index 000000000..242786139 --- /dev/null +++ b/crates/icp-sync-plugin/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "icp-sync-plugin" +version.workspace = true +edition.workspace = true +license.workspace = true +repository.workspace = true +publish.workspace = true + +[dependencies] +camino.workspace = true +candid.workspace = true +hex.workspace = true +ic-agent.workspace = true +icp-canister-interfaces.workspace = true +snafu.workspace = true +tokio.workspace = true +wasmtime.workspace = true +wasmtime-wasi.workspace = true + +[lints] +workspace = true diff --git a/crates/icp-sync-plugin/DESIGN.md b/crates/icp-sync-plugin/DESIGN.md new file mode 100644 index 000000000..13f1cae4e --- /dev/null +++ b/crates/icp-sync-plugin/DESIGN.md @@ -0,0 +1,302 @@ +# Sync Plugin System Design + +## Overview + +Sync plugins extend `icp sync` with an arbitrary post-deployment step type. +A plugin is a WebAssembly component whose `exec()` export is invoked by +`icp-cli` during sync for a specific canister. The host runs it inside a +[wasmtime](https://wasmtime.dev/) WASI sandbox with a deliberately narrow +capability surface. + +--- + +## Motivation + +The existing sync steps (`script` and `assets`) cover common patterns but +cannot express arbitrary post-deployment logic without shelling out. Shell +scripts lack structure, have unrestricted host access, and cannot be +distributed as self-contained verifiable artifacts. + +Sync plugins fill that gap: + +- Written in any language that compiles to `wasm32-wasip2` +- Distributed as a single `.wasm` component (local path or remote URL + sha256) +- Sandboxed — cannot make arbitrary syscalls, network connections, or + unrestricted filesystem access +- Can call canister methods (update and query) on **exactly one canister** — + the one being synced +- Can read files from declared directories via the WASI filesystem interface + +--- + +## Canister Manifest Syntax + +A sync plugin step is declared in `canister.yaml` under `sync.steps` with +`type: plugin`: + +```yaml +name: my-canister +build: + steps: + - type: pre-built + path: dist/my_canister.wasm + +sync: + steps: + # Local plugin + - type: plugin + path: ./plugins/populate-data.wasm + sha256: e3b0c44298fc1c149afb... # optional but recommended + dirs: # directories preopened read-only + - assets/seed-data + - config + files: # files read by the host and passed inline + - config.txt + + # Remote plugin (downloaded + verified before execution) + - type: plugin + url: https://example.com/plugins/migrate-v2.wasm + sha256: a665a45920422f9d417e... # required for remote +``` + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `type` | `"plugin"` | yes | Identifies the step type | +| `path` | string | one of `path`/`url` | Local path to the wasm, relative to canister directory | +| `url` | string | one of `path`/`url` | Remote URL to download the wasm from | +| `sha256` | string | required for `url`, optional for `path` | SHA-256 hex digest of the wasm file | +| `dirs` | `[string]` | no | Directories (relative to canister dir) the plugin may read; each is preopened via WASI | +| `files` | `[string]` | no | Files (relative to canister dir) read by the host and passed inline in `sync-exec-input.files` | + +--- + +## Plugin Interface (WIT) + +The interface is defined in [`sync-plugin.wit`](sync-plugin.wit) — that file +is the source of truth. The world has one host-provided import and one +plugin-provided export: + +```wit +world sync-plugin { + // Host import: call the canister being synced. + import canister-call: func(req: canister-call-request) -> result, string>; + + // Plugin export: run the sync step. + export exec: func(input: sync-exec-input) -> result, string>; +} +``` + +Notable choices: + +- **`result` throughout** — all fallible functions return + `result<..., string>`, so plugins can use `?` uniformly. +- **Raw Candid bytes at the boundary** — `canister-call-request.arg` is + `list`. The plugin encodes the argument (e.g. with `candid::Encode!`) + and the host forwards bytes unchanged. The response is also raw bytes for + the plugin to decode. +- **`canister-call` takes no canister ID** — the host always calls the + canister from `sync-exec-input.canister-id`. The plugin cannot supply a + different target; the restriction is structural. +- **Filesystem access via WASI, not a host import** — plugins use standard + language APIs (`std::fs` in Rust). The host preopens the declared `dirs` + read-only; no explicit `read-file` or `list-dir` import is needed. +- **Logging via stdio, not a host import** — stdout and stderr are captured + by the host (via `MemoryOutputPipe`) and forwarded to the CLI's progress + output after `exec()` returns. Plugins use normal print facilities. +- **No generated files checked in** — `wasmtime::component::bindgen!` (host) + and `wit_bindgen::generate!` (guest) both run at build time from the WIT + file. The WIT is the sole source of truth. + +--- + +## Sandbox + +### Filesystem + +- The host preopens each directory listed in `dirs:` **read-only** + (`DirPerms::READ`, `FilePerms::READ`) via `WasiCtxBuilder::preopened_dir`. +- The plugin sees each preopen at the same relative path it used in the + manifest (e.g. `dirs: ["assets"]` is visible as `assets/` inside the guest). +- Files listed in `files:` are read by the host before plugin execution and + passed inline in `sync-exec-input.files`. The plugin accesses them from the + input struct, not from the filesystem. +- Any path not covered by a preopen is invisible. Writes, creates, deletes, + renames, and symlinks that escape a preopen are rejected by wasmtime. + +### WASI capabilities + +The host links `wasi:cli/imports` via `wasmtime_wasi::p2::add_to_linker_sync`. +The effective capability surface is: + +| Capability | Available | Notes | +|------------|-----------|-------| +| `wasi:filesystem` | read-only preopens | constrained to declared `dirs` | +| `wasi:io`, `wasi:clocks`, `wasi:random` | yes | Rust's `HashMap`, `chrono`, etc. work normally | +| `wasi:cli/exit` | yes | `process::exit` / panics abort the guest cleanly | +| `wasi:cli/environment` | empty | returns empty env and args; use `sync-exec-input.environment` | +| `wasi:cli/terminal-*` | not a terminal | color auto-detection libraries simply disable color | +| `wasi:sockets` | blocked | all addresses denied; treat network as unavailable | +| Arbitrary filesystem write | blocked | no writable preopens | +| Spawning subprocesses | blocked | no WASI process interface linked | +| Calls to other canisters | blocked | host ignores any canister ID; always calls the synced canister | + +**Stdio:** +- `stdin` is closed. +- `stdout` and `stderr` are captured with `MemoryOutputPipe`. After `exec()` + returns, stdout is forwarded to the CLI progress output first, then stderr. + Invalid UTF-8 is replaced with U+FFFD. + +### What this means for plugin authors + +You can: +- Read any file under a declared `dirs:` entry using standard filesystem APIs. +- Access inline file content from `sync-exec-input.files`. +- Use clocks, RNG, and standard language features. +- Panic or exit — the host surfaces the error and continues. + +You cannot: +- Open network connections or resolve DNS. +- Write to disk, spawn subprocesses, or read environment variables. +- Call canisters other than the one being synced. +- Escape a preopen via `..` or symlinks. + +--- + +## Crate Structure + +### `crates/icp-sync-plugin` + +Host-side Component Model runtime for sync plugins. + +``` +crates/icp-sync-plugin/ + src/ + lib.rs — public API: run_plugin(), RunPluginError + runtime.rs — wasmtime component setup, HostState, bindgen!, exec() call + sync-plugin.wit — WIT interface (source of truth) + Cargo.toml — wasmtime, wasmtime-wasi, ic-agent, candid, camino, snafu, tokio +``` + +Public function: + +```rust +pub fn run_plugin( + wasm_path: Utf8PathBuf, + base_dir: Utf8PathBuf, + dirs: Vec, + files: Vec<(String, String)>, + target_canister_id: Principal, + agent: Agent, + environment: String, + stdio: Option>, +) -> Result<(), RunPluginError> +``` + +`dirs` and `files` come directly from the manifest adapter. The runtime +preopens each `dir` from `base_dir.join(dir)` and passes `files` inline in +`SyncExecInput`. + +### `HostState` and bindgen + +```rust +wasmtime::component::bindgen!({ + world: "sync-plugin", + path: "sync-plugin.wit", +}); + +struct HostState { + target_canister_id: Principal, + agent: Arc, + wasi_ctx: wasmtime_wasi::WasiCtx, + wasi_table: wasmtime_wasi::ResourceTable, +} + +impl SyncPluginImports for HostState { + fn canister_call(&mut self, req: CanisterCallRequest) -> Result, String> { ... } +} +``` + +`HostState` implements `WasiView` so wasmtime_wasi can access the WASI context. +`canister_call` uses `tokio::runtime::Handle::current().block_on(...)` because +the caller already wraps the synchronous `run_plugin` in +`tokio::task::block_in_place`. + +### `crates/icp/src/manifest/adapter/plugin.rs` + +Deserializes the `canister.yaml` fields into: + +```rust +pub struct Adapter { + pub source: SourceField, // path: or url: + pub sha256: Option, + pub dirs: Option>, + pub files: Option>, +} +``` + +### `crates/icp/src/canister/sync/plugin.rs` + +Resolves the wasm (local read or remote HTTP fetch), verifies sha256, reads +inline files, then calls `icp_sync_plugin::run_plugin(...)`. + +--- + +## Writing a Sync Plugin (Rust) + +Plugins target `wasm32-wasip2` and use `wit_bindgen::generate!` to produce +bindings from the WIT file at build time: + +```toml +# Cargo.toml +[lib] +crate-type = ["cdylib"] + +[dependencies] +candid = "0.10" +wit-bindgen = { version = "0.56", features = ["realloc"] } +``` + +```rust +// src/lib.rs +wit_bindgen::generate!({ + world: "sync-plugin", + path: "../../../crates/icp-sync-plugin/sync-plugin.wit", +}); + +use candid::Encode; +struct Plugin; + +impl Guest for Plugin { + fn exec(input: SyncExecInput) -> Result, String> { + // Access inline files from the manifest's `files:` list. + if let Some(f) = input.files.first() { + let arg = Encode!(&f.content.trim()) + .map_err(|e| format!("encode error: {e}"))?; + canister_call(&CanisterCallRequest { + method: "set_config".to_string(), + arg, + call_type: Some(icp::sync_plugin::types::CallType::Update), + })?; + } + + // Access declared directories via standard std::fs. + for dir in &input.dirs { + // std::fs::read_dir(dir), etc. + } + + Ok(Some(format!("done for canister {}", input.canister_id))) + } +} + +export!(Plugin); +``` + +Build: + +```bash +rustup target add wasm32-wasip2 +cargo build --target wasm32-wasip2 --release +``` + +The output `.wasm` file is loaded directly by the host — no additional +tooling is required. See `examples/icp-sync-plugin/` for a working example. diff --git a/crates/icp-sync-plugin/TODO.md b/crates/icp-sync-plugin/TODO.md new file mode 100644 index 000000000..52f73bab7 --- /dev/null +++ b/crates/icp-sync-plugin/TODO.md @@ -0,0 +1,22 @@ +# Sync Plugin TODO + +## Wasm caching + +Cache remote plugin wasm files in `.icp/cache/` so they are not re-downloaded +on every sync. Key the cache entry on the sha256 checksum. When a remote step +has a sha256 and the cached file matches, skip the HTTP fetch entirely. + +## Plugin timeout + +Add `timeout_seconds: Option` to `manifest::adapter::plugin::Adapter` +and wire it through `sync/plugin.rs` → `run_plugin`. Use wasmtime's +epoch-based interruption (`Engine::increment_epoch` on a background thread, +`Store::set_epoch_deadline`) to interrupt a plugin that runs too long. + +## Integration tests + +Add end-to-end tests that compile the `examples/icp-sync-plugin/plugin` +against a mock canister and verify the full `run_plugin` path (wasm load, +WASI preopen, canister-call, stdio capture). Unit-level tests for sha256 +mismatch and the remote-download path in `sync/plugin.rs` would also improve +coverage. diff --git a/crates/icp-sync-plugin/build.rs b/crates/icp-sync-plugin/build.rs new file mode 100644 index 000000000..44680d997 --- /dev/null +++ b/crates/icp-sync-plugin/build.rs @@ -0,0 +1,3 @@ +fn main() { + println!("cargo:rerun-if-changed=sync-plugin.wit"); +} diff --git a/crates/icp-sync-plugin/src/lib.rs b/crates/icp-sync-plugin/src/lib.rs new file mode 100644 index 000000000..6c78f715e --- /dev/null +++ b/crates/icp-sync-plugin/src/lib.rs @@ -0,0 +1,3 @@ +mod runtime; + +pub use runtime::{RunPluginError, run_plugin}; diff --git a/crates/icp-sync-plugin/src/runtime.rs b/crates/icp-sync-plugin/src/runtime.rs new file mode 100644 index 000000000..8cccfb0cd --- /dev/null +++ b/crates/icp-sync-plugin/src/runtime.rs @@ -0,0 +1,244 @@ +// Host-side Component Model runtime for sync plugins. +use std::sync::Arc; + +use camino::Utf8PathBuf; +use candid::{Encode, Principal}; +use ic_agent::Agent; +use snafu::prelude::*; +use tokio::sync::mpsc::Sender; +use wasmtime_wasi::p2::pipe::MemoryOutputPipe; +use wasmtime_wasi::{DirPerms, FilePerms}; + +wasmtime::component::bindgen!({ + world: "sync-plugin", + path: "sync-plugin.wit", +}); + +use icp::sync_plugin::types::CallType; + +// HostState holds everything the plugin's import functions need. +struct HostState { + target_canister_id: Principal, + agent: Arc, + /// Proxy canister to route update calls through, if configured. + proxy: Option, + // WASI context. Preopened directories in this context are the only + // filesystem locations the plugin can access. + wasi_ctx: wasmtime_wasi::WasiCtx, + wasi_table: wasmtime_wasi::ResourceTable, +} + +impl wasmtime_wasi::WasiView for HostState { + fn ctx(&mut self) -> wasmtime_wasi::WasiCtxView<'_> { + wasmtime_wasi::WasiCtxView { + ctx: &mut self.wasi_ctx, + table: &mut self.wasi_table, + } + } +} + +// `types::Host` is an empty marker trait generated for the `types` interface. +impl icp::sync_plugin::types::Host for HostState {} + +impl SyncPluginImports for HostState { + fn canister_call(&mut self, req: CanisterCallRequest) -> Result, String> { + use icp_canister_interfaces::proxy::{ProxyArgs, ProxyResult}; + + let arg_bytes = req.arg; + let cid = self.target_canister_id; + let method = req.method.clone(); + let agent = Arc::clone(&self.agent); + let call_type = req.call_type.unwrap_or(CallType::Update); + let proxy = if req.direct { None } else { self.proxy }; + + // We are already inside tokio::task::block_in_place (see sync/plugin.rs), + // so blocking the thread here is safe. + tokio::runtime::Handle::current().block_on(async move { + match call_type { + CallType::Update => { + if let Some(proxy_cid) = proxy { + let proxy_args = ProxyArgs { + canister_id: cid, + method: method.clone(), + args: arg_bytes, + cycles: candid::Nat::from(0u64), + }; + let encoded = Encode!(&proxy_args) + .map_err(|e| format!("proxy encode failed: {e}"))?; + let raw = agent + .update(&proxy_cid, "proxy") + .with_arg(encoded) + .await + .map_err(|e| format!("proxy call failed: {e}"))?; + let (result,): (ProxyResult,) = candid::decode_args(&raw) + .map_err(|e| format!("proxy decode failed: {e}"))?; + match result { + ProxyResult::Ok(ok) => Ok(ok.result), + ProxyResult::Err(err) => Err(err.format_error()), + } + } else { + agent + .update(&cid, &method) + .with_arg(arg_bytes) + .await + .map_err(|e| format!("canister call failed: {e}")) + } + } + CallType::Query => agent + .query(&cid, &method) + .with_arg(arg_bytes) + .call() + .await + .map_err(|e| format!("canister call failed: {e}")), + } + }) + } +} + +#[derive(Debug, Snafu)] +pub enum RunPluginError { + #[snafu(display("failed to create wasmtime engine for plugin at {path}"))] + CreateEngine { + source: wasmtime::Error, + path: Utf8PathBuf, + }, + + #[snafu(display("failed to load wasm component from {path}"))] + LoadComponent { + source: wasmtime::Error, + path: Utf8PathBuf, + }, + + #[snafu(display("failed to preopen directory '{dir}' for the plugin"))] + PreopenDir { + source: wasmtime::Error, + dir: Utf8PathBuf, + }, + + #[snafu(display("failed to instantiate wasm component at {path}"))] + Instantiate { + source: wasmtime::Error, + path: Utf8PathBuf, + }, + + #[snafu(display("failed to call exec() on plugin at {path}"))] + CallExec { + source: wasmtime::Error, + path: Utf8PathBuf, + }, + + #[snafu(display("plugin returned error: {message}"))] + PluginFailed { message: String }, +} + +pub fn run_plugin( + wasm_path: Utf8PathBuf, + base_dir: Utf8PathBuf, + dirs: Vec, + files: Vec<(String, String)>, + target_canister_id: Principal, + agent: Agent, + proxy: Option, + identity_principal: Principal, + environment: String, + stdio: Option>, +) -> Result<(), RunPluginError> { + use wasmtime::component::{Component, Linker}; + use wasmtime::{Config, Engine, Store}; + + let mut config = Config::new(); + config.wasm_component_model(true); + let engine = Engine::new(&config).context(CreateEngineSnafu { + path: wasm_path.clone(), + })?; + + let component = + Component::from_file(&engine, wasm_path.as_std_path()).context(LoadComponentSnafu { + path: wasm_path.clone(), + })?; + + // Preopen each declared directory read-only. The guest sees it at the + // same relative path it used in the manifest. + let mut wasi_builder = wasmtime_wasi::WasiCtxBuilder::new(); + for dir in &dirs { + let host_path = base_dir.join(dir); + wasi_builder + .preopened_dir( + host_path.as_std_path(), + dir, + DirPerms::READ, + FilePerms::READ, + ) + .context(PreopenDirSnafu { dir: host_path })?; + } + + let stdout_pipe = MemoryOutputPipe::new(usize::MAX); + let stderr_pipe = MemoryOutputPipe::new(usize::MAX); + if stdio.is_some() { + wasi_builder + .stdout(stdout_pipe.clone()) + .stderr(stderr_pipe.clone()); + } + + let host_state = HostState { + target_canister_id, + agent: Arc::new(agent), + proxy, + wasi_ctx: wasi_builder.build(), + wasi_table: wasmtime_wasi::ResourceTable::new(), + }; + + let mut linker: Linker = Linker::new(&engine); + wasmtime_wasi::p2::add_to_linker_sync(&mut linker).context(InstantiateSnafu { + path: wasm_path.clone(), + })?; + SyncPlugin::add_to_linker::<_, wasmtime::component::HasSelf<_>>(&mut linker, |s| s).context( + InstantiateSnafu { + path: wasm_path.clone(), + }, + )?; + + let mut store = Store::new(&engine, host_state); + + let plugin = + SyncPlugin::instantiate(&mut store, &component, &linker).context(InstantiateSnafu { + path: wasm_path.clone(), + })?; + + let input = SyncExecInput { + canister_id: target_canister_id.to_text(), + environment, + dirs, + files: files + .into_iter() + .map(|(name, content)| FileInput { name, content }) + .collect(), + identity_principal: identity_principal.to_text(), + proxy_canister_id: proxy.map(|p| p.to_text()), + }; + + let result = plugin + .call_exec(&mut store, &input) + .context(CallExecSnafu { path: wasm_path })?; + + if let Some(tx) = &stdio { + for bytes in [stdout_pipe.contents(), stderr_pipe.contents()] { + if !bytes.is_empty() { + let s = String::from_utf8_lossy(&bytes).into_owned(); + let _ = tx.blocking_send(s); + } + } + } + + match result { + Ok(Some(msg)) => { + if let Some(tx) = &stdio { + let _ = tx.blocking_send(msg); + } + } + Ok(None) => {} + Err(message) => return PluginFailedSnafu { message }.fail(), + } + + Ok(()) +} diff --git a/crates/icp-sync-plugin/sync-plugin.wit b/crates/icp-sync-plugin/sync-plugin.wit new file mode 100644 index 000000000..1491b7f8c --- /dev/null +++ b/crates/icp-sync-plugin/sync-plugin.wit @@ -0,0 +1,80 @@ +package icp:sync-plugin@0.1.0; + +/// Types shared between the host runtime and sync plugins. +interface types { + /// Whether a canister call is an update or a query. + enum call-type { update, query } + + /// A file the host read on behalf of the plugin. + record file-input { + /// Path of the file as declared in the manifest (relative to + /// the canister directory). + name: string, + /// UTF-8 contents of the file. + content: string, + } + + /// Input passed by the runtime to the plugin's exec() export. + record sync-exec-input { + /// Textual principal of the canister being synced. + canister-id: string, + /// Name of the environment being synced (e.g. "production", "local"). + environment: string, + /// Directories declared in the manifest step's `dirs` setting. + /// The host preopens each entry via WASI; the plugin can traverse + /// them with standard `wasi:filesystem` (e.g. Rust's `std::fs`). + dirs: list, + /// Files declared in the manifest step's `files` setting, read by + /// the host and passed inline. The plugin decides how to use them. + files: list, + /// Textual principal of the signing identity used for canister calls. + identity-principal: string, + /// Textual principal of the proxy canister, if one was configured via + /// `--proxy`. None when no proxy is in use. + proxy-canister-id: option, + } + + /// A request to call a method on the target canister. + record canister-call-request { + /// The canister method to call. + method: string, + /// Candid-encoded argument bytes. The plugin is responsible for + /// encoding; the host forwards these bytes unchanged. + arg: list, + /// Defaults to update if omitted. + call-type: option, + /// When true, the call bypasses any proxy canister configured via + /// `--proxy`, going directly to the target canister. When false + /// (the default), the host routes the call through the proxy if one + /// is configured. + direct: bool, + } +} + +/// The complete interface of a sync plugin. +world sync-plugin { + use types.{sync-exec-input, canister-call-request, file-input}; + + // ------------------------------------------------------------------------- + // Host functions (imports) — provided by icp-cli, called by the plugin + // ------------------------------------------------------------------------- + + /// Make an update or query call to the canister being synced. + /// The host always calls the canister from sync-exec-input.canister-id; + /// the plugin does not choose the target. + /// Returns the raw Candid-encoded response bytes on success or an error + /// message on failure. The plugin is responsible for decoding. + import canister-call: func(req: canister-call-request) -> result, string>; + + // The plugin's stdout and stderr are captured by the host and forwarded + // to the CLI's progress output, so plugins can simply print (e.g. + // Rust's `println!` / `eprintln!`) instead of calling a host import. + + // ------------------------------------------------------------------------- + // Plugin exports — implemented by the plugin, called by the host + // ------------------------------------------------------------------------- + + /// Execute the sync plugin for the canister being synced. + /// Returns optional output text on success or an error message on failure. + export exec: func(input: sync-exec-input) -> result, string>; +} diff --git a/crates/icp/Cargo.toml b/crates/icp/Cargo.toml index 3fbf01738..c6c5bee38 100644 --- a/crates/icp/Cargo.toml +++ b/crates/icp/Cargo.toml @@ -37,6 +37,7 @@ ic-ledger-types = { workspace = true } ic-management-canister-types = { workspace = true } ic-utils = { workspace = true } icp-canister-interfaces = { workspace = true } +icp-sync-plugin = { workspace = true } icrc-ledger-types = { workspace = true } indoc = { workspace = true } itertools = { workspace = true } diff --git a/crates/icp/src/canister/sync/mod.rs b/crates/icp/src/canister/sync/mod.rs index adc06ec69..59171c5aa 100644 --- a/crates/icp/src/canister/sync/mod.rs +++ b/crates/icp/src/canister/sync/mod.rs @@ -8,11 +8,17 @@ use crate::manifest::canister::SyncStep; use crate::prelude::*; mod assets; +mod plugin; mod script; pub struct Params { pub path: PathBuf, pub cid: Principal, + /// Name of the environment being synced (e.g. "local", "production"). + /// Passed to sync plugin steps via `SyncExecInput`. + pub environment: String, + /// Proxy canister to route calls through, if `--proxy` was passed. + pub proxy: Option, } #[derive(Debug, Snafu)] @@ -22,6 +28,9 @@ pub enum SynchronizeError { #[snafu(transparent)] Assets { source: assets::AssetsError }, + + #[snafu(transparent)] + Plugin { source: plugin::PluginError }, } #[async_trait] @@ -49,6 +58,15 @@ impl Synchronize for Syncer { match step { SyncStep::Assets(adapter) => Ok(assets::sync(adapter, params, agent).await?), SyncStep::Script(adapter) => Ok(script::sync(adapter, params, stdio).await?), + SyncStep::Plugin(adapter) => Ok(plugin::sync( + adapter, + params, + agent, + ¶ms.environment.clone(), + params.proxy, + stdio, + ) + .await?), } } } diff --git a/crates/icp/src/canister/sync/plugin.rs b/crates/icp/src/canister/sync/plugin.rs new file mode 100644 index 000000000..9912192e3 --- /dev/null +++ b/crates/icp/src/canister/sync/plugin.rs @@ -0,0 +1,177 @@ +use camino::Utf8PathBuf; +use candid::Principal; +use ic_agent::Agent; +use icp_sync_plugin::{RunPluginError, run_plugin}; +use reqwest::{Client, Method, Request}; +use sha2::{Digest, Sha256}; +use snafu::prelude::*; +use tokio::sync::mpsc::Sender; +use url::Url; + +use crate::{ + fs::{read, read_to_string, write}, + manifest::adapter::{plugin::Adapter, prebuilt::SourceField}, +}; + +use super::Params; + +#[derive(Debug, Snafu)] +pub enum PluginError { + #[snafu(display("failed to read plugin wasm at '{path}'"))] + ReadWasm { + source: crate::fs::IoError, + path: Utf8PathBuf, + }, + + #[snafu(display("failed to read plugin input file at '{path}'"))] + ReadFile { + source: crate::fs::IoError, + path: Utf8PathBuf, + }, + + #[snafu(display("failed to parse plugin url"))] + ParseUrl { source: url::ParseError }, + + #[snafu(display("failed to fetch plugin wasm file"))] + HttpRequest { source: reqwest::Error }, + + #[snafu(display("http request failed: {status}"))] + HttpStatus { status: reqwest::StatusCode }, + + #[snafu(display("failed to read http response for plugin"))] + HttpResponse { source: reqwest::Error }, + + #[snafu(display("failed to write downloaded plugin wasm to temp file"))] + WriteTempWasm { source: crate::fs::IoError }, + + #[snafu(display("plugin wasm checksum mismatch, expected: {expected}, actual: {actual}"))] + ChecksumMismatch { expected: String, actual: String }, + + #[snafu(display("failed to get identity principal: {err}"))] + GetIdentityPrincipal { err: String }, + + #[snafu(display("failed to run plugin"))] + Run { source: RunPluginError }, + + #[snafu(display("failed to send log message"))] + Log { + source: tokio::sync::mpsc::error::SendError, + }, +} + +pub(super) async fn sync( + adapter: &Adapter, + params: &Params, + agent: &Agent, + environment: &str, + proxy: Option, + stdio: Option>, +) -> Result<(), PluginError> { + // 1. Acquire the wasm bytes — either from a local path or a remote URL. + let (wasm_bytes, wasm_path) = match &adapter.source { + SourceField::Local(s) => { + let full_path = params.path.join(&s.path); + if let Some(tx) = &stdio { + tx.send(format!("Reading plugin wasm: {full_path}")) + .await + .context(LogSnafu)?; + } + let bytes = read(full_path.as_ref()).context(ReadWasmSnafu { + path: full_path.clone(), + })?; + (bytes, full_path) + } + + SourceField::Remote(s) => { + let url = Url::parse(&s.url).context(ParseUrlSnafu)?; + if let Some(tx) = &stdio { + tx.send(format!("Fetching plugin wasm: {url}")) + .await + .context(LogSnafu)?; + } + let client = Client::new(); + let req = Request::new(Method::GET, url); + let resp = client.execute(req).await.context(HttpRequestSnafu)?; + let status = resp.status(); + if !status.is_success() { + return HttpStatusSnafu { status }.fail(); + } + let bytes = resp.bytes().await.context(HttpResponseSnafu)?.to_vec(); + + // Write to a temp file so we can pass a path to `run_plugin`. + let tmp_path = params.path.join(format!( + ".icp-plugin-{}.wasm", + hex::encode(&bytes[..std::cmp::min(8, bytes.len())]) + )); + write(tmp_path.as_ref(), &bytes).context(WriteTempWasmSnafu)?; + (bytes, tmp_path) + } + }; + + // 2. Verify sha256 checksum if provided. + let cksum = hex::encode({ + let mut h = Sha256::new(); + h.update(&wasm_bytes); + h.finalize() + }); + + if let Some(expected) = &adapter.sha256 { + if let Some(tx) = &stdio { + tx.send("Verifying plugin wasm checksum".to_string()) + .await + .context(LogSnafu)?; + } + if &cksum != expected { + return ChecksumMismatchSnafu { + expected: expected.clone(), + actual: cksum, + } + .fail(); + } + } + + // 3. Collect inputs: `dirs` stays as manifest strings (runtime preopens them), + // `files` are read on the host and passed inline. + let base_dir = Utf8PathBuf::from(params.path.as_str()); + let dirs: Vec = adapter.dirs.clone().unwrap_or_default(); + + let mut files: Vec<(String, String)> = Vec::new(); + for name in adapter.files.as_deref().unwrap_or(&[]) { + let abs = params.path.join(name); + let content = read_to_string(abs.as_ref()).context(ReadFileSnafu { path: abs })?; + files.push((name.clone(), content)); + } + + // 4. Run the plugin (blocking call — signal Tokio that this thread will block). + let identity_principal = agent + .get_principal() + .map_err(|err| PluginError::GetIdentityPrincipal { err })?; + + let wasm_path_buf = Utf8PathBuf::from(wasm_path.as_str()); + let agent_clone = agent.clone(); + let environment_owned = environment.to_owned(); + let stdio_clone = stdio.clone(); + + tokio::task::block_in_place(|| { + run_plugin( + wasm_path_buf, + base_dir, + dirs, + files, + params.cid, + agent_clone, + proxy, + identity_principal, + environment_owned, + stdio_clone, + ) + }) + .context(RunSnafu)?; + + // Clean up temp file if we downloaded from a remote URL. + if matches!(&adapter.source, SourceField::Remote(_)) { + let _ = std::fs::remove_file(wasm_path.as_std_path()); + } + + Ok(()) +} diff --git a/crates/icp/src/manifest/adapter/mod.rs b/crates/icp/src/manifest/adapter/mod.rs index 99c66b732..d631d1430 100644 --- a/crates/icp/src/manifest/adapter/mod.rs +++ b/crates/icp/src/manifest/adapter/mod.rs @@ -1,3 +1,4 @@ pub mod assets; +pub mod plugin; pub mod prebuilt; pub mod script; diff --git a/crates/icp/src/manifest/adapter/plugin.rs b/crates/icp/src/manifest/adapter/plugin.rs new file mode 100644 index 000000000..b0b87f291 --- /dev/null +++ b/crates/icp/src/manifest/adapter/plugin.rs @@ -0,0 +1,114 @@ +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; + +use super::prebuilt::SourceField; + +/// Configuration for a sync plugin step. +/// +/// A sync plugin is a WebAssembly module invoked during `icp sync` for a +/// specific canister. It runs inside a WASI sandbox whose filesystem access +/// is limited to the directories listed in `dirs` (preopened read-only) plus +/// the contents of any files listed in `files` (read by the host and passed +/// inline to the plugin). +/// +/// Example: +/// ```yaml +/// - type: plugin +/// path: ./plugins/populate-data.wasm +/// sha256: e3b0c44298fc1c149afb... # optional but recommended +/// dirs: # directories preopened read-only +/// - assets/seed-data +/// files: # files read by the host and passed inline +/// - config.txt +/// ``` +#[derive(Clone, Debug, Deserialize, PartialEq, JsonSchema, Serialize)] +pub struct Adapter { + #[serde(flatten)] + pub source: SourceField, + + /// Optional sha256 checksum of the wasm file. + /// Required when `url` is used; optional (but recommended) for `path`. + pub sha256: Option, + + /// Directories (relative to canister directory) the plugin may read from. + /// Each entry must be a directory; it is preopened via WASI so the plugin + /// can traverse it using standard filesystem APIs. + pub dirs: Option>, + + /// Files (relative to canister directory) the host reads and passes to + /// the plugin as part of `sync-exec-input.files`. + pub files: Option>, +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::manifest::adapter::prebuilt::{LocalSource, RemoteSource}; + + #[test] + fn local_path() { + assert_eq!( + serde_yaml::from_str::( + r#" + path: plugins/my-sync.wasm + "# + ) + .expect("failed to deserialize Adapter from yaml"), + Adapter { + source: SourceField::Local(LocalSource { + path: "plugins/my-sync.wasm".into(), + }), + sha256: None, + dirs: None, + files: None, + }, + ); + } + + #[test] + fn local_path_with_sha256_dirs_and_files() { + assert_eq!( + serde_yaml::from_str::( + r#" + path: plugins/my-sync.wasm + sha256: abc123 + dirs: + - assets/seed-data + - config + files: + - config.txt + "# + ) + .expect("failed to deserialize Adapter from yaml"), + Adapter { + source: SourceField::Local(LocalSource { + path: "plugins/my-sync.wasm".into(), + }), + sha256: Some("abc123".to_string()), + dirs: Some(vec!["assets/seed-data".to_string(), "config".to_string()]), + files: Some(vec!["config.txt".to_string()]), + }, + ); + } + + #[test] + fn remote_url_with_sha256() { + assert_eq!( + serde_yaml::from_str::( + r#" + url: https://example.com/plugins/migrate-v2.wasm + sha256: a665a45920422f9d417e + "# + ) + .expect("failed to deserialize Adapter from yaml"), + Adapter { + source: SourceField::Remote(RemoteSource { + url: "https://example.com/plugins/migrate-v2.wasm".to_string(), + }), + sha256: Some("a665a45920422f9d417e".to_string()), + dirs: None, + files: None, + }, + ); + } +} diff --git a/crates/icp/src/manifest/adapter/prebuilt.rs b/crates/icp/src/manifest/adapter/prebuilt.rs index 599540a64..9974d75f1 100644 --- a/crates/icp/src/manifest/adapter/prebuilt.rs +++ b/crates/icp/src/manifest/adapter/prebuilt.rs @@ -27,7 +27,8 @@ pub enum SourceField { Remote(RemoteSource), } -/// Configuration for a Pre-built canister build adapter. +/// Configuration for a wasm source — used by adapters that load a `.wasm` file +/// either from a local path or from a remote URL. #[derive(Clone, Debug, Deserialize, PartialEq, JsonSchema, Serialize)] pub struct Adapter { #[serde(flatten)] diff --git a/crates/icp/src/manifest/canister.rs b/crates/icp/src/manifest/canister.rs index 6fafaf721..48f786e13 100644 --- a/crates/icp/src/manifest/canister.rs +++ b/crates/icp/src/manifest/canister.rs @@ -316,6 +316,11 @@ pub enum SyncStep { /// Represents syncing of an assets canister Assets(adapter::assets::Adapter), + + /// Represents a sync step executed by a WebAssembly plugin running inside + /// the Extism sandbox. The plugin can call canister methods on exactly + /// the canister being synced and read files from the declared `dirs`. + Plugin(adapter::plugin::Adapter), } impl fmt::Display for SyncStep { @@ -326,6 +331,13 @@ impl fmt::Display for SyncStep { match self { SyncStep::Script(v) => format!("script {v}"), SyncStep::Assets(v) => format!("assets {v}"), + SyncStep::Plugin(v) => { + let src = match &v.source { + adapter::prebuilt::SourceField::Local(l) => format!("path: {}", l.path), + adapter::prebuilt::SourceField::Remote(r) => format!("url: {}", r.url), + }; + format!("plugin {src}") + } } ) } @@ -722,6 +734,92 @@ mod tests { }; } + #[test] + fn sync_steps_plugin_local() { + assert_eq!( + validate_canister_yaml(indoc! {r#" + name: my-canister + build: + steps: + - type: script + command: dosomething.sh + sync: + steps: + - type: plugin + path: ./plugins/my-sync.wasm + dirs: + - assets/seed-data/ + "#}), + CanisterManifest { + name: "my-canister".to_string(), + settings: Settings::default(), + init_args: None, + instructions: Instructions::BuildSync { + build: BuildSteps { + steps: vec![BuildStep::Script(script::Adapter { + command: script::CommandField::Command("dosomething.sh".to_string()), + })] + }, + sync: Some(SyncSteps { + steps: vec![SyncStep::Plugin( + crate::manifest::adapter::plugin::Adapter { + source: prebuilt::SourceField::Local(prebuilt::LocalSource { + path: "./plugins/my-sync.wasm".into(), + }), + sha256: None, + dirs: Some(vec!["assets/seed-data/".to_string()]), + files: None, + } + )] + }), + }, + }, + ); + } + + #[test] + fn sync_steps_plugin_remote() { + assert_eq!( + validate_canister_yaml(indoc! {r#" + name: my-canister + build: + steps: + - type: script + command: dosomething.sh + sync: + steps: + - type: plugin + url: https://example.com/plugins/migrate-v2.wasm + sha256: a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3 + "#}), + CanisterManifest { + name: "my-canister".to_string(), + settings: Settings::default(), + init_args: None, + instructions: Instructions::BuildSync { + build: BuildSteps { + steps: vec![BuildStep::Script(script::Adapter { + command: script::CommandField::Command("dosomething.sh".to_string()), + })] + }, + sync: Some(SyncSteps { + steps: vec![SyncStep::Plugin(crate::manifest::adapter::plugin::Adapter { + source: prebuilt::SourceField::Remote(prebuilt::RemoteSource { + url: "https://example.com/plugins/migrate-v2.wasm".to_string(), + }), + sha256: Some( + "a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3" + .to_string() + ), + dirs: None, + files: None, + })] + }), + }, + }, + ); + } + #[test] fn sync_steps() { assert_eq!( diff --git a/docs/reference/cli.md b/docs/reference/cli.md index 8377994d1..c4bbe984c 100644 --- a/docs/reference/cli.md +++ b/docs/reference/cli.md @@ -1469,6 +1469,7 @@ Synchronize canisters ###### **Options:** +* `--proxy ` — Principal of a proxy canister to route management canister calls through * `-e`, `--environment ` — Override the environment to connect to. By default, the local environment is used * `--identity ` — The user identity to run this command as diff --git a/docs/schemas/canister-yaml-schema.json b/docs/schemas/canister-yaml-schema.json index ba1ac9637..8b15fc5a5 100644 --- a/docs/schemas/canister-yaml-schema.json +++ b/docs/schemas/canister-yaml-schema.json @@ -44,7 +44,7 @@ "description": "Remote url to fetch a WASM file from" } ], - "description": "Configuration for a Pre-built canister build adapter.", + "description": "Configuration for a wasm source — used by adapters that load a `.wasm` file\neither from a local path or from a remote URL.", "properties": { "sha256": { "description": "Optional sha256 checksum of the WASM", @@ -89,6 +89,49 @@ ], "type": "object" }, + "Adapter4": { + "anyOf": [ + { + "$ref": "#/$defs/LocalSource", + "description": "Local path on-disk to read a WASM file from" + }, + { + "$ref": "#/$defs/RemoteSource", + "description": "Remote url to fetch a WASM file from" + } + ], + "description": "Configuration for a sync plugin step.\n\nA sync plugin is a WebAssembly module invoked during `icp sync` for a\nspecific canister. It runs inside a WASI sandbox whose filesystem access\nis limited to the directories listed in `dirs` (preopened read-only) plus\nthe contents of any files listed in `files` (read by the host and passed\ninline to the plugin).\n\nExample:\n```yaml\n- type: plugin\n path: ./plugins/populate-data.wasm\n sha256: e3b0c44298fc1c149afb... # optional but recommended\n dirs: # directories preopened read-only\n - assets/seed-data\n files: # files read by the host and passed inline\n - config.txt\n```", + "properties": { + "dirs": { + "description": "Directories (relative to canister directory) the plugin may read from.\nEach entry must be a directory; it is preopened via WASI so the plugin\ncan traverse it using standard filesystem APIs.", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "files": { + "description": "Files (relative to canister directory) the host reads and passes to\nthe plugin as part of `sync-exec-input.files`.", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "sha256": { + "description": "Optional sha256 checksum of the wasm file.\nRequired when `url` is used; optional (but recommended) for `path`.", + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, "ArgsFormat": { "description": "Format specifier for canister call/install args content.", "oneOf": [ @@ -452,6 +495,20 @@ "type" ], "type": "object" + }, + { + "$ref": "#/$defs/Adapter4", + "description": "Represents a sync step executed by a WebAssembly plugin running inside\nthe Extism sandbox. The plugin can call canister methods on exactly\nthe canister being synced and read files from the declared `dirs`.", + "properties": { + "type": { + "const": "plugin", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" } ] }, diff --git a/docs/schemas/icp-yaml-schema.json b/docs/schemas/icp-yaml-schema.json index efd5d1bc7..afcbcd76d 100644 --- a/docs/schemas/icp-yaml-schema.json +++ b/docs/schemas/icp-yaml-schema.json @@ -44,7 +44,7 @@ "description": "Remote url to fetch a WASM file from" } ], - "description": "Configuration for a Pre-built canister build adapter.", + "description": "Configuration for a wasm source — used by adapters that load a `.wasm` file\neither from a local path or from a remote URL.", "properties": { "sha256": { "description": "Optional sha256 checksum of the WASM", @@ -89,6 +89,49 @@ ], "type": "object" }, + "Adapter4": { + "anyOf": [ + { + "$ref": "#/$defs/LocalSource", + "description": "Local path on-disk to read a WASM file from" + }, + { + "$ref": "#/$defs/RemoteSource", + "description": "Remote url to fetch a WASM file from" + } + ], + "description": "Configuration for a sync plugin step.\n\nA sync plugin is a WebAssembly module invoked during `icp sync` for a\nspecific canister. It runs inside a WASI sandbox whose filesystem access\nis limited to the directories listed in `dirs` (preopened read-only) plus\nthe contents of any files listed in `files` (read by the host and passed\ninline to the plugin).\n\nExample:\n```yaml\n- type: plugin\n path: ./plugins/populate-data.wasm\n sha256: e3b0c44298fc1c149afb... # optional but recommended\n dirs: # directories preopened read-only\n - assets/seed-data\n files: # files read by the host and passed inline\n - config.txt\n```", + "properties": { + "dirs": { + "description": "Directories (relative to canister directory) the plugin may read from.\nEach entry must be a directory; it is preopened via WASI so the plugin\ncan traverse it using standard filesystem APIs.", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "files": { + "description": "Files (relative to canister directory) the host reads and passes to\nthe plugin as part of `sync-exec-input.files`.", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "sha256": { + "description": "Optional sha256 checksum of the wasm file.\nRequired when `url` is used; optional (but recommended) for `path`.", + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, "ArgsFormat": { "description": "Format specifier for canister call/install args content.", "oneOf": [ @@ -948,6 +991,20 @@ "type" ], "type": "object" + }, + { + "$ref": "#/$defs/Adapter4", + "description": "Represents a sync step executed by a WebAssembly plugin running inside\nthe Extism sandbox. The plugin can call canister methods on exactly\nthe canister being synced and read files from the declared `dirs`.", + "properties": { + "type": { + "const": "plugin", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" } ] }, diff --git a/examples/icp-sync-plugin/Cargo.lock b/examples/icp-sync-plugin/Cargo.lock new file mode 100644 index 000000000..5de2ce58d --- /dev/null +++ b/examples/icp-sync-plugin/Cargo.lock @@ -0,0 +1,966 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "ar_archive_writer" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eb93bbb63b9c227414f6eb3a0adfddca591a8ce1e9b60661bb08969b87e340b" +dependencies = [ + "object", +] + +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "binread" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16598dfc8e6578e9b597d9910ba2e73618385dc9f4b1d43dd92c349d6be6418f" +dependencies = [ + "binread_derive", + "lazy_static", + "rustversion", +] + +[[package]] +name = "binread_derive" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d9672209df1714ee804b1f4d4f68c8eb2a90b1f7a07acf472f88ce198ef1fed" +dependencies = [ + "either", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "bitflags" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "candid" +version = "0.10.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ba5b4833b63bf7b785fecdd2cc918ed90d988fd974825d5c48e7b407c39ef38" +dependencies = [ + "anyhow", + "binread", + "byteorder", + "candid_derive", + "hex", + "ic_principal", + "leb128", + "num-bigint", + "num-traits", + "paste", + "pretty", + "serde", + "serde_bytes", + "stacker", + "thiserror 1.0.69", +] + +[[package]] +name = "candid_derive" +version = "0.10.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b60664b6324832dfb4863f3b19eb4d58819cd38fba6d3941b101213cea0d9ec" +dependencies = [ + "lazy_static", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "canister" +version = "0.1.0" +dependencies = [ + "candid", + "ic-cdk", +] + +[[package]] +name = "cc" +version = "1.2.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43c5703da9466b66a946814e1adf53ea2c90f10063b86290cc9eb67ce3478a20" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "darling" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" +dependencies = [ + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.117", +] + +[[package]] +name = "darling_macro" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "data-encoding" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "foldhash", +] + +[[package]] +name = "hashbrown" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "ic-cdk" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "057912339f889013f42b36cc0623585949ed278457efb32aef041bdc48acb111" +dependencies = [ + "candid", + "ic-cdk-executor", + "ic-cdk-macros", + "ic-error-types", + "ic0", + "pin-project-lite", + "serde", + "thiserror 2.0.18", +] + +[[package]] +name = "ic-cdk-executor" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33716b730ded33690b8a704bff3533fda87d229e58046823647d28816e9bcee7" +dependencies = [ + "ic0", + "slotmap", + "smallvec", +] + +[[package]] +name = "ic-cdk-macros" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b140627c01710ac185fbc984ab1fda1781ffef4abbd952e07383350899b0952b" +dependencies = [ + "candid", + "darling", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "ic-error-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbeeb3d91aa179d6496d7293becdacedfc413c825cac79fd54ea1906f003ee55" +dependencies = [ + "serde", + "strum", + "strum_macros", +] + +[[package]] +name = "ic0" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1499d08fd5be8f790d477e1865d63bab6a8d748300e141270c4296e6d5fdd6bc" + +[[package]] +name = "ic_principal" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2b6c5941dfd659e77b262342fa58ad49489367ad026255cda8c43682d0c534" +dependencies = [ + "crc32fast", + "data-encoding", + "serde", + "sha2", + "thiserror 1.0.69", +] + +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown 0.17.0", + "serde", + "serde_core", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "leb128" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cc46bac87ef8093eed6f272babb833b6443374399985ac8ed28471ee0918545" + +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + +[[package]] +name = "libc" +version = "0.2.185" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ff2c0fe9bc6cb6b14a0592c2ff4fa9ceb83eea9db979b0487cd054946a2b8f" + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "macro-string" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59a9dbbfc75d2688ed057456ce8a3ee3f48d12eec09229f560f3643b9f275653" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", + "serde", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "object" +version = "0.37.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" +dependencies = [ + "memchr", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "plugin" +version = "0.1.0" +dependencies = [ + "candid", + "wit-bindgen", +] + +[[package]] +name = "pretty" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d22152487193190344590e4f30e219cf3fe140d9e7a3fdb683d82aa2c5f4156" +dependencies = [ + "arrayvec", + "typed-arena", + "unicode-width", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn 2.0.117", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "psm" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3852766467df634d74f0b2d7819bf8dc483a0eb2e3b0f50f756f9cfe8b0d18d8" +dependencies = [ + "ar_archive_writer", + "cc", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_bytes" +version = "0.11.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5d440709e79d88e51ac01c4b72fc6cb7314017bb7da9eeff678aa94c10e3ea8" +dependencies = [ + "serde", + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "slotmap" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdd58c3c93c3d278ca835519292445cb4b0d4dc59ccfdf7ceadaab3f8aeb4038" +dependencies = [ + "version_check", +] + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "stacker" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d74a23609d509411d10e2176dc2a4346e3b4aea2e7b1869f19fdedbc71c013" +dependencies = [ + "cc", + "cfg-if", + "libc", + "psm", + "windows-sys", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.117", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl 2.0.18", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "typed-arena" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" + +[[package]] +name = "typenum" +version = "1.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-width" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wasm-encoder" +version = "0.246.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61fb705ce81adde29d2a8e99d87995e39a6e927358c91398f374474746070ef7" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.246.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3e4c2aa916c425dcca61a6887d3e135acdee2c6d0ed51fd61c08d41ddaf62b1" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.246.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71cde4757396defafd25417cfb36aa3161027d06d865b0c24baaae229aac005d" +dependencies = [ + "bitflags", + "hashbrown 0.16.1", + "indexmap", + "semver", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[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_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "wit-bindgen" +version = "0.56.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7607d30e7e5e8fd5a0695f7cb8b2128829e0bf9dca7a1fe8c4d6ed3ca1058fce" +dependencies = [ + "bitflags", + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.56.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fda3a4ce47c08d27f575d451a60102bab5251776abd0a7a323d1f038eb6339ab" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.56.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "920a1c8c0f89397431db4900a7bf7c511b78e1b7068289fe812dc76e993f1491" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn 2.0.117", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.56.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "857a143d2373abfcd31ad946393efe775ed8c90a2a365ce73c61bf38f36a1000" +dependencies = [ + "anyhow", + "macro-string", + "prettyplease", + "proc-macro2", + "quote", + "syn 2.0.117", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.246.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1936c26cb24b93dc36bf78fb5dc35c55cd37f66ecdc2d2663a717d9fb3ee951e" +dependencies = [ + "anyhow", + "bitflags", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.246.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd979042b5ff288607ccf3b314145435453f20fc67173195f91062d2289b204d" +dependencies = [ + "anyhow", + "hashbrown 0.16.1", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/examples/icp-sync-plugin/Cargo.toml b/examples/icp-sync-plugin/Cargo.toml new file mode 100644 index 000000000..77fbd035e --- /dev/null +++ b/examples/icp-sync-plugin/Cargo.toml @@ -0,0 +1,3 @@ +[workspace] +members = ["canister", "plugin"] +resolver = "2" diff --git a/examples/icp-sync-plugin/README.md b/examples/icp-sync-plugin/README.md new file mode 100644 index 000000000..57518b0ab --- /dev/null +++ b/examples/icp-sync-plugin/README.md @@ -0,0 +1,83 @@ +# icp-sync-plugin example + +This example demonstrates the sync plugin system: a Wasm component that runs +inside `icp sync` and drives canister update calls on behalf of the user. + +## Project structure + +``` +icp-sync-plugin/ +├── canister/ # The target canister (compiled to wasm32-unknown-unknown) +├── plugin/ # The sync plugin (compiled to wasm32-wasip2) +├── seed-data/ # Fruit files the plugin registers (preopened via WASI) +└── icp.yaml # Manifest wiring the build and sync steps together +``` + +### `canister/` + +A simple Rust canister with three methods: + +| Method | Type | Description | +|---|---|---| +| `set_uploader(principal)` | update | Stores a principal as the authorised uploader. Restricted to canister controllers. | +| `register(name, content)` | update | Appends a `(name, content)` fruit pair. Restricted to the stored uploader. | +| `show()` | query | Returns the current uploader principal and all registered fruits. | + +### `plugin/` + +A Rust Wasm component that implements the `sync-plugin` world defined in +`crates/icp-sync-plugin/sync-plugin.wit`. The host runtime calls its `exec` +export and provides a `canister-call` import the plugin uses to reach the +canister. + +## How the plugin system is exercised + +This example is designed to demonstrate both routing modes of the +`canister-call` import — the `direct` flag — in a single sync run. + +### Call 1 — `set_uploader` via proxy (`direct: false`) + +The plugin reads `identity-principal` from `sync-exec-input` (the signing +identity the CLI is using) and calls `set_uploader` with it. The call is +routed through the proxy canister (`direct: false`), so it arrives at the +target canister with the **proxy's principal as the caller**. Because the proxy +canister is listed as a controller of the target, the controller guard passes. + +This models a pattern where privileged, one-time setup calls must come from a +known controller — not directly from an end-user identity. + +### Call 2 — `register` directly (`direct: true`) + +For each file under `seed-data/`, the plugin calls `register` with +`direct: true`, bypassing the proxy entirely. The call arrives at the canister +with the **user's identity principal as the caller**, which is exactly the +uploader stored in step 1, so the uploader guard passes. + +This models a pattern where bulk data-upload calls must be attributable to the +actual user identity rather than a shared proxy. + +### Data flow summary + +``` +icp sync + └─ host runtime loads plugin.wasm + ├─ exec(sync-exec-input) called + │ identity-principal = + │ proxy-canister-id = + │ + ├─ canister-call set_uploader() direct=false → proxy → canister + │ canister stores uploader = + │ + └─ canister-call register(name, content) direct=true → canister (× N files) + canister checks caller == uploader ✓ +``` + +## Building + +```bash +# Build the canister +cargo build --target wasm32-unknown-unknown --release -p canister + +# Build the plugin +cargo build --target wasm32-wasip2 --release -p plugin +``` diff --git a/examples/icp-sync-plugin/canister/Cargo.toml b/examples/icp-sync-plugin/canister/Cargo.toml new file mode 100644 index 000000000..09b64f280 --- /dev/null +++ b/examples/icp-sync-plugin/canister/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "canister" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +candid = "0.10" +ic-cdk = "0.20" diff --git a/examples/icp-sync-plugin/canister/src/lib.rs b/examples/icp-sync-plugin/canister/src/lib.rs new file mode 100644 index 000000000..6fd8fbd8e --- /dev/null +++ b/examples/icp-sync-plugin/canister/src/lib.rs @@ -0,0 +1,41 @@ +use std::cell::RefCell; + +use candid::Principal; + +thread_local! { + static UPLOADER: RefCell> = RefCell::default(); + static FRUITS: RefCell> = RefCell::default(); +} + +// Set the uploader principal (controller-only). Called once via the proxy canister. +#[ic_cdk::update] +fn set_uploader(uploader: Principal) { + let caller = ic_cdk::api::msg_caller(); + assert!( + ic_cdk::api::is_controller(&caller), + "only a controller can call set_uploader" + ); + UPLOADER.with_borrow_mut(|u| *u = Some(uploader)); +} + +// Register a (name, content) fruit pair. Restricted to the stored uploader. +#[ic_cdk::update] +fn register(name: String, content: String) { + let caller = ic_cdk::api::msg_caller(); + let uploader = UPLOADER.with_borrow(|u| *u); + assert_eq!( + Some(caller), + uploader, + "only the uploader can call register" + ); + FRUITS.with_borrow_mut(|f| f.push((name, content))); +} + +// Return the stored uploader principal and every registered fruit. +#[ic_cdk::query] +fn show() -> (Option, Vec<(String, String)>) { + ( + UPLOADER.with_borrow(|u| *u), + FRUITS.with_borrow(|f| f.clone()), + ) +} diff --git a/examples/icp-sync-plugin/config.txt b/examples/icp-sync-plugin/config.txt new file mode 100644 index 000000000..38f8e886e --- /dev/null +++ b/examples/icp-sync-plugin/config.txt @@ -0,0 +1 @@ +dev diff --git a/examples/icp-sync-plugin/demo.did b/examples/icp-sync-plugin/demo.did new file mode 100644 index 000000000..95328f1b3 --- /dev/null +++ b/examples/icp-sync-plugin/demo.did @@ -0,0 +1,5 @@ +service : { + set_uploader : (principal) -> (); + register : (text, text) -> (); + show : () -> (opt principal, vec record { text; text }) query; +} diff --git a/examples/icp-sync-plugin/icp.yaml b/examples/icp-sync-plugin/icp.yaml new file mode 100644 index 000000000..134cfd827 --- /dev/null +++ b/examples/icp-sync-plugin/icp.yaml @@ -0,0 +1,22 @@ +canisters: + - name: my-canister + build: + steps: + - type: script + commands: + - cargo build --target wasm32-unknown-unknown --release --locked -p canister + - mv target/wasm32-unknown-unknown/release/canister.wasm "$ICP_WASM_OUTPUT_PATH" + + - type: script + commands: + - command -v ic-wasm >/dev/null 2>&1 || { echo >&2 "ic-wasm not found. To install ic-wasm, see https://github.com/dfinity/ic-wasm\n"; exit 1; } + - ic-wasm "$ICP_WASM_OUTPUT_PATH" -o "$ICP_WASM_OUTPUT_PATH" metadata candid:service -f demo.did --keep-name-section + + sync: + steps: + - type: plugin + # Path to the compiled PoC plugin wasm, relative to this directory. + # Build it first: cargo build -p plugin --target wasm32-wasip2 --release + path: target/wasm32-wasip2/release/plugin.wasm + dirs: + - seed-data diff --git a/examples/icp-sync-plugin/plugin/Cargo.toml b/examples/icp-sync-plugin/plugin/Cargo.toml new file mode 100644 index 000000000..cbecad57f --- /dev/null +++ b/examples/icp-sync-plugin/plugin/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "plugin" +version = "0.1.0" +edition = "2024" +publish = false + +[lib] +crate-type = ["cdylib"] + +[dependencies] +candid = "0.10.19" +wit-bindgen = { version = "0.56", features = ["realloc"] } diff --git a/examples/icp-sync-plugin/plugin/build.rs b/examples/icp-sync-plugin/plugin/build.rs new file mode 100644 index 000000000..70f9202ea --- /dev/null +++ b/examples/icp-sync-plugin/plugin/build.rs @@ -0,0 +1,3 @@ +fn main() { + println!("cargo:rerun-if-changed=../../../crates/icp-sync-plugin/sync-plugin.wit"); +} diff --git a/examples/icp-sync-plugin/plugin/src/lib.rs b/examples/icp-sync-plugin/plugin/src/lib.rs new file mode 100644 index 000000000..e4a3fdc44 --- /dev/null +++ b/examples/icp-sync-plugin/plugin/src/lib.rs @@ -0,0 +1,80 @@ +wit_bindgen::generate!({ + world: "sync-plugin", + path: "../../../crates/icp-sync-plugin/sync-plugin.wit", +}); + +use std::fs; +use std::path::Path; + +use candid::{Encode, Principal}; + +struct Plugin; + +impl Guest for Plugin { + fn exec(input: SyncExecInput) -> Result, String> { + println!( + "sync plugin: starting for canister {} (environment: {})", + input.canister_id, input.environment + ); + + // 1. Set the uploader to the current identity principal. + // Routed through the proxy (direct: false) so the controller-gated + // call is signed by the proxy canister, which is a controller. + let uploader = Principal::from_text(&input.identity_principal) + .map_err(|e| format!("invalid identity principal: {e}"))?; + let arg = Encode!(&uploader).map_err(|e| format!("encode set_uploader arg: {e}"))?; + canister_call(&CanisterCallRequest { + method: "set_uploader".to_string(), + arg, + call_type: Some(icp::sync_plugin::types::CallType::Update), + direct: false, + })?; + println!("set_uploader ({}): ok", input.identity_principal); + + // 2. Register every file found by traversing the preopened dirs. + // Direct calls (direct: true) because register is gated on the + // uploader principal, which is the current identity — not the proxy. + let mut registered = 0u32; + for dir in &input.dirs { + registered += register_dir(Path::new(dir))?; + } + + Ok(Some(format!( + "registered {} item(s) in canister {} (environment: {})", + registered, input.canister_id, input.environment + ))) + } +} + +fn register_dir(dir: &Path) -> Result { + let entries = fs::read_dir(dir).map_err(|e| format!("read_dir {}: {e}", dir.display()))?; + let mut count = 0u32; + for entry in entries { + let entry = entry.map_err(|e| format!("dir entry in {}: {e}", dir.display()))?; + let path = entry.path(); + let file_type = entry + .file_type() + .map_err(|e| format!("file_type {}: {e}", path.display()))?; + if file_type.is_dir() { + count += register_dir(&path)?; + } else if file_type.is_file() { + let content = fs::read_to_string(&path) + .map_err(|e| format!("read_to_string {}: {e}", path.display()))?; + let path_str = path.to_string_lossy().into_owned(); + let content_trimmed = content.trim(); + let arg = Encode!(&path_str, &content_trimmed) + .map_err(|e| format!("encode register arg: {e}"))?; + canister_call(&CanisterCallRequest { + method: "register".to_string(), + arg, + call_type: Some(icp::sync_plugin::types::CallType::Update), + direct: true, + })?; + println!("{path_str}: ok"); + count += 1; + } + } + Ok(count) +} + +export!(Plugin); diff --git a/examples/icp-sync-plugin/seed-data/fruit-01.txt b/examples/icp-sync-plugin/seed-data/fruit-01.txt new file mode 100644 index 000000000..4c479deff --- /dev/null +++ b/examples/icp-sync-plugin/seed-data/fruit-01.txt @@ -0,0 +1 @@ +apple diff --git a/examples/icp-sync-plugin/seed-data/fruit-02.txt b/examples/icp-sync-plugin/seed-data/fruit-02.txt new file mode 100644 index 000000000..637a09b86 --- /dev/null +++ b/examples/icp-sync-plugin/seed-data/fruit-02.txt @@ -0,0 +1 @@ +banana diff --git a/examples/icp-sync-plugin/seed-data/fruit-03.txt b/examples/icp-sync-plugin/seed-data/fruit-03.txt new file mode 100644 index 000000000..44a910549 --- /dev/null +++ b/examples/icp-sync-plugin/seed-data/fruit-03.txt @@ -0,0 +1 @@ +cherry diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 43e5784a1..cdeba7a2b 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "1.90.0" +channel = "1.91.0" components = ["rustfmt", "clippy"]