Conversation
WASM CI check statusI investigated expanding the CI WASM check from Blocker: upstream transitive dependencies
The offending dependency chain: Cargo's feature unification means even though What's neededThe upstream crates ( # In upstream Cargo.toml:
reqwest = { version = "0.12", default-features = false, features = ["json"] }
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
reqwest = { version = "0.12", default-features = false, features = ["rustls-tls"] }Once upstream makes that change, Current CI scopeFor now, CI can check:
The CI workflow changes from #251 couldn't be pushed due to token scope limitations ( |
e49f23e to
693a285
Compare
|
Warning Review the following alerts detected in dependencies. According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.
|
storage feature flaga4bc092 to
c4f5401
Compare
| /// | ||
| /// Returns an error if the embedded material cannot be loaded or verified. | ||
| #[uniffi::constructor] | ||
| pub fn from_embedded() -> Result<Self, WalletKitError> { |
There was a problem hiding this comment.
/otto let's feature gate this - make sure to also feature gate the embed-zkeys feature on world-id crates
There was a problem hiding this comment.
On it — I'll gate Groth16Materials + from_embedded behind an embed-zkeys feature flag, and ensure the embed-zkeys feature on the world-id crates is only activated when that feature is enabled in walletkit/walletkit-core.
There was a problem hiding this comment.
/otto the function should also be feature gated
There was a problem hiding this comment.
/otto ignore - it actually is
There was a problem hiding this comment.
On it — adding #[cfg(feature = "embed-zkeys")] directly on the function as well.
There was a problem hiding this comment.
Got it, no action needed then.
|
/otto rebase against main, resolve any conflicts and resolve CI issues |
|
On it — spawning a job to rebase against |
|
|
On it — rebasing against |
0ab2dee to
13b0c9d
Compare
|
Rebase complete ✅ — one commit behind
Branch force-pushed. |
|
/otto fix ci |
|
Checking CI failures now — will fix and update here. |
|
CI fixed ✅ — the only failure was "Check code formatting". Two files had import blocks in the wrong order after the cfg-gating changes:
|
| Ok((Arc::new(query_material), Arc::new(nullifier_material))) | ||
| impl std::fmt::Debug for Groth16Materials { | ||
| fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
| f.debug_struct("Groth16Materials").finish_non_exhaustive() |
There was a problem hiding this comment.
/otto what does finish_non_exhaustive do?
There was a problem hiding this comment.
finish_non_exhaustive is a method on DebugStruct (from std::fmt) that closes the struct's debug output with { field: value, .. } — the trailing .. signals to the reader that there are additional fields not shown. It's used in manual Debug impls when you want to hide some fields (e.g. large/sensitive data like the zkey material) while still producing valid, informative debug output.
|
|
||
| use super::error::{StorageError, StorageResult}; | ||
| #[cfg(not(target_arch = "wasm32"))] | ||
| use super::error::StorageError; |
There was a problem hiding this comment.
/otto why is this feature gated?
There was a problem hiding this comment.
It's purely a lint/cleanliness fix — StorageError itself is WASM-compatible (just a thiserror enum of String variants, nothing platform-specific).
The gate is needed because StorageError is only used inside #[cfg(not(target_arch = "wasm32"))] mod imp, specifically in the map_io_err helper that constructs StorageError::Lock(...). The WASM mod imp never needs to construct an error — all three methods just return Ok(...) unconditionally — so the import is genuinely unused on WASM, and the workspace's -D warnings / dead_code = "deny" turns that into a hard error.
| //! # Example | ||
| //! | ||
| //! ```rust,no_run | ||
| //! ```rust,ignore |
There was a problem hiding this comment.
/otto why no_run -> ingore?
There was a problem hiding this comment.
no_run still compiles the snippet — it just skips execution. The problem is the example calls Groth16Materials::from_embedded, which only exists when the embed-zkeys feature is enabled. Without it, the doc-test compilation fails with E0599 ("no associated item named from_embedded found").
embed-zkeys is not in the crate's default features (deliberately — it embeds large zkey blobs), and [package.metadata.docs.rs] is only read by docs.rs, not by cargo test --doc or CI. So no_run still breaks in the default environment.
ignore skips compilation entirely, keeping the example visible in rendered docs without causing CI failures. It's the standard idiom for examples that depend on an optional feature not enabled by default.
|
/otto fix ci |
|
On it — checking CI failures and fixing. Will update here when done. |
|
All 16 CI checks pass ✅ — no code changes were needed. The failures were:
|
|
/otto fix ci |
|
On it — investigating and fixing CI failures now. |
- Introduce `embed-zkeys` Cargo feature in walletkit-core and walletkit
that activates world-id-core/embed-zkeys and world-id-core/zstd-compress-zkeys;
previously these were always enabled, preventing downstream consumers from
opting out (e.g. to reduce binary size on WASM).
- Feature-gate `Groth16Materials::from_embedded` behind `embed-zkeys`.
`Groth16Materials::from_cache` (native filesystem) is unaffected.
- Feature-gate `storage::groth16_cache` (and the exported
`cache_embedded_groth16_material`) behind `all(not(wasm32), embed-zkeys)`.
- Fix WASM compilation error: split the single `#[uniffi::export] impl
Groth16Materials` block into two (one per feature/target gate) so the
uniffi proc-macro no longer generates FFI shims that reference
`from_cache`/`StoragePaths` on wasm32 targets.
- Fix dead-code / unused-import warnings on wasm32:
- logger.rs: gate `struct LogEvent`, `LOG_CHANNEL`, and the
`mpsc`/`Mutex` imports behind `#[cfg(not(target_arch = "wasm32"))]`.
- storage/lock.rs: gate `StorageError` import behind non-wasm.
- Add `required-features = ["embed-zkeys"]` to the integration test
targets that call `from_embedded` / `load_embedded_*` so cargo skips
them when the feature is off.
- Fix pre-existing missing-docs error in authenticator_integration.rs and
credential_storage_integration.rs (clippy --all-targets -D warnings).
- Update crate-level doc example to use the correct API and mark it
`ignore` since it requires the `embed-zkeys` feature.
Co-authored-by: otto@toolsforhumanity.com
Co-authored-by: otto@toolsforhumanity.com
UniFFI constructors require owned Arc arguments across the FFI boundary, so clippy::needless_pass_by_value cannot be acted on here. Document this with #[expect(..., reason = ...)] so the suppression is self-explanatory and will become a compile error if the lint ever stops firing. Co-authored-by: otto@toolsforhumanity.com
sqlite3mc registers its cipher implementations during the very first sqlite3_open_v2 call. When the test binary runs all 8 tests as parallel threads, two threads can race inside that one-time initialization window and one sees 'unknown cipher chacha20' even though chacha20 is compiled in (CODEC_TYPE_CHACHA20). Add init_sqlite() using std::sync::OnceLock so that exactly one thread performs the first open; all other threads block until codec initialization is complete before running their own test-specific code. Called as the first statement of every test in the file. Co-authored-by: otto@toolsforhumanity.com
docs.rs builds run without network access; world-id-core/embed-zkeys downloads circuit files (zkeys) during the build script, so including it in [package.metadata.docs.rs] features would cause every docs.rs build to fail with a network error. The crate-level example is already marked `ignore` precisely because it calls from_embedded() which requires embed-zkeys, so removing the feature from the docs.rs config is safe and complete. Co-authored-by: otto@toolsforhumanity.com
from_embedded is gated behind #[cfg(feature = "embed-zkeys")] and embed-zkeys is excluded from [package.metadata.docs.rs] features (docs.rs has no network access for the circuit download). rustdoc resolves intra-doc links against the features active at doc-build time, so the backtick link produced an unresolved-link error under RUSTDOCFLAGS=-Dwarnings. Replace with a plain code-span so the reference remains readable in the rendered docs without creating a dead link. Co-authored-by: otto@toolsforhumanity.com
Replace the single init_logging function that contained scattered inline #[cfg] blocks with three self-contained functions: - init_logging_native (#[cfg(not(wasm32))]): mpsc channel + background delivery thread. Documents *why* the channel is needed: calling a UniFFI foreign callback synchronously from inside UniFFI's future-poll machinery (rust_call_with_out_status) causes EXC_BAD_ACCESS due to nested FFI frame corruption. - init_logging_wasm (#[cfg(wasm32)]): stores the logger in LOGGER_INSTANCE for direct synchronous dispatch. Safe on WASM because the single-threaded cooperative runtime cannot have a UniFFI poll frame on the stack when a tracing event fires. - init_logging (ungated, #[uniffi::export]): handles the LOGGING_INITIALIZED idempotency guard and the shared subscriber setup, then dispatches to the appropriate platform impl via a single #[cfg]-gated call site. Each platform's code path is now fully self-contained; the public dispatcher contains no inline cfg blocks at all. Co-authored-by: otto@toolsforhumanity.com
…vent circuit download
Both world-id-authenticator v0.5.2 and world-id-proof v0.5.2 ship with
default = ["embed-zkeys"], which means any package that activates them
without explicit default-features = false ends up triggering world-id-proof's
build script to download ~100 MB of circuit files from raw.githubusercontent.com.
The two paths that activated world-id-proof/embed-zkeys without our knowledge:
1. walletkit-core -> world-id-core/authenticator
-> dep:world-id-authenticator (default-features = true)
-> world-id-authenticator/embed-zkeys
-> world-id-proof/embed-zkeys ← download
2. walletkit-core -> world-id-core/authenticator
-> dep:world-id-proof (default-features = true)
-> world-id-proof/default = ["embed-zkeys"] ← download
Neither path is controllable from our Cargo.toml without patching upstream
crates, since both are inside the published world-id-core v0.5.2.
Fix: vendor both crates with a single change each (default = []) and add
[patch.crates-io] entries pointing to the vendor copies. The embed-zkeys
feature still activates correctly when our own feature is
explicitly enabled (verified: world-id-proof resolves to [embed-zkeys,
zstd-compress-zkeys] when walletkit-core/embed-zkeys is active).
The vendor copies are verbatim source from crates.io v0.5.2 with only the
[features] default line changed. They should be updated whenever either
crate is bumped.
Co-authored-by: otto@toolsforhumanity.com
Remove the [patch.crates-io] overrides for world-id-authenticator and world-id-proof that set default=[] to prevent circuit downloads. The upstream crates on crates.io are used directly now. Also fix duplicate uniffi workspace dependency in walletkit-core/Cargo.toml introduced during rebase conflict resolution.
d0654df to
f37aba0
Compare
Rebase & vendor cleanup completeRebase against
|
f37aba0 to
076cba6
Compare
|
Fix for WASM CI failure ( Root cause: Fix: Moved Native |
…lock The UniFFI proc macro processes all methods in the impl block before `#[cfg]` attributes are evaluated, so `VaultChangedListener` was being resolved even on wasm32 where the cfg-gated import is absent. Move the method into the non-uniffi impl block where the `#[cfg]` gate works as expected.
2ad5cfb to
f9d2f70
Compare
Summary
Enables
wasm32-unknown-unknowncompilation for bothwalletkit-coreandwalletkitcrates. This is the foundation for running World ID authentication flows in the browser.What works on WASM
cargo check --target wasm32-unknown-unknown)Authenticator::init(with no-op connector + registry = None)generate_nullifier/generate_credential_blinding_factor(via gloo-net WebSocket OPRF transport)generate_single_proof(pure local ZK proof generation)What's native-only (correctly gated)
Groth16Materials::from_cache(filesystem-based, usesstd::fs)generate_proof(usesSystemTime::now(),fetch_inclusion_proof_with_cache)uniffiscaffolding (requiresSend, not available on WASM)ctorinit,rustlsTLS config,reqwest[brotli,rustls-tls]Changes
Commit 1: walletkit-db WASM FFI fixes
Fixes sqlite-wasm-rs FFI compatibility + CI WASM compile check.
Commit 2: Remove
storagefeature flagUnifies the storage code path — the SQLite credential store is always compiled in.
Commit 3: Introduce
Groth16MaterialswrapperDecouples filesystem-dependent Groth16 material loading from the Authenticator constructor. Opaque wrapper with
from_cache(native) andfrom_embedded(all platforms) constructors.Commit 4: Enable WASM compilation
uniffi::derives/attributes withcfg_attr(not(wasm32), ...)across ~17 source filesctor,reqwest[rustls-tls,brotli],rustlsto native-only depsgroth16_cache,generate_proof,fetch_inclusion_proof_with_cachefor non-WASMis_connect()check in http_request.rs (requires hyper)Upstream Dependencies
This PR uses
[patch.crates-io]git refs pointing to WASM-compat branches in upstream repos. These patches will be removed once the upstream PRs are merged and released:Verification
cargo check -p walletkit-core --target wasm32-unknown-unknowncargo check -p walletkit --target wasm32-unknown-unknowncargo check(native)cargo test -p walletkit-core --lib— 76/76 passed