Skip to content

Add initial WASM support for Browser Support#2002

Draft
siennathesane wants to merge 14 commits into
everruns:mainfrom
sunbeamdotpt:fix/wasm-systemtime
Draft

Add initial WASM support for Browser Support#2002
siennathesane wants to merge 14 commits into
everruns:mainfrom
sunbeamdotpt:fix/wasm-systemtime

Conversation

@siennathesane

@siennathesane siennathesane commented Jun 7, 2026

Copy link
Copy Markdown

This PR introduces initial support for the WASM platform so Bashkit can be run in a sandboxed browser environment. For the most part, despite the amount of files changed, this is a simple PR.

The first change was to standardize time into an internal package where it could switched between web-time and std::time. Unfortunately I had to update a large amount of files for this change, but the scope is limited exclusively to updating time components.

The second change was introducing an IndexedDb FsBackend implementation. This allows for a semi-persistent, browser-backed storage engine for the environment.

The final change is adding network support. The HTTP client was abstracted and then WASM was implemented separately.

If you'd like to see it working, you can test it at sunbeam.pt

…e module

On wasm32-unknown-unknown, std::time::SystemTime::now() panics at runtime.
This commit introduces a centralized  module that re-exports
 on WASM targets and
 on native targets.

All internal call sites are updated to use , and
helper functions  /  bridge chrono conversions
since chrono's trait impls only cover std::time::SystemTime.

- Adds web-time = 1 to workspace and bashkit Cargo.toml
- Creates crates/bashkit/src/time.rs with cfg-gated re-exports
- Updates 20+ source files to use crate::time instead of std::time
- All 2442 lib tests pass on native
- cargo check passes for wasm32-unknown-unknown
Adds crates/bashkit-wasm-tests as a standalone workspace crate that
exercises the platform-compatible time module on wasm32-unknown-unknown.

Tests verify:
- SystemTime::now() does not panic
- UNIX_EPOCH < now
- chrono roundtrip (SystemTime -> DateTime<Utc> -> SystemTime)
- Duration arithmetic

Run with: wasm-pack test --node (or --headless --chrome)

All 4 tests pass.
SystemTime::now() was not the only time API that panics on
wasm32-unknown-unknown — Instant::now() does too. This commit extends
the centralized time module to also export Instant, and updates all
call sites to use crate::time::Instant.

- time.rs now exports Instant alongside SystemTime/Duration/UNIX_EPOCH
- interpreter, parser, sqlite engine, sleep, tool modules updated
- Verified: Bash::new() and bash.exec() now work in the browser
@siennathesane

Copy link
Copy Markdown
Author

Here is an example of Bashkit being rendered by xterm.js through Bevy.

image

@siennathesane siennathesane changed the title Add initial WASM support Add initial WASM support for Browser Support Jun 7, 2026
Implement IndexedDbFs using rexie + serde-wasm-bindgen behind the
indexeddb feature flag. Includes invisible root node (/) auto-creation
and AssertSend wrapper for wasm32 async_trait compatibility.
Add wasm_bindgen_test coverage for IndexedDbFs including write/read,
append, mkdir, read_dir, remove, stat, rename, copy, symlink, chmod,
and PosixFs wrapper smoke test. Configure run_in_browser for headless
Chrome execution.
@siennathesane siennathesane marked this pull request as ready for review June 8, 2026 11:09
Copilot AI review requested due to automatic review settings June 8, 2026 11:09

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds WASM compatibility and browser persistence by introducing platform-compatible time re-exports and a new IndexedDB-backed filesystem backend.

Changes:

  • Introduce crate::time module (std on native, web_time on WASM) and migrate Instant/SystemTime/Duration usages to it.
  • Add IndexedDbFs (feature-gated) for browser persistence via IndexedDB (Rexie).
  • Add a new bashkit-wasm-tests crate covering WASM time helpers and IndexedDB FS operations.

Reviewed changes

