plan: keep default crate wasm-clean; split tokio features for local
The default crate (no features) must compile to wasm32-unknown-unknown so the downstream TS/Python adapter story works — a wasm-compiled alktty is the protocol layer for a sandboxed adapter. The local feature is inherently non-wasm (portable-pty + tokio::process need a real OS) and enabling it on wasm is a build error by design. Cargo.toml: - tokio: drop features = ["full"], use the wasm-clean subset alkcall uses (rt, sync, io-util, macros) with default-features = false - local feature adds tokio/process + tokio/rt-multi-thread - document the wasm constraint in the [features] comment Plan: - Decision 1: add WASM target subsection recording the constraint - Phase 0: mark the tokio feature split as done - Risks: add WASM-target-regression risk with a cargo-check CI mitigation
This commit is contained in:
+11
-2
@@ -15,11 +15,20 @@ name = "alktty"
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
local = ["dep:portable-pty", "dep:tokio-util"]
|
# `local` is inherently non-wasm (portable-pty + tokio::process need a real
|
||||||
|
# OS). The default crate (no features) targets `wasm32-unknown-unknown`;
|
||||||
|
# enabling `local` on wasm is a build error by design — use a real OS for
|
||||||
|
# the local-process backend. The protocol crate (wire, negotiation,
|
||||||
|
# control, backend trait, adapter, session, channels) stays wasm-clean so
|
||||||
|
# downstream TS/Python adapters can compile it in a sandbox.
|
||||||
|
local = ["dep:portable-pty", "dep:tokio-util", "tokio/process", "tokio/rt-multi-thread"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
alkcall = "0.1.1"
|
alkcall = "0.1.1"
|
||||||
tokio = { version = "1", features = ["full"] }
|
# Minimal, wasm-clean tokio features. `local` adds `process` +
|
||||||
|
# `rt-multi-thread` (non-wasm). Do NOT use `features = ["full"]` — it
|
||||||
|
# pulls in `signal`/`fs`/`net` which break `wasm32-unknown-unknown`.
|
||||||
|
tokio = { version = "1", default-features = false, features = ["rt", "sync", "io-util", "macros"] }
|
||||||
bytes = "1"
|
bytes = "1"
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
futures-core = "0.3"
|
futures-core = "0.3"
|
||||||
|
|||||||
@@ -150,6 +150,29 @@ doesn't exist in a single crate. A docker or SSH backend would still
|
|||||||
be a separate crate — those have real external deps (`bollard`,
|
be a separate crate — those have real external deps (`bollard`,
|
||||||
`russh`) and their own resource models.
|
`russh`) and their own resource models.
|
||||||
|
|
||||||
|
**WASM target.** The default crate (no `local` feature) MUST compile
|
||||||
|
to `wasm32-unknown-unknown`. alkcall and alktype both target wasm;
|
||||||
|
keeping alktty wasm-clean is what makes the downstream TS/Python
|
||||||
|
adapter story work — a wasm-compiled alktty is the protocol layer for
|
||||||
|
a sandboxed adapter (browser terminal over WebTransport, a Python
|
||||||
|
wheel that shells out to a wasm module, etc.). The `local` feature is
|
||||||
|
inherently non-wasm (`portable-pty` needs a real OS, `tokio::process`
|
||||||
|
needs `spawn`), so enabling `local` on wasm is a build error by
|
||||||
|
design — the local-process backend runs on a real OS (Linux, macOS,
|
||||||
|
Windows), never in a sandbox.
|
||||||
|
|
||||||
|
Concretely, `Cargo.toml` uses `tokio = { default-features = false,
|
||||||
|
features = ["rt", "sync", "io-util", "macros"] }` (the wasm-clean
|
||||||
|
subset alkcall uses) and `local` adds `tokio/process` +
|
||||||
|
`tokio/rt-multi-thread`. Do NOT use `features = ["full"]` — it pulls
|
||||||
|
in `signal`/`fs`/`net` which break `wasm32-unknown-unknown`. The
|
||||||
|
adapter's `tokio::spawn` for per-session pumps is fine on wasm (the
|
||||||
|
wasm tokio runtime supports `spawn`); the `local` module's std
|
||||||
|
threads and `tokio::process::Command` are the non-wasm parts, and
|
||||||
|
they're feature-gated. `libc` stays under `cfg(unix)` (it's already
|
||||||
|
there for `signal_from_name` and the pipe-mode `kill` path — neither
|
||||||
|
runs on wasm because the only callers are in `local`).
|
||||||
|
|
||||||
### 2. Dependency: `alknet-core` → `alkcall::core`
|
### 2. Dependency: `alknet-core` → `alkcall::core`
|
||||||
|
|
||||||
All types previously from `alknet-core` now come from `alkcall::core`:
|
All types previously from `alknet-core` now come from `alkcall::core`:
|
||||||
@@ -292,12 +315,20 @@ operation spec — the registry runs the ACL before the wrapper, so the
|
|||||||
### Phase 0: Scaffold hygiene (small fixes before porting)
|
### Phase 0: Scaffold hygiene (small fixes before porting)
|
||||||
|
|
||||||
1. Bump `alkcall` in `Cargo.toml` from `"0.1.0"` → `"0.1.1"` (ALPN
|
1. Bump `alkcall` in `Cargo.toml` from `"0.1.0"` → `"0.1.1"` (ALPN
|
||||||
rename release).
|
rename release). *(Done in this revision.)*
|
||||||
2. Add `futures = "0.3"` to `[dependencies]` (the `BoxFuture` alias
|
2. Add `futures = "0.3"` to `[dependencies]` (the `BoxFuture` alias
|
||||||
uses `futures::future::BoxFuture`; alkcall pulls it transitively
|
uses `futures::future::BoxFuture`; alkcall pulls it transitively
|
||||||
but alktty should declare it directly to not rely on a transitive
|
but alktty should declare it directly to not rely on a transitive
|
||||||
dep for a public type alias).
|
dep for a public type alias). *(Done.)*
|
||||||
3. Confirm the `local` feature already wires `portable-pty` +
|
3. **Split tokio features for the WASM target.** *(Done.* `Cargo.toml`
|
||||||
|
*now uses `tokio = { default-features = false, features = ["rt",
|
||||||
|
"sync", "io-util", "macros"] }` for the default wasm-clean build,
|
||||||
|
and `local` adds `tokio/process` + `tokio/rt-multi-thread`.)* The
|
||||||
|
scaffold's `features = ["full"]` pulled in `signal`/`fs`/`net`
|
||||||
|
which break `wasm32-unknown-unknown`. The dev-deps that need
|
||||||
|
`tokio/process` (the pipe/pty integration tests) get it via the
|
||||||
|
`local` feature on the crate itself, not by re-declaring `full`.
|
||||||
|
4. Confirm the `local` feature already wires `portable-pty` +
|
||||||
`tokio-util` as optional deps (it does in the scaffold). The
|
`tokio-util` as optional deps (it does in the scaffold). The
|
||||||
`local` module's `pty.rs` additionally needs `libc` under
|
`local` module's `pty.rs` additionally needs `libc` under
|
||||||
`cfg(unix)` — already in `[target.'cfg(unix)'.dependencies]`.
|
`cfg(unix)` — already in `[target.'cfg(unix)'.dependencies]`.
|
||||||
@@ -518,7 +549,23 @@ well-understood pattern (wezterm uses it) but is inherently platform-
|
|||||||
specific (Unix only for PTY, pipe mode works cross-platform).
|
specific (Unix only for PTY, pipe mode works cross-platform).
|
||||||
|
|
||||||
**Mitigation**: Gate PTY behind `#[cfg(unix)]` as the existing code does.
|
**Mitigation**: Gate PTY behind `#[cfg(unix)]` as the existing code does.
|
||||||
Pipe mode works on all platforms.
|
Pipe mode works on all platforms. The whole `local` module is behind
|
||||||
|
the `local` feature, which is non-wasm by design.
|
||||||
|
|
||||||
|
### Risk: WASM target regression
|
||||||
|
|
||||||
|
The default crate MUST stay `wasm32-unknown-unknown`-clean. A future
|
||||||
|
change that pulls in `tokio::process`, `std::thread`, `libc`, or any
|
||||||
|
OS-specific dep into a non-`local` module silently breaks the
|
||||||
|
downstream TS/Python adapter story (the wasm-compiled protocol layer
|
||||||
|
is what makes those adapters cheap to build).
|
||||||
|
|
||||||
|
**Mitigation**: Add a CI job that runs `cargo check --target
|
||||||
|
wasm32-unknown-unknown` (no features) on every PR. Cheap, catches the
|
||||||
|
regression at the boundary. The tokio feature split in `Cargo.toml`
|
||||||
|
(the wasm-clean `["rt", "sync", "io-util", "macros"]` subset, with
|
||||||
|
`local` adding `process`/`rt-multi-thread`) is the structural guard;
|
||||||
|
the CI job is the enforcement.
|
||||||
|
|
||||||
### Risk: BAST schema drift
|
### Risk: BAST schema drift
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user