Copilot reviewed 35 out of 36 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
crates/bashkit/src/tool.rs Switches timing to crate::time::Instant for WASM-safe Instant::now().
crates/bashkit/src/time.rs Adds platform-compatible time exports and chrono conversion helpers.
crates/bashkit/src/scripted_tool/execute.rs Switches timing to crate::time::Instant in tool execution + tests.
crates/bashkit/src/parser/mod.rs Uses crate::time::{Duration, Instant} to avoid WASM Instant::now() panics.
crates/bashkit/src/network/bot_auth.rs Uses crate::time::{SystemTime, UNIX_EPOCH} for WASM-safe time.
crates/bashkit/src/lib.rs Exposes new time module and conditionally re-exports IndexedDbFs.
crates/bashkit/src/interpreter/mod.rs Switches timing to crate::time::Instant and updates test imports.
crates/bashkit/src/interop/fs.rs Uses crate::time types for ABI timestamp handling.
crates/bashkit/src/fs/traits.rs Switches to crate::time::SystemTime in FS trait types.
crates/bashkit/src/fs/realfs.rs Switches to crate::time::SystemTime for metadata timestamps.
crates/bashkit/src/fs/readonly.rs Switches to crate::time::SystemTime for metadata timestamps.
crates/bashkit/src/fs/posix.rs Switches to crate::time::SystemTime for metadata timestamps.
crates/bashkit/src/fs/overlay.rs Switches to crate::time::SystemTime for metadata timestamps.
crates/bashkit/src/fs/mountable.rs Switches to crate::time::SystemTime for metadata and new mount entries.
crates/bashkit/src/fs/mod.rs Adds indexeddb module + re-export behind feature flag.
crates/bashkit/src/fs/memory.rs Switches to crate::time::SystemTime for metadata timestamps.
crates/bashkit/src/fs/indexeddb.rs Adds new IndexedDB-based FsBackend implementation for WASM.
crates/bashkit/src/fs/backend.rs Switches FsBackend timestamps to crate::time::SystemTime.
crates/bashkit/src/builtins/sqlite/engine.rs Switches timing to crate::time::Instant for WASM-safe Instant::now().
crates/bashkit/src/builtins/sleep.rs Switches timing to crate::time::Instant in tests.
crates/bashkit/src/builtins/shuf.rs Switches RNG seeding source to crate::time::{SystemTime, UNIX_EPOCH}.
crates/bashkit/src/builtins/rg/mod.rs Switches test mtimes to crate::time::{UNIX_EPOCH, Duration}.
crates/bashkit/src/builtins/python.rs Switches to crate::time::Duration and uses crate::time::UNIX_EPOCH.
crates/bashkit/src/builtins/mod.rs Switches execution deadline anchor to crate::time::Instant.
crates/bashkit/src/builtins/ls/list.rs Uses crate::time::UNIX_EPOCH for mtime formatting.
crates/bashkit/src/builtins/ls/find.rs Uses crate::time::UNIX_EPOCH for mtime formatting.
crates/bashkit/src/builtins/inspect.rs Uses crate::time::UNIX_EPOCH for stat formatting.
crates/bashkit/src/builtins/fileops.rs Bridges chrono <-> platform SystemTime via new helpers.
crates/bashkit/src/builtins/date.rs Uses crate::time::to_chrono_utc for mtime -> chrono conversion.
crates/bashkit/src/builtins/curl.rs Uses crate::time for multipart boundary entropy + test trait signature.
crates/bashkit/src/builtins/archive.rs Uses crate::time::UNIX_EPOCH for tar mtime output.
crates/bashkit/Cargo.toml Adds web-time and introduces optional IndexedDB deps + feature.
crates/bashkit-wasm-tests/src/lib.rs Adds WASM smoke tests for time helpers and IndexedDB FS.
crates/bashkit-wasm-tests/Cargo.toml Adds new WASM test crate configuration and deps.
Cargo.toml Adds workspace dependency on web-time.
Comments suppressed due to low confidence (2)

crates/bashkit/src/time.rs:1

  • from_chrono mis-handles datetimes before UNIX_EPOCH: secs is an i64, but it’s cast to u64, which will wrap negative timestamps into a huge positive duration (producing far-future SystemTime). Consider handling secs < 0 explicitly (compute UNIX_EPOCH - Duration::...), and be careful to combine seconds/nanos without underflow for negative timestamps.
    crates/bashkit/src/time.rs:1
  • to_chrono_utc silently clamps any SystemTime before UNIX_EPOCH to the Unix epoch via unwrap_or_default(), losing information. If this function is used for file mtimes (e.g., touch -t), pre-1970 timestamps will round to 1970-01-01. Consider handling the Err(e) case from duration_since() by converting to a negative chrono timestamp using e.duration().

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread crates/bashkit/src/fs/mod.rs
Comment thread crates/bashkit/src/fs/indexeddb.rs
Comment thread crates/bashkit/src/fs/indexeddb.rs
Comment thread crates/bashkit/src/fs/indexeddb.rs
Comment on lines +546 to +549
let all = store
.get_all(None, None)
.await
.map_err(|e| IoError::other(format!("indexeddb get_all: {e}")))?;

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like this is the correct behavior?

Comment thread crates/bashkit-wasm-tests/src/lib.rs Outdated
Comment on lines +1 to +7
//! WASM-specific smoke tests for bashkit platform-compatible time types.
//!
//! Run with: wasm-pack test --node
//! or: wasm-pack test --headless --chrome

use wasm_bindgen_test::*;
wasm_bindgen_test_configure!(run_in_browser);
@chaliy

chaliy commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Wow :). Let me look at this later today. Definely sounds like a fun.

Make http_client a marker feature (empty) and use target-specific
dependencies so reqwest/rustls are only compiled on native, while
js-sys/wasm-bindgen/web-sys are available on WASM. This fixes the
getrandom 0.2 / ring compilation failure on wasm32-unknown-unknown.
@siennathesane

Copy link
Copy Markdown
Author

I tried to keep a healthy abstraction of native vs WASM so WASM wouldn't cause issues with the existing code.

@siennathesane siennathesane marked this pull request as draft June 10, 2026 12:40
@siennathesane

Copy link
Copy Markdown
Author

Returning to draft to work out more kinks in the design patterns. Browser-based fetch blocks everything due to embedded CORS requirements, so it's effectively useless. I am going to update the network client implementation to be more sane.

@chaliy

chaliy commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Hey @siennathesane , I checked you demo! It is nice. I however have troubles to proceed with this PR. In this PR it is would be a third implementation of WASM for this repo.

  • There is already wasm32-wasip1-threads (napi-rs + @napi-rs/wasm-runtime) - in examples/browser
  • Also emscripten wheel spec, which is not applicable for you, but still WASM

What I think could be a good steps moving forward:

  1. Can you pls analyse it you can use one of the existing WASM implementations, extend them
  2. If 1 is not working (my guess SharedArrayBuffer/COOP/COEP would be blocker for your use case), can you look at making it more optional, I would be totally fine to have this target in examples, or imlementing extensibiltiy points that would enable you to use bashkit as library and then have integration crate on your side.

@siennathesane

Copy link
Copy Markdown
Author

Ah I'm sorry, I missed it. I'll check your WASM code and let you know.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